为什么这个C链表程序会给出“分段错误”?

时间:2010-02-18 23:31:07

标签: c linked-list

第一个函数读取一个包含一堆'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;
}

修复了'file'为空的问题。

6 个答案:

答案 0 :(得分:6)

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

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);

答案 1 :(得分:2)

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

答案 2 :(得分:1)

是的 - 其他人对FILE指针所说的内容,以及按值传递list而不是引用lcreate(),是真的。

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

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

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

<强>更新

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

答案 3 :(得分:1)

main函数中,您还将list的值传递给lcreate。在lcreate()函数中,您将覆盖list的本地副本,而不是更改主函数中list的值。由于list初始化为NULL,因此当您致电list->val时,您会收到段错误。

答案 4 :(得分:0)

我也可以看到另外一个问题。在lcreate()的while语句中,if语句的真正子句malloc的一些内存并将其分配给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-> gt的下一次尝试依次调整空指针,从而导致分段错误(哪个,顺便说一句,意味着你试图访问尚未分配给你的进程的内存): -

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

正如其他人指出的那样,你也没有将list返回给main,所以当你点击printf()循环时它仍然是NULL。

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

答案 5 :(得分:0)

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