You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 14:45:01