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

第一个函数读取一个包含一堆’char’的文件,并将它们放在一个链表中。 它无法正常工作:(。

#include  #include  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; ival); list = list->next; } return 0; } 

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

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

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

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

main函数中,您还将按值传递给lcreate 。 在lcreate()函数中,您将覆盖list的本地副本,而不是更改main函数中list的值。 由于list初始化为NULL ,因此在调用list->val

是的 – 其他人对FILE指针的说法,并且按值传递而不是引用lcreate() ,是真的。

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

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

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

更新:

还要记得在遍历列表后释放你已经分配的内存,否则你最终会出现内存泄漏(虽然实际上这对你来说不是一个问题,因为程序结束了,但释放内存是进入的好习惯)。

我也可以看到另外一个问题。 在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不会是非null但是elem仍然是null所以elem-> next的赋值会尝试依赖空指针,从而导致分段错误(顺便说一句,这意味着你试图访问内存,尚未分配给您的流程): –

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

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

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

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