为什么在构建二叉树时会出现段错误?
Why is this segfaulting whilst building a binary tree?
我通过 gdb 发现此代码中的这一行是段错误。但是我似乎不明白为什么?在发生段错误之前,它将 运行 到 6/7 次。 Temp是链表中的一个节点,它包含一个频率(int),我用它在升序链表中找到插入新节点的位置。
while (ind == 0 && temp != NULL)
{
temp = temp -> next;
if (temp -> frequency > parent_node -> frequency) /*<--- SEG FAULT HERE */
{
parent_node -> next = temp -> next; /* parent points at higher freq node */
temp -> next = parent_node; /* parent node is temp next */
ind = 1;
}
if (temp -> next == NULL)
{
temp -> next = parent_node;
ind = 1;
}
}
你 temp = temp->next
但 temp->next
可能是 nullptr
。在尝试访问它的成员之前,您必须检查它是否为空。
您的问题是您检查 temp
不为空,然后立即更新 temp
,因此它可能再次为空。
(我不喜欢 temp
这个名字,所以我在示例中将其更改为 node
)
分解最清楚,所以:
while(ind == 0 && node != null) {
node = node -> next; // now node might be null
doStuffWith(node);
}
相反,您可以将赋值移动到循环的末尾。这意味着,当然,第一次,分配没有发生。所以你可能需要在循环外调用一次:
node = node -> next; // or some other initialisation of node
while(ind == 0 && node != null) {
doStuffWith(node);
node = node -> next;
}
也许您已被告知 DRY 原则:"Don't repeat yourself",因此您可能对重复 node = node -> next
感到不自在。然而,这是一个非常常见的模式示例,例如:
int chars = stream.read(buffer);
while(chars != -1) {
doSomethingWith(buffer);
chars = stream.read(buffer);
}
这是一些代码,它将 newnode
指向的新节点插入到链表中,其中 liststart
指向列表中的第一个节点,或者 NULL
用于空列表:
if (liststart == NULL) {
liststart = newnode;
newnode->next = NULL;
} else {
struct mylist *prev = liststart;
while (prev->next != NULL && prev->next->frequency <= newnode->frequency) {
prev = prev->next;
}
if (prev->next == NULL) {
prev->next == newnode;
newnode->next = NULL;
} else {
newnode->next = prev->next->next;
prev->next = newnode;
}
}
这是一个使用指向指针的指针的替代版本:
struct mylist **pprev;
pprev = &liststart;
while (*pprev != NULL && (*pprev)->frequency <= newnode->frequency) {
pprev = &(*pprev)->next;
}
newnode->next = *pprev;
*pprev = newnode;
我通过 gdb 发现此代码中的这一行是段错误。但是我似乎不明白为什么?在发生段错误之前,它将 运行 到 6/7 次。 Temp是链表中的一个节点,它包含一个频率(int),我用它在升序链表中找到插入新节点的位置。
while (ind == 0 && temp != NULL)
{
temp = temp -> next;
if (temp -> frequency > parent_node -> frequency) /*<--- SEG FAULT HERE */
{
parent_node -> next = temp -> next; /* parent points at higher freq node */
temp -> next = parent_node; /* parent node is temp next */
ind = 1;
}
if (temp -> next == NULL)
{
temp -> next = parent_node;
ind = 1;
}
}
你 temp = temp->next
但 temp->next
可能是 nullptr
。在尝试访问它的成员之前,您必须检查它是否为空。
您的问题是您检查 temp
不为空,然后立即更新 temp
,因此它可能再次为空。
(我不喜欢 temp
这个名字,所以我在示例中将其更改为 node
)
分解最清楚,所以:
while(ind == 0 && node != null) {
node = node -> next; // now node might be null
doStuffWith(node);
}
相反,您可以将赋值移动到循环的末尾。这意味着,当然,第一次,分配没有发生。所以你可能需要在循环外调用一次:
node = node -> next; // or some other initialisation of node
while(ind == 0 && node != null) {
doStuffWith(node);
node = node -> next;
}
也许您已被告知 DRY 原则:"Don't repeat yourself",因此您可能对重复 node = node -> next
感到不自在。然而,这是一个非常常见的模式示例,例如:
int chars = stream.read(buffer);
while(chars != -1) {
doSomethingWith(buffer);
chars = stream.read(buffer);
}
这是一些代码,它将 newnode
指向的新节点插入到链表中,其中 liststart
指向列表中的第一个节点,或者 NULL
用于空列表:
if (liststart == NULL) {
liststart = newnode;
newnode->next = NULL;
} else {
struct mylist *prev = liststart;
while (prev->next != NULL && prev->next->frequency <= newnode->frequency) {
prev = prev->next;
}
if (prev->next == NULL) {
prev->next == newnode;
newnode->next = NULL;
} else {
newnode->next = prev->next->next;
prev->next = newnode;
}
}
这是一个使用指向指针的指针的替代版本:
struct mylist **pprev;
pprev = &liststart;
while (*pprev != NULL && (*pprev)->frequency <= newnode->frequency) {
pprev = &(*pprev)->next;
}
newnode->next = *pprev;
*pprev = newnode;