第一个函数读取一个包含一堆'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'为空的问题。
答案 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)
file
为NULL
,您永远不会为其分配文件句柄。
答案 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循环中对头进行空检查。当然,这些都是优化,万一你的链表变得非常大!