下面是我在C中的简单链表。我的问题是"headRef=&newNode;",这会导致分段错误。然后我尝试了"*headRef=newNode;",它解决了seg故障问题。虽然这两行代码在我看来是以相同的方式工作的,但为什么其中一行代码会导致seg故障,而另一行代码不会?提前谢谢。
struct node{
int data;
struct node* next;
};
void Push(struct node** headRef, int data){
struct node* newNode = malloc(sizeof(struct node));
if(!newNode) return;
newNode->data = data;
newNode->next = *headRef;
headRef = &newNode;
return;
}
您对指针引用语义有一个根本性的误解。以下是核心示例:
// Call site:
T x;
modify(&x); // take address-of at the call site...
// Callee:
void modify(T * p) // ... so the caller takes a pointer...
{
*p = make_T(); // ... and dereferences it.
}
所以:调用者获取的地址,被调用者取消引用指针并修改对象。
在您的代码中,这意味着您需要说*headRef = newNode;
(在我们的基本示例中,您有T = struct node *
)。你找错地方了!
newNode
已经是一个地址,您已经将其声明为指针:struct node *newNode
。使用*headRef = newNode
,您将该地址分配给类似的指针,struct node *
分配给struct node *
。
令人困惑的是,headRef = &newNode
看起来同样有效,因为类型一致:您正在将另一个struct node **
分配给struct node **
。
但这是错误的,有两个原因:
- 您想要更改函数参数
headRef
(一个struct node *
)的值。您已经将headRef
的地址传递到函数中,因为C是按值传递的,所以要更改变量,您需要它的地址。您要更改的变量是地址,因此您将指针传递给指针struct node **
:需要额外的间接级别,以便您可以更改函数内的地址,并将该更改反映在函数外。因此,在函数中,您需要取消引用变量以获得您想要更改的内容:在函数中您想要更改*headRef
,而不是headRef
- 取
newNode
的地址会产生不必要的间接级别。如上所述,您要分配的值是newNode
持有的地址,而不是newNode
的地址
headRef = &newNode
是本地赋值,因此该赋值仅在Push
函数的范围内有效。如果对headRef
的更改应该在Push
之外可见,则需要执行*headRef = newNode
。此外,这两者并不等同。CCD_ 25将节点指针的地址分配给指向节点的指针,而CCD_。
您将headRef
设置为保存堆栈上的变量的地址;一旦Push()
函数返回,堆栈就不再有效,您可以指望它会被覆盖。这肯定是一个segfault的配方。