C语言中*root与**root的区别及指针、数组传参规则疑问
C语言指针传参常见问题解答
C语言的所有参数传递本质都是值传递,也就是说函数拿到的永远是入参的副本,对副本本身的修改不会同步到函数外部的原变量,这个是理解所有问题的核心。
为什么树根指针有时候需要传&root(二级指针)
分两种场景判断是否需要二级指针:
- 如果你的
calcHeight函数只需要读取root指向的节点内容,不会修改root这个指针本身的指向(比如不会给根节点分配内存、不会删除根节点后让root指向新的根),那你完全可以直接传root,函数参数定义为int calcHeight(struct node *root)就够用。 - 只有当你需要在函数内部修改
root这个指针变量本身存储的地址时,才需要传二级指针。比如你要在函数里初始化根节点:
void initRoot(struct node **root) { // 这里修改的是外面原root变量的值,让它指向新申请的内存 *root = malloc(sizeof(struct node)); (*root)->data = 1; (*root)->left = (*root)->right = NULL; } // 调用时需要传root的地址 initRoot(&root);
如果这种场景你直接传root进去,函数拿到的是root的副本,修改副本的指向不会影响外面的原root,初始化就会失效,还会出现内存泄漏。
数组传参为什么不需要传地址就能修改元素
你的测试代码里修改arr[2]能生效,和是不是数组没有关系,本质是:你修改的不是arr这个指针本身的值,而是修改arr指向的内存空间里存储的内容。
你传给someFunct的arr是int*类型的指针,函数拿到的是这个指针的副本,但是副本和原arr存储的地址是完全相同的,都指向calloc申请的那块内存的首地址。arr[2]等价于*(arr + 2),是对地址做偏移后解引用修改对应内存的值,自然会同步到外部。
你可以做个对比测试,如果要在函数内部修改arr这个指针本身的指向(比如重新申请内存),直接传arr就会失效:
void resizeArr(int *arr) { // 这里修改的是arr副本的指向,外面的原arr不会变 arr = realloc(arr, 20 * sizeof(int)); }
这种场景下你就需要传二级指针才能生效:
void resizeArr(int **arr) { *arr = realloc(*arr, 20 * sizeof(int)); } // 调用时传&arr resizeArr(&arr);
另外你提到的「数组不需要传地址」,本质是C语言的语法规则:数组名作为函数参数传递时,会自动隐式转换为指向数组首元素的指针,你传int arr[10]和传&arr[0]是完全等价的,你修改的也是数组元素所在的内存内容,所以不需要额外传数组的地址。
内容的提问来源于stack exchange,提问作者meg
相关产品推荐
相关产品推荐

