我正在使用链接列表进行练习。当我在列表的开头输入值并且值小于列表中的值时,它可以工作。但是当数字越大时我就会出现分段错误。有人对下面的代码有什么问题的想法?
//标题(称为headeroef):
typedef struct node
{
int n;
struct node* next;
} node;
//其他代码
#include <cs50.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include "headeroef.h"
void insert(void);
void traverse(void);
node* first = NULL;
int main (void)
{
int c;
do
{
printf("Print instructions: \n"
"1. insert\n"
"2. Delete\n");
printf("Command: ");
c = GetInt();
switch(c)
{
case 1: insert(); break;
}
}
while (c!=0);
}
void insert(void)
{
node* newPtr = malloc(sizeof(node));
printf("Number to insert: \n");
newPtr->n = GetInt();
newPtr->next = NULL;
if (first == NULL)
{
first = newPtr;
}
else if(newPtr->n < first->n)
{
newPtr->next = first;
first = newPtr;
}
else
{
node* predPtr = first;
//Dit houdt dus als in als aan deze else wordt voldaan!
while (true)
{
if (predPtr->n == newPtr->n)
{
free(newPtr);
break;
}
else if (predPtr->next->n > newPtr->n)
{
//Hiermee doe je weer die swap
newPtr->next = predPtr->next;
predPtr->next = newPtr;
break;
}
//Uitzoeken waarom hier een segmentation fault komt.s
}
}
traverse();
}
void traverse(void)
{
printf("The list is now\n");
node* ptr = first;
while (ptr!=NULL)
{
printf("%i\n", ptr->n);
ptr = ptr->next;
}
}
答案 0 :(得分:2)
遍历列表以搜索插入点的while(true)
循环不会检查它是否已到达列表的末尾,最终导致取消引用NULL
指针。
当predPtr
指向链表的最后一个节点时,此检查会导致问题:
if (predPtr->next->n > newPtr->n)
当predPtr
是最后一个节点时,predPtr->next
为NULL
,因此将predPtr->next->n
视为未定义的行为。
答案 1 :(得分:1)
我们假设您在列表中有单个号码5
,并且您想要添加7
。
由于first
不是NULL
并且您尝试插入的数字不比第一个少,所以最终会在最后一个块中结束:
node* predPtr = first;
//Dit houdt dus als in als aan deze else wordt voldaan!
while (true)
{
if (predPtr->n == newPtr->n)
{
free(newPtr);
break;
}
else if (predPtr->next->n > newPtr->n)
{
//Hiermee doe je weer die swap
newPtr->next = predPtr->next;
predPtr->next = newPtr;
break;
}
//Uitzoeken waarom hier een segmentation fault komt.s
}
由于您并未尝试插入重复内容,因此第一个if
语句无关紧要。结合:
node* predPtr = first;
while (true) {
:
else if (predPtr->next->n > newPtr->n)
是造成崩溃的原因,因为predPtr->next
为NULL(只有5
元素),因此predPtr->next->n
将取消引用空指针。< / p>
在尝试取消引用之前,您基本上需要检测到这一点。如果你到达最后一个元素并且仍小于你想要插入的那个元素,你需要附加它而不是运行列表的末尾。< / p>
使用当前代码执行此操作的最简单方法可能是将while
循环更改为:
while (true) {
// gooi als identiek.
if (predPtr->n == newPtr->n) {
free(newPtr);
break;
}
// voegen als aan het einde van de lijst
if (predPtr->next == NULL) {
predPtr->next = newPtr;
break;
}
// steek indien minder
if (predPtr->next->n > newPtr->n) {
newPtr->next = predPtr->next;
predPtr->next = newPtr;
break;
}
// vooruit naar volgend element.
predPtr = predPtr->next;
}
您会注意到我还在循环底部添加了语句,以便在列表中前进。如果没有这个,你几乎肯定会在某个时刻出现无限循环。
你也可以重构你的循环以使用不同的结局条件,但这需要更多的工作,而且我并不热衷于做更多的工作,除非我按小时付款: - )
答案 2 :(得分:0)
else if (predPtr->next->n > newPtr->n)
您检查predPtr-&gt; next-&gt; n,而不检查next是否为null。同时(真)循环可能永远不会结束。