【问题标题】:Why is this C linked list program giving 'segmentation fault'?为什么这个 C 链表程序会给出“分段错误”?
【发布时间】:2010-02-18 23:31:07
【问题描述】:

第一个函数读取一个包含一堆 'char' 的文件并将它们放在一个链表中。它不工作:(。

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

struct list {
    char val;
    struct list* next;
};

typedef struct list element;

int lcreate(char* fname, element* list);
int ldelete(element* list);
int linsert(char a, char b, element* list);
int lremove(char a, element* list);
int lsave(char* fname, element* list);



int lcreate(char* fname, element* list) {
    element* elem = list;
    char c = 0;
    FILE * file = NULL;

    file = fopen(fname, "r");

    while ((c = getc(file)) != EOF)
    {
        if(list == NULL) {
            list = (element*)malloc(sizeof(element));
            if(list == NULL) {
                return 0;
            }
            list->val = c;
        }
        else {

            elem->next=(element*)malloc(sizeof(element));
            elem = elem->next;
            elem-> val = c;
        }
    }
    fclose(file);
    elem->next = NULL;
    return 1;
}



int main(void) {
    int i = 0;


    element * list = NULL;
    lcreate("list.txt", list);

    for(i = 0; i<4; ++i) {
        printf("%c", list->val);
        list = list->next;
    }

    return 0;
}

修复了“文件”为空的问题。

【问题讨论】:

    标签: c linked-list


    【解决方案1】:

    一个明显的问题就在这里:

    FILE * file = NULL;
    
    fopen(fname, "r");
    

    要使fopen 完成很多工作,您需要将fopen 的结果分配给您的FILE *

    file = fopen(fname, "r");
    

    编辑:由于您在 C 中工作,因此不能通过引用传递指针。作为替代方案,您可以将指针传递给指针:

    int lcreate(char *fname, element **list) {
    
         // ...
         *list = malloc(sizeof(element));
         (*list)->next = null;
         (*list)->val = c;
    // ...
    }
    

    基本上,lcreate 中的所有代码都需要引用*list 而不仅仅是list。或者,您可以将一个指向现有列表的指针作为输入,并返回一个指向该列表的指针,因此在 main 中您将拥有类似:list = lcreate("list.txt", list);

    【讨论】:

    • 别忘了elem= list 分配了一个值。如果您希望在更新list 时更新elem,您需要将原始代码中的elem 更改为element **elem= &amp;list,或者在Jerry 的版本中更改element **elem= list
    【解决方案2】:

    fileNULL,您永远不会为其分配文件句柄。

    【讨论】:

      【解决方案3】:

      在您的main 函数中,您还将list 按值传递给lcreate。在lcreate() 函数中,您将覆盖list 的本地副本,而不是更改主函数中list 的值。由于list被初始化为NULL,调用list-&gt;val时会出现段错误。

      【讨论】:

      • 好的,我如何在 lcreate 中覆盖列表?谢谢!
      • @ron - 将双指针传递给list,即element** list; lcreate("list.txt", list);。然后在lcreate 方法中,你像这样分配它:*list = malloc(...)。这将确保调用者将看到被调用者所做的更改。
      【解决方案4】:

      是的——其他人关于FILE 指针以及通过值而不是引用lcreate() 传递list 的说法是正确的。

      您也没有从lcreate() 返回列表的大小——您可能应该通过返回值或指针参数返回它。

      您正尝试在 main() 函数中对列表进行 4 次迭代,但列表中的项目可能少于 4 个。如果list 为NULL,最终printf() 将导致分段错误。

      如果您在进行这些更改后仍有问题,我建议您在代码中添加跟踪,以找出发生分段错误的时间点。

      更新:

      另外请记住在遍历列表后释放分配的内存,否则最终会导致内存泄漏(尽管实际上这对您来说并不是一个问题,因为程序正在结束,但是释放内存是一个好习惯)。

      【讨论】:

        【解决方案5】:

        我还发现了一个额外的问题。在lcreate() 的while 语句中,if 语句malloc 的一些内存的true 子句将其分配给list 但是elem 没有更新。

        while ((c = getc(file)) != EOF)
        {
            if(list == NULL) {
                list = (element*)malloc(sizeof(element));
                if(list == NULL) {
                    return 0;
                }
                list->val = c;
            }
            else {
        

        下一次通过 while 循环 list 将不是非空但 elem 仍然为空,因此 elem->next 的分配尝试遵循空指针,从而导致分段错误(顺便说一句,这意味着您试图访问尚未分配给您的进程的内存):-

        else {
            elem->next=(element*)malloc(sizeof(element));
        

        正如其他人指出的那样,您也不会将 list 返回到 main,因此当您点击 printf() 循环时它仍然是 NULL。

        最后,在查看这些问题时,调试器是您的朋友。您将确切地看到哪一行触发了 seg 错误以及变量的状态。

        【讨论】:

          【解决方案6】:

          最好通过检查非空指针来检查 malloc 是否成功。 此外,您可能希望在 while 之外分配头/第一个链接,以避免每次在 while 循环中对头进行空检查。当然,这些都是优化,以防您的链表变得非常大!

          【讨论】:

            猜你喜欢
            • 2014-03-31
            • 1970-01-01
            • 2021-09-22
            • 2019-04-17
            • 2018-04-12
            • 2017-10-14
            • 2017-08-16
            • 1970-01-01
            相关资源
            最近更新 更多