c语言中函数传递二级指针,修改指针指向
#include<stdio.h>voidtry_change_ptr(int*p){// 发现p指向的地址和ptr指向的地址一样,但是p本身的地址和ptr本身的地址不一样printf("Inside function, p = %p, &p = %p\n",(void*)p,&p);// 所以可以修改p指向的内容*p=1;// 但修改不了ptr的指向地址,因为p是一个拷贝,p本身的地址和ptr本身的地址不一样p=NULL;// 修改的是函数内部的 p(副本)printf("Inside function, p = %p, &p = %p\n",(void*)p,&p);}intmain(){inta=10;int*ptr=&a;printf("&a %p\n",&a);printf("%d\n",*ptr);// 打印ptr的指向地址和ptr本身的地址printf("Before call, ptr = %p, &ptr = %p \n",(void*)ptr,&ptr);//这里会创建副本,就像int fun(int a) 传入a一样,如果要修改a的地址,就要传a的地址try_change_ptr(ptr);printf("After call, ptr = %p, &ptr = %p \n",(void*)ptr,&ptr);// 仍然是 &a!没变!printf("%d\n",a);return0;}/* &a 0000002274F4FB60 10 Before call, ptr = 0000002274F4FB60, &ptr = 0000002274F4FB68 Inside function, p = 0000002274F4FB60, &p = 0000002274F4FB40 Inside function, p = 0000000000000000, &p = 0000002274F4FB40 After call, ptr = 0000002274F4FB60, &ptr = 0000002274F4FB68 1 *//*如果你不仅想修改内容,还想在函数内部改变原指针的指向,你需要使用二级指针(指针的指针)。 这就像你不仅拿到了钥匙,还拿到了“存放钥匙的保险箱的钥匙”。*///void changePointer(int **p) {// **p = 200; // 依然可以修改内容// *p = NULL; // 成功修改了外部指针的指向!//}//int main() {// int a = 10;// int *ptr = &a;// changePointer(&ptr); // 注意这里传的是 ptr 的地址// // 此时 ptr 已经变成了 NULL// return 0;//}/* * 输出打印 Before call, ptr = 0060FE98 Inside function, *p = 10 Inside function, p = 00000000 After call, ptr = 0060FE98 *///void really_change_ptr(int **pp)//{// //和a的地址相同// printf("Inside function, *pp = %p\n", *pp);// printf("Inside function, **pp = %d\n", **pp);// *pp = NULL; // 通过 pp 修改它指向的那个指针变量// printf("Inside function, pp = %p\n", (void *) pp);// printf("Inside function, *pp = %p\n", *pp);//}//int main()//{// int a = 10;// printf("a add: %p\n", &a);// int *ptr = &a;// printf("Before: %p\n", (void *) ptr);// //这里要修改指针的地址,就要通过指针类型,传指针的地址// really_change_ptr(&ptr); // 传 ptr 的地址// printf("After: %p\n", (void *) ptr); // 现在变成 NULL 了!//}/* a add: 0060FE9C Before: 0060FE9C Inside function, *pp = 0060FE9C Inside function, **pp = 10 Inside function, pp = 0060FE98 Inside function, *pp = 00000000 After: 00000000 */在 C/C++ 中,*ptr++是一个非常经典且高频使用的表达式。它的核心逻辑可以总结为一句话:先取当前指针指向的值,然后将指针向后移动一个单位。
为了让你彻底弄懂,我们从底层原理到实际代码进行拆解:
1. 底层原理:运算符优先级与结合性
在这个表达式中,同时出现了*(解引用)和++(后置自增)。
根据 C/C++ 的语法规则:
- 后置
++的优先级高于*。 - 当优先级相同时,结合方向是从右向左。
因此,*ptr++在编译器眼中等价于*(ptr++)。
2. 具体执行步骤
假设ptr是一个指向数组的指针,*(ptr++)的执行过程分为两步:
- 取值:先对当前的
ptr进行解引用,获取它当前指向的内存中的值。 - 移动指针:随后,
ptr自身的地址发生偏移,指向下一个元素(步长取决于指针的类型,例如int*会向后移动 4 个字节)。
⚠️ 核心注意点:这个表达式只改变了ptr的指向,并没有修改原来内存位置里的数据值。
3. 代码演示
我们来看一段直观的代码:
#include<stdio.h>intmain(){intarr[]={10,20,30};int*ptr=arr;// ptr 初始指向 arr[0]// 使用 *ptr++intval=*ptr++;printf("取出的值 val = %d\n",val);// 输出: 10printf("当前指向的值 *ptr = %d\n",*ptr);// 输出: 20return0;}结果解析:val拿到了旧值10,而ptr已经悄悄向后移动,现在指向了20。
4. 易混淆对比(避坑指南)
初学者经常把*ptr++和下面这两个表达式搞混,它们的区别非常大:
| 表达式 | 等价形式 | 作用对象 | 结果 |
|---|---|---|---|
*ptr++ | *(ptr++) | 指针本身 | 取出旧值,指针向后移动,数据不变 |
(*ptr)++ | (*ptr)++ | 指向的数据 | 取出旧值,数据加 1,指针不动 |
*++ptr | *(++ptr) | 指针本身 | 指针先向后移动,再取出新位置的值 |
💡 总结与应用
*ptr++这种“先取值,后移动”的特性,非常适合用来顺序遍历数组。在底层 C 语言开发中,它能让遍历数组的代码变得非常简洁优雅,不需要像arr[i++]那样单独写一行ptr++。
