C语言查缺补漏(五)指针作参

忽略点五:指针作参

​ 平时比赛很少用到指针(链表,动态数组都有对应的STL,字典树也可以用数组模拟),业精于勤荒于嬉,C语言的指针就这样被我遗忘了。。

​ 之前博文说过,C语言的优势之一就是在于能够直接访问物理地址,C语言的一大特色就是指针!!所以,学C语言舍弃指针是非常不明智的选择,终归是要还以前忽略的债。。苦笑~

​ 关于指针,自己忽略的部分有很多,这一篇主要讲一下关于指针作参的用法:

——对于函数来说:

​ 它不像变量那样可以进行值传递,我们在将函数作参进行传递时,需要传递它的地址,格式为:

int g (int (*f)(int), int a) {		//定义
    return f(a);
}
//省略代码
g(函数名, int型变量); 				//调用 

——对于一维数组来说:

​ 它的格式为:

void f (int *p) {		//定义
    //省略代码
}
//省略代码
int a[5];
f (a);				//调用 

​ 关于这个a,我对它的理解是数组的初始位置,它等价于&a[0]。因为我们在声明指针指向a数组时,是通过 int *p = a来实现的。

注意点!!!!

void f (int a[5]) {		//定义
    //省略代码
}
//省略代码
int a[5];
f (a);				//调用 

​ 对于 void f(int a[5]),参数int a[5]就真的是数组吗?

​ 答案是否定的,这里如果真的把数组作为函数参数的话,需要分配临时的栈区执行拷贝等操作,会特别麻烦。所以编译器对代码进行了优化,把数组退化成了指针。从调用传入的是a(指针)就可以看出。

——对于二维数组来说:

它的格式为:

void f (int *p) {		//定义
    //省略代码
}
//省略代码
int a[5][5];
f (a[0]);	//调用 由一维数组可知,a[0]等价于&a[0][0],也等价于*a

​ a[0]等同于二维数组的首地址,也是二维数组下标为0行的首地址,同理a[1]为下标为1行的首地址,以此类推。

​ 下面的问题没想明白,欢迎大佬来为我解惑。

​ 我的认识(不一定正确):那么二维数组的a是什么呢?从上边我们可以知道,a[0], a[1]等等都是地址信息,把他们整体来看,就是一个一维的指针数组。那么a为这个一维指针数组的首地址,而*a就是a[0]的值,也就是二维数组的首地址,从下面代码中也可以证实我的观点:

void f(int *p) {
    for (int i = 0; i < 4; i++) {
        printf("%d\n", p[i]);
    }
}
//省略代码
int a[2][2] = {1, 2, 3, 4};
f(*a);

​ 最后结果输出 1,2,3,4,说明了*a 等价于a[0],也就是二维数组的首地址

​ 按上面的逻辑,*a等价于a[0],那么a就是存储a[0]指针地址的地址,所以a的值应该与a[0]不相同,也就是与 *a不相同,所以以下代码会报错:

void f(int *p) {
    for (int i = 0; i < 4; i++) {
        printf("%d\n", p[i]);
    }
}
//省略代码
int a[2][2] = {1, 2, 3, 4};
f(a);

可我通过以下代码输出发现,a的值等于 a[0]

int a[2][2] = {1, 2, 3, 4};
printf("%p\n", a);
printf("%p\n", *a);

输出为:

在这里插入图片描述

很迷茫。。。希望有大佬能为我解惑~

——对于结构体来说:

​ 结构体指针和变量指针作参类似,但它的指针可通过 ->符指向它的成员,举个栗子(截取遍历链表代码的一部分):

struct node {
    int val;
    node *next;
}
void f(node *root) {
    while (root -> next != NULL) {
        printf("%d\n", root -> val)
    }
}
//省略代码
node root = {a, NULL};
f(&root);

​ root -> val等价于 (*root).val

​ 只要捋清每个变量所代表的意义,指针作参就不会那么迷糊了,就酱紫~

转载请注明出处!!!

如果有写的不对或者不全面的地方 请指正! 谢谢~

猜你喜欢

转载自blog.csdn.net/Ivan_zcy/article/details/82919495