为何用*root初始化Node*curr无编译错误,用*p初始化普通指针却报错?
链表双指针赋值的疑问解答
问题描述
我正在学习链表,搞不懂为什么代码里insert_end函数中的Node *curr = *root;这行没有编译错误?按我的理解,初始化Node *curr应该用&取地址才对?但我自己定义双指针p和普通指针,用*p初始化普通指针时却出现编译错误,程序跑不起来。我觉得这两种场景是一样的,看不出差异。附上代码示例:
#include <stdio.h> #include <stdlib.h> typedef struct Node { int x; struct Node *next; } Node; void insert_end(Node **root, int value) { Node *new_node = malloc(sizeof(Node)); new_node->next = NULL; new_node->x = value; //We have to use the loop to reach the // end of the list where we add our additional box Node *curr = *root; while (curr->next != NULL) { curr = curr->next; } curr->next = new_node; } int main() { Node *root = malloc(sizeof(Node)); root->x = 15; //1st element root->next = NULL; //the last element of a list is always initialized with null //exit loop when *next = NULL //it matters the order of freeing the memory insert_end(&root, -2); for (Node *curr = root; curr != NULL; curr = curr->next) { printf("%d\n", curr->x); } return 0; }
问题解答
1. 明确双指针Node **root的含义
Node **root是指向指针的指针,它存储的是另一个Node*类型指针的地址。在main函数中调用insert_end(&root, -2)时,&root是把main里的普通指针root的地址传给了函数参数,所以函数里的root(双指针)指向的是main中root指针本身。
2. Node *curr = *root;为什么合法
*root是对双指针做解引用操作,得到的是main里的root指针(也就是一个Node*类型的值)。而curr也是Node*类型,类型完全匹配,所以用*root初始化curr是完全合法的,自然不会有编译错误。
这一步的目的是让curr拿到链表的头指针,从而从链表头部开始遍历,找到末尾节点。
3. 你自己的测试代码出错的原因
你说的“用*p初始化普通指针出错”,大概率是因为你的双指针p没有正确指向一个有效的普通指针:
- 如果
p是未初始化的野指针(比如直接写Node **p;),这时候解引用*p会访问非法内存,属于未定义行为,编译会警告甚至运行崩溃; - 但如果像链表代码里那样给双指针正确赋值,比如:
这种情况就不会出错,和链表代码的场景完全一致。Node *real_ptr = malloc(sizeof(Node)); Node **p = &real_ptr; // p指向real_ptr这个普通指针 Node *curr = *p; // 这时候*p就是real_ptr,类型匹配,完全合法
4. 纠正你的误解
你以为需要用&取地址,但这里*root已经是一个Node*类型的指针了,再用&取地址会得到Node**类型,和Node*的curr类型不匹配,反而会编译报错。链表代码里的写法才是正确的。
内容的提问来源于stack exchange,提问作者JOHN BOURAS
相关产品推荐
相关产品推荐

