【问题标题】:C pointer pointer, and seg faultC 指针指针和段错误
【发布时间】:2012-08-21 17:00:40
【问题描述】:
下面是我在 C 中的简单链表。我的问题在“headRef = &newNode;”中这会导致分段错误。然后我尝试了“*headRef = newNode;”这解决了段错误问题。尽管在我看来这两行代码以相同的方式工作,但为什么一个会导致 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;
}
【问题讨论】:
标签:
c
pointers
segmentation-fault
【解决方案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 *)。你搞错了!
【解决方案2】:
newNode 已经是一个地址,您已将其声明为指针:struct node *newNode。使用*headRef = newNode,您将该地址分配给类似的指针,将struct node * 分配给struct node *。
令人困惑的是headRef = &newNode 似乎同样有效,因为类型一致:您分配给struct node ** 另一个struct node **。
但这是错误的,原因有两个:
- 您想更改函数参数
headRef 的值struct node *。您已将headRef 的地址 传递给函数,因为C 是按值传递的,因此要更改变量,您需要它的地址。您要更改的这个变量是一个地址,因此您将一个指针传递给一个指针struct node **:需要额外的间接级别,以便您可以在函数内更改地址,并让该更改反映 outide 功能。因此,在函数中,您需要取消引用变量以获取您想要更改的内容:在您的函数中,您想要更改*headRef,不 headRef .
- 获取
newNode 的地址会创建不必要的间接级别。如上所述,您要分配的值是由 newNode 持有的地址,不是 地址 newNode。
【解决方案3】:
headRef = &newNode是局部赋值,所以赋值只在Push函数范围内有效。如果对headRef 的更改应该在Push 之外可见,您需要执行*headRef = newNode。此外,这两者并不等价。 headRef = &newNode 将节点指针的地址分配给指向节点指针的指针,而*headRef = newNode 将节点的地址分配给指向节点的指针。
【解决方案4】:
您正在设置headRef 来保存位于堆栈中的变量的地址;只要你的Push() 函数返回,堆栈就不再有效,你可以指望它被覆盖。这肯定会导致段错误。