【问题标题】:Why current = current->next gives segmentation fault when current->next == NULL?当 current->next == NULL 时,为什么 current = current->next 会出现分段错误?
【发布时间】:2015-04-15 05:27:44
【问题描述】:

我有下面的 C 程序来实现升序链表。问题出在 buildList() 函数中,因此您可以忽略除 main() 和 buildList() 之外的其他函数。

#include<stdio.h>
#include<stdlib.h>

struct node
{
    int data;
    struct node *next;
};

void buildList(struct node **, int);
void printList(struct node **);

int main()
{
    struct node *head;
    head = NULL; /*Empty list*/

    int hold, i, j;
    printf("How many integers in this list: ");
    scanf("%d",&i);
    j = 1;
    for(i; i > 0; i--)
    {
            printf("Integer %d: ",j);
            scanf("%d",&hold);
            buildList(&head, hold);
            j++;
    }
    printList(&head);
    return 0;
}

void buildList(struct node **headRef, int data)
{
    struct node *newNode;
    newNode = malloc(sizeof(struct node));
    struct node *current, *current1;
    current = *headRef;
    //If list is empty, add the number as the first node.
    if (current == NULL)
    {
            newNode->data = data;
            newNode->next = *headRef;
            *headRef = newNode;
    }
   //If the list is not empty.
    else
    {
            //If the number is not greater than first number.
            if (data <= current->data)
            {
                    newNode->data = data;
                    newNode->next = current;
                    *headRef = newNode;
            }
            //If the number is greater than the first number in list.
            else
            {
                    int flag = 0;
                    while (data > (current->data))
                    {
                            current1 = current;
                            current = current->next;
                    }


                    newNode->data = data;
                    current1->next = newNode;
                    newNode->next = current;
            }
    }
}

//Prints nodes and total number of nodes.
void printList(struct node **headRef)
{
    int count = 0;
    struct node *current;
    current = *headRef;
    while (current != NULL)
    {
            count++;
            printf("%d ",current->data);
            current = current->next;

    }
    printf("\nTotal nodes: %d\n",count);
}

这个程序可以正常工作,直到我给出一个大于列表中任何数字的数字。在这种情况下,我会遇到分段错误。

案例一(精细正确的输出)

-bash-4.1$ ./a.out
How many integers in this list: 3
Integer 1: 5
Integer 2: 1
Integer 3: 4
1 4 5
Total nodes: 3
-bash-4.1$

案例二(此处代码中断(分段错误))

-bash-4.1$ ./a.out
How many integers in this list: 3
Integer 1: 5
Integer 2: 6
Segmentation fault
-bash-4.1$

经过很长时间试图弄清楚我的代码出了什么问题,我发现当一个数字大于列表中的任何数字时,在这种情况下,它应该被插入到列表的末尾,此语句(在函数 buildList() 的最后一个 else 中)导致了问题:

  current = current->next;

我终于想通了,当current->next为NULL时,这条语句会导致seg fault。

我想出了一个像下面这样的解决方法,它可以提供正确的输出。

 else
 {
     int flag = 0;
     while (data > (current->data))
     {
         current1 = current;
         if(current->next != NULL)
         {
             current = current->next;
         }
         else
         {
             flag = 1;
             break;
         }
    }
    newNode->data = data;
    current1->next = newNode;
    if (flag == 1)
    {
       newNode->next = NULL;
    }
    else
    {
       newNode->next = current;
    }
}

现在我得到了正确的输出。

-bash-4.1$ ./a.out
How many integers in this list: 3
Integer 1: 5
Integer 2: 1
Integer 3: 10
1 5 10
Total nodes: 3
-bash-4.1$

现在我想知道为什么不是 current = current->next;当 current->next 为 NULL 时工作。我期待这条语句将 NULL 分配给 current。

谁能告诉我这是什么原因? 我的解决方法也是一个好方法吗?还是有更好的方法?

对不起,这个问题太长了,但是花了大约 2 个小时来调试这个,我想我快疯了。

谢谢。

【问题讨论】:

  • @lurker 这不是在链表开头添加节点的方式吗?通过覆盖这个列表的头部?我通过网上找到的教程学习了链表,它说这就是在链表开头添加节点的方法。如果这不是标准方式,请告诉我。
  • 对不起,这是正确的。我没有仔细查看next 设置。

标签: c debugging null linked-list segmentation-fault


【解决方案1】:

您的调试技术给了您一点红鲱鱼。问题出在这个循环中:

while (data > (current->data))
{
    current1 = current;
    current = current->next;
}

但不是你认为的那条线。如果current-&gt;next 是NULL,则current 设置为NULL,正如您所描述的那样。然而,接下来发生的操作是循环条件 - 取消引用 current。布拉莫。你可能想要这样的东西:

while (current && (data > current->data))
{
    current1 = current;
    current = current->next;
}

我没有分析你的整个程序,所以除了明显的崩溃之外,我无法评论这部分的正确性。

【讨论】:

  • 该死的!!我怎么没想到!!!我想我必须休息一下,过去 3-4 天我一直在疯狂地编程,我的大脑可能需要休息一下。但是谢谢男人。一件好事是,我的理解是正确的,即 current 将为 NULL。
  • @user266168,你应该学会使用调试器。它可以帮助您立即找到像这样的错误。
  • 是的,我读到了调试器对在线页面的帮助。是否有任何调试器内置于 CentOS Linux(我的意思是 gcc 编译器)?因为我ssh到我的学校实验室centOS linux机器练习C,我不认为我会被允许我自己在那里安装任何东西。
【解决方案2】:

当第二个输入大于第一个输入时,这个while 循环不会停止。

     while ( data > (current->data))
     {
        current1 = current;
        current = current->next;
     }

您最终会取消引用 NULL 指针。你需要:

     while ( current != NULL && data > (current->data))
     {
        current1 = current;
        current = current->next;
     }

【讨论】:

  • @R Sahu 谢谢。卡尔还指出了我犯的同样错误。当您编写此答案时,我只是在更改代码并进行测试。是的,根本原因是我取消了对 NULL 指针的引用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-12
  • 2019-01-12
  • 1970-01-01
  • 1970-01-01
  • 2012-03-03
相关资源
最近更新 更多