1

下面是我在 C 中的简单链表。我的问题在“headRef = &newNode;”中 这会导致分段错误。然后我尝试了“*headRef = newNode;” 这解决了段错误问题。尽管在我看来这两行代码以相同的方式工作,但为什么一个会导致 seg fault 而另一行不会呢?提前致谢。

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;
}
4

4 回答 4

1

newNode已经是一个地址,你已经将它声明为一个指针:struct node *newNode。随着*headRef = newNode您将该地址分配给类似的指针, astruct node *到 a struct node *

混淆headRef = &newNode 似乎同样有效,因为类型一致:您分配给struct node **another struct node **

但这是错误的,原因有二:

  1. 您想更改函数参数headRefa的值struct node *。您已将地址传递headRef给函数,因为 C 是按值传递的,因此要更改变量,您需要它的地址。您要更改的这个变量一个地址,因此您将一个指针传递给一个指针 a struct node **: 需要额外的间接级别,以便您可以在函数内更改地址,并将该更改反映在函数外部。因此,在函数中,您需要取消引用变量以获取您想要更改的内容:在您的函数中,您想要更改*headRef而不是 headRef.
  2. 取地址newNode是创建不必要的间接级别。如上所述,您要分配的值是持有 newNode的地址,而不是的地址 newNode
于 2012-08-21T17:03:30.257 回答
1

您对通过指针的引用语义有一个基本的误解。这是核心示例:

// 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 *)。你搞错了!

于 2012-08-21T17:05:08.403 回答
0

headRef = &newNode是局部赋值,所以赋值只在函数范围内有效Push。如果对 的更改headRef应该在Push您需要做的外部可见*headRef = newNode。此外,这两者并不等价。headRef = &newNode将节点指针的地址分配给指向节点指针的指针,而*headRef = newNode使用间接将节点的地址分配给指向节点的指针。

于 2012-08-21T17:05:23.373 回答
0

您正在设置headRef保存位于堆栈上的变量的地址;一旦你的Push()函数返回,堆栈就不再有效,你可以指望它被覆盖。这是段错误的可靠方法。

于 2012-08-21T17:05:36.120 回答