为什么会导致分段错误?

时间:2014-05-29 07:46:07

标签: c cs50

我正在使用链接列表进行练习。当我在列表的开头输入值并且值小于列表中的值时,它可以工作。但是当数字越大时我就会出现分段错误。有人对下面的代码有什么问题的想法?

//标题(称为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;
        }
}

3 个答案:

答案 0 :(得分:2)

遍历列表以搜索插入点的while(true)循环不会检查它是否已到达列表的末尾,最终导致取消引用NULL指针。

predPtr指向链表的最后一个节点时,此检查会导致问题:

if (predPtr->next->n > newPtr->n)

predPtr是最后一个节点时,predPtr->nextNULL,因此将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。同时(真)循环可能永远不会结束。