优秀的编程知识分享平台

网站首页 > 技术文章 正文

抓住指针的精髓,才算掌握了 C 语言的灵魂

nanyue 2024-09-15 23:21:36 技术文章 4 ℃

作者 | 五道杠的小屁孩wwk

责编 | 夕颜

出品 | CSDN博客

学习C肯定会碰到指针,指针是C的灵魂。所以学好指针很关键,这里写一些指针方面的容易错的或者易混淆的知识点还有自己不会的盲点,以便之后复习时用。

数组传参和数组形参

1.1 数组传参

如果函数遇到数组传参的,不论是什么形式的形参,只要是数组,那么被调函数都将这个形参都当做指针来使用。

#include "stdio.h"

PrintArray(int *a, int num){int i;for (i = 0; i < num; i++){printf("%5d", a[i]);}printf("\n");}

int main(void){

int a = { 3,4,5,6,7,7,8 };

int num = sizeof(a) / sizeof(a[0]);PrintArray(a, num);

system("pause");}

一般我们使用数组传参。

下面还有一种形参表示方法也很常用,效果其实是一样的。

#include "stdio.h"

PrintArray(int *a, int num){int i;for (i = 0; i < num; i++){printf("%5d", a[i]);}printf("\n");}



PrintArray1(int a[], int num){int i;for (i = 0; i < num; i++){printf("%5d", a[i]);}printf("\n");}int main(void){

int a = { 3,4,5,6,7,7,8 };

int num = sizeof(a) / sizeof(a[0]);PrintArray(a, num);

PrintArray1(a, num);system("pause");}

甚至还有一种方法:

#include "stdio.h"

PrintArray(int *a, int num){int i;for (i = 0; i < num; i++){printf("%5d", a[i]);}printf("\n");}

PrintArray1(int a[], int num){int i;for (i = 0; i < num; i++){printf("%5d", a[i]);}printf("\n");}

PrintArray2(int a[7], int num){int i;for (i = 0; i < num; i++){printf("%5d", a[i]);}printf("\n");}int main(void){

int a = { 3,4,5,6,7,7,8 };

int num = sizeof(a) / sizeof(a[0]);PrintArray(a, num);

PrintArray1(a, num);

PrintArray2(a, num);system("pause");}

1.2 数组传参实质

数组实质传的都是指针,不论什么表现形式。

#include "stdio.h"

PrintArray(int *a, int num){int i,num1;num1 = sizeof(a) / sizeof(a[0]);printf("num = %5d",num1);

for (i = 0; i < num; i++){printf("%5d", a[i]);}printf("\n");}

PrintArray1(int a[], int num){int i,num1;num1 = sizeof(a) / sizeof(a[0]);printf("num = %5d", num1);for (i = 0; i < num; i++){printf("%5d", a[i]);}printf("\n");}

PrintArray2(int a[7], int num){int i,num1;num1 = sizeof(a) / sizeof(a[0]);printf("num = %5d", num1);for (i = 0; i < num; i++){printf("%5d", a[i]);}printf("\n");}int main(void){

int a = { 3,4,5,6,7,7,8 };

int num = sizeof(a) / sizeof(a[0]);PrintArray(a, num);

PrintArray1(a, num);

PrintArray2(a, num);system("pause");}

可以看到num1的值均为1。

实参都是数组,形参都是指针,无论什么形式。

数组首元素地址和整个数组地址

#include "stdio.h"

int main(void){int a[10];

printf("a的大小 = %d\n", sizeof(a));

printf("a = %d\n", a);

printf("a + 1 = %d\n", a + 1);

printf("&a = %d\n", &a);

printf("&a + 1 = %d\n", &a + 1);system("pause");}

从这组输出我们可以看到几点:

  • a数组大小是40。因为一个int是4字节,一共10个。

  • 数组a和&a值一样

  • 但是a是数组首元素地址,而&a是整个数组地址。

  • 这个原因也导致另外两个值不同。a+1就是第二个元素地址,偏移4字节

  • &a+1是相当于偏移整个数组大小,也就是40字节。

变量在内存中的位置

变量在内存中有四个地方可以存放,读取修改变量实质都是通过指针修改。

3.1 变量存放的区域

3.2 常量例子

#include "stdio.h"

char *GetChar1(void){char *p1 = "abcdefg";return p1;}

char *GetChar2(void){char *p2 = "abcdefg1";return p2;}

int main(void){char *p1 = ;char *p2 = ;

p1 = GetChar1;p2 = GetChar2;//打印数据printf("p1 = %s\n", p1); printf("p2 = %s\n", p2);//打印地址printf("p1 = %5d\n", p1);printf("p2 = %5d\n", p2);system("pause");}

在内存中表示为:

因为GetChar函数里面都是指针所以都放在栈区,而常量都在全局区。

当被调函数return之后,上面两个指针被释放,然后将地址赋给main函数里面的指针,他们就指向相应的值。

接下来,还有一个易错的点!!!

#include "stdio.h"

char *GetChar1(void){char *p1 = "abcdefg1";return p1;}

char *GetChar2(void){char *p2 = "abcdefg1";return p2;}

int main(void){char *p1 = ;char *p2 = ;

p1 = GetChar1;p2 = GetChar2;//打印数据printf("p1 = %s\n", p1); printf("p2 = %s\n", p2);//打印地址printf("p1 = %5d\n", p1);printf("p2 = %5d\n", p2);system("pause");}

main函数里面指针地址是一样的

3.3 堆和栈例子

用户自己申明的变量是在堆中存放的,只有用户释放。

#include "stdio.h"

char *GetString(int num){char *s = ;s = (char *)malloc(sizeof(char)*num);if (s == ){return ;}return s;}int main(void){char *p1 = ;p1 = GetString(10);if (p1 == ){return;}strcpy(p1, "abcdefg");printf("%s\n", p1);system("pause");}

内存中分布:

当GetString被调用后,s释放之后,malloc分配的空间还是存在,所以还能继续打印。

接下来的问题在实际写的过程中会犯错:

#include "stdio.h"



char *GetString(int num){char *s = ;s = (char *)malloc(sizeof(char)*num);if (s == ){return ;}return s;}

char *GetString1(void){char s1[10];strcpy(s1, "qwerty");printf("%s\n", s1);return s1;}int main(void){char *p1 = ;char *p2 = ;p1 = GetString(10);if (p1 == ){return;}p2 = GetString1;strcpy(p1, "abcdefg");printf("%s\n", p1);printf("%s\n", p2);system("pause");}

这时的p2其实打印不出来或者程序死机了。这是因为GetString1中的s1变量是申明在栈区中,当调用结束后,被释放了,那块区域中的qwerty就没了。但是地址还是那个10字节的起始地址,并没有全部return出来。

其他

内存中的栈是开口向下的。

版权声明:本文为CSDN博主「五道杠的小屁孩wwk」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/weixin_36101480/article/details/106181096

?尤雨溪:重头来过的 Vue 3 带来了什么?

?原来 Kylin 的增量构建,大有学问!| 原力计划

?可怕!CPU 竟成了黑客的帮凶!

?如何用NLP辅助投资分析?三大海外机构落地案例详解

?这 10 个云计算错误,会让你的业务一蹶不振!

?好扑科技结合区块链行业发展趋势,重磅推出“好扑区块链合伙人”计划

Tags:

最近发表
标签列表