【问题标题】:Segmentation fault, although the code is never executed?分段错误,虽然代码从未执行?
【发布时间】:2014-02-13 06:55:38
【问题描述】:

我刚刚开始学习 C,并且正在研究链表的简单实现。当我尝试打印我的清单时,我意识到了一些奇怪的事情。即使该代码从未执行过,我也会在部分代码中遇到分段错误。这怎么可能?

据我所知,while 循环永远不会执行,因为 next 指针不指向任何东西。我在想,也许在评估 while 循环时,它可能会导致它指向导致分段错误的东西,但奇怪的是,如果你删除行 root = root->next 它执行得很好(没有任何错误)。即使这样,它也永远不会进入 while 循环。那么如果代码从不执行,一行代码(root = root->next 怎么会导致错误呢?代码编译得很好。我是不是在某个地方犯了一个简单的错误?

我知道这几乎不是链表的正确实现,它是为了学习目的而制作的。

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

struct linkedlist   {
    int value;
    struct linkedlist * next;
};

typedef struct linkedlist item;

int main(int argc, char **argv) {
    item * root;
    item * current;

    root = malloc(sizeof(item));
    root->value = 500;

    int i;
    for(i = 0; i <= 20; i++)    {
        current->next = malloc(sizeof(item));
        current = current->next;
        current->value = i;
    }

    while(root->next != 0)  {
        //This is never executed
        printf("[%d]\n", root->value);
        //the line below does cause the segmentation error
        //but how can this affect anything at all if this is never executed?
        root = root->next;
    }
    return 0;
}

【问题讨论】:

    标签: c pointers crash linked-list segmentation-fault


    【解决方案1】:

    current-&gt;next 的第一行是取消引用一个未初始化的指针。您可能忘记在循环之前将current 初始化为root。取消对未初始化指针的引用是未定义行为 (UB),这意味着任何事情都可能发生。实际上,未初始化的变量将具有与存储在其内存位置的任何内容相对应的值。因此,未初始化的指针将被设置为某个半随机地址,并且要么指向内存中的一些半随机内容(可能是其他程序变量),要么无效。

    在 while 循环测试 root-&gt;next 的条件中,另一个未初始化的指针被取消引用。一般来说,你应该确保你的每个列表项(包括root)的next字段设置为0,否则你将无法检测到链表的结尾(再次未初始化的指针, 所以 UB 再次和实践中的值很可能与 0 不同。

    纠正代码中此类问题的建议:

    #include <stdio.h>
    #include <stdlib.h>
    
    struct linkedlist   {
        int value;
        struct linkedlist * next;
    };
    
    typedef struct linkedlist item;
    
    int main(int argc, char **argv) {
        item * root;
        item * current;
    
        root = malloc(sizeof(item));
        root->value = 500;
        root->next = 0;
    
        current = root;
    
        int i;
        for(i = 0; i <= 20; i++)    {
            current->next = malloc(sizeof(item));
            current = current->next;
            current->value = i;
            current->next = 0;
        }
    
        while(root->next != 0)  {
            printf("[%d]\n", root->value);
            root = root->next;
        }
        return 0;
    }
    

    【讨论】:

    • 但是如果我取消注释行 root=root->next;并在它执行的最后输入一条prinf语句而不会崩溃。
    • root->next 也不会在 while 循环之前初始化。
    • @OldProgrammer 我可以在while循环中以某种方式检查吗?而(根->下一个!= NULL)?
    • @dani-h 取消引用未初始化的指针是未定义的行为,因此您不应该根据您的问题是否崩溃做出任何结论。
    • @plabatut 你能说得清楚一点吗?
    猜你喜欢
    • 1970-01-01
    • 2011-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-26
    • 2012-04-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多