【问题标题】:what is the difference between *root and **root?*root 和 **root 有什么区别?
【发布时间】:2021-12-05 12:07:03
【问题描述】:

我正在迭代一个树数据结构,它有一个指向其根的指针,如下所示-

struct node *root;

当我必须将此根的引用作为参数传递给函数时......我必须像传递它一样-

calcHeight(&root);
-
-
-
//somewhere

int calcHeight(struct node **root)      // function defination is this

我的问题是 - 为什么我们需要将“root”指针作为 &root 传递?我们不能像传递根一样--

struct node *root;
calcHeight(root);
int calcHeight(struct node *root);

// 编辑

void someFunct(int *arr){
    printf("arr2 inside someFunct is %d\n",arr[2]);
    arr[2]=30;
}

int main()
{
    int *arr=(int*)calloc(10,sizeof(int));
    printf("arr[2] is %d\n",arr[2]);

    someFunct(arr);
    printf("arr[2] finally is %d\n",arr[2]);
    return 0;
}

在这种情况下,即使我没有传递 arr 的地址,主函数中的 arr 也会被修改。 我得到这样一个事实,对于结构和单值变量,我们必须传递像someFunct(&var) 这样的地址,但这对于数组来说不是必需的吗?对于数组我们写 someFunct(arr)
但我不明白这背后的原因?

【问题讨论】:

标签: c pointers tree double-pointer


【解决方案1】:

struct node * 是指向 struct node 的指针。
struct node ** 是指向 struct node 的指针。

传入struct node ** 的原因可能是该函数需要修改struct node * 实际指向的内容——这对于名为calcHeight 的函数来说似乎很奇怪。如果是freeNode,它可能是有道理的。示例:

void freeNode(struct node **headp) {
    free(*headp);
    *headp = NULL; // make the struct node * passed in point at NULL
}

Demo

另一个原因可能是使界面保持一致,以便始终需要为支持struct nodes 的函数中的所有函数提供struct node ** - 不仅是那些实际需要更改内容的函数struct node * 指向。


关于添加的// EDIT部分:

在这种情况下,没有理由发送指针对指针。如果不需要改变实际的指针,只需要传入指针的即可。

内存布局示例:

Address    What's stored there
+-----+
|  +0 |     uint64_t   ui1 = 1     <--+
+-----+                               |
|  +8 |     uint64_t   ui2 = 2        |
+-----+                               |
| +16 |     uint64_t*  p   = &ui1  ---+
+-----+

现在,如果函数只需要 uint64_t 值,您可以将 ui1ui2*p 发送到该函数。

void someFunc(uint64_t val) { ++val; ... }

此函数对val 所做的更改对函数的调用者不可见。

如果一个函数应该能够对函数的调用者进行可见的更改,请发送一个指针:

void someFunc(uint64_t *valp) { *valp = 10; }

使用someFunc(&amp;ui1);someFunc(p); 调用它会更改ui1 并为其分配10。

如果您有一个指针并且想要更改它实际指向的内容,这就是您最初的问题,您需要发送一个指向该指针的指针:

void someFunc(uint64_t **valpp) { *valpp = &ui2 }`

如果您使用someFunc(&amp;p) 调用它(其中p 当前指向ui1),您会发现函数调用之后,p 将指向ui2

+-----+
|  +0 |     uint64_t   ui1 = 1
+-----+
|  +8 |     uint64_t   ui2 = 2     <--+
+-----+                               |
| +16 |     uint64_t*  p   = &ui2  ---+
+-----+

【讨论】:

  • 所以基本上每当我必须修改值时,我都必须传递指针的地址 - someFunct(struct node &root) ?如果我只想访问它,那么传递指针就足够了- someOtherFunct(struct node root)?
  • @meg 那将是someFunct(&amp;root);someFunct(root);,但是是的,通常情况就是这样。大多数库不会在“free”函数中将指针设置为 NULL,但这样做也很常见。在这种情况下,您需要通过 **
  • 为什么会这样?如果我们可以通过 someFunct(root) 访问该值,那为什么我们不能修改它呢?
  • @meg 使用struct node *,您可以修改它所指向的内容,但不能修改您用来调用该函数的实际指针。您需要该变量的地址才能更改该变量。如果你查看demo,把函数改成不是**而是*,在函数里面设置成NULL,就看不到函数外的效果了。
  • 好的!所以基本上该指针 var 的副本被制作了......实际的 var 永远不会被修改?
【解决方案2】:

因为在calcHeight 中,您按值传递参数。如果要修改root指向的值,需要传递指针的地址。

【讨论】:

    【解决方案3】:

    第一个是指向节点的指针,它是一个结构。

    struct node *root;
    

    root定义为一个可以存储节点地址的变量。

    第二个是指向结构节点的指针。

    struct node **root;
    

    将root定义为变量,该变量可以存储另一个具有节点地址的变量的地址。

    为什么我们需要将“root”指针作为 &root 传递?

    calcHeight(&root);
    

    C 通过值而不是引用传递参数。所以,你必须通过root的地址来修改root的值。

    【讨论】:

      猜你喜欢
      • 2015-07-28
      • 2020-05-10
      • 1970-01-01
      • 2019-03-06
      • 1970-01-01
      • 2022-11-15
      • 2013-03-31
      相关资源
      最近更新 更多