我只是在学习链接列表,我必须做一个包含很多部分的作业,但是我要开始,我需要做的第一件事是将输入文件读入一个链表。 该文件的一部分是:
George Washington, 2345678
John Adams, 3456789
Thomas Jefferson, 4567890
James Madison, 0987654
James Monroe, 9876543
John Quincy Adams, 8765432
并且共包含26行。
我现在想做的只是在文件中阅读。 我尝试使用此代码(现在主要用于)
#include <stdio.h>
#include <stdlib.h>
struct node{
char name[20];
int id;
struct node *next;
}*head;
int main(void){
struct node *temp;
temp = (struct node *)malloc(sizeof(struct node));
head = temp;
FILE *ifp;
ifp = fopen("AssignmentOneInput.txt", "r");
int c = 0;
while(c<26){
fscanf(ifp, "%s", &temp->name);
fscanf(ifp, "%d", &temp->id);
printf("%d\n", c);
temp = temp->next;
c++;
}
对于输出,我知道扫描了第一个名称和第一个ID,因为c的值显示为0(现在我使用c的值任意控制fscanf)。但在那之后,程序崩溃了。所以问题必须是temp = temp->next;
它编译得很好。
我对链接列表很新,所以我真的不知道自己在做什么。
感谢您的帮助!
答案 0 :(得分:1)
首先,由于您在C
写作,因此无需强制转换malloc
。
其次,您必须自己为每个新节点分配内存。
第三,数组的名称已经衰减到一个指针,因此你不应该使用它的&
,因为这样你就会得到一个指向你不想要的指针。
最后,您需要修复scanf
语法来处理字段中的空格。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node{
char name[20];
int id;
struct node *next;
}*head;
int main(void){
struct node *temp;
temp = malloc(sizeof(struct node));
temp->next = NULL;
head = temp;
FILE *ifp;
ifp = fopen("AssignmentOneInput.txt", "r");
int c = 0;
char buffer[1024];
memset(buffer, 0, 1024);
while(c<5){
fgets(buffer, 1024, ifp);
sscanf(buffer, "%19[^,], %d", temp->name, &temp->id);
printf("%d %s %d\n",c, temp->name, temp->id);
temp->next = malloc(sizeof(struct node));
temp = temp->next;
temp->next = NULL;
c++;
}
}
答案 1 :(得分:1)
在以下几行中,您已为列表中的单个元素(一个struct node
)分配了足够的空间,并将head
指针指向它:
temp = (struct node *)malloc(sizeof(struct node));
head = temp;
稍后您会将值读入此元素的name
和id
字段:
fscanf(ifp, "%s", &temp->name);
fscanf(ifp, "%d", &temp->id);
但temp->next
指向的是什么?你到目前为止只为一个元素分配了空间。在将每个后续元素添加到列表中时,需要为每个后续元素分配空间。
编辑:正如@ merlin2011所示,这个答案只会帮助您解决程序崩溃问题,但不会让您的程序完全正常运行。但是,希望你能够在没有崩溃的情况下更好地调试它。
答案 2 :(得分:1)
主要问题当然是temp = temp->next
设置从未初始化的字段next
的临界值,导致代码段。在下一个循环中出现故障。
存在链接列表问题和输入问题。建议在找到好的数据之前不要分配空间。
以temp_head
开头。代码仅使用next
的{{1}}字段。
temp_head
每当代码读取行数据时,建议使用struct node temp_head;
temp_head.next = NULL;
struct node *p = &temp_head;
读取行,然后扫描缓冲区。
fgets()
使用char buf[100];
while (fgets(buf, sizeof buf, ifp) != NULL) {
struct node nbuf;
扫描缓冲区。使用sscanf()
阅读'%[^,]'
。
','
注意:
不需要 if (2 != sscanf(buf, " %19[^,],%d", nbuf.name, &nbuf.id)) {
break; // Invalid data encountered
}
nbuf.next = NULL;
// Code does not allocate data until good data was found
p->next = malloc(sizeof *(p->next));
if (p->next == NULL) break; // OOM
p = p->next;
*p = nbuf; // Copy the data
}
head = temp_head.next;
中的演员。
考虑这种分配方式:temp = (struct node *)malloc(sizeof(struct node));
,IMO更容易编码,维护更少。
temp = malloc(sizeof *temp)
有3个问题:对字符串输入没有限制,不需要fscanf(ifp, "%s", &temp->name); fscanf(ifp, "%d", &temp->id);
并且无法检查扫描结果。请注意,上面的代码使用&
,它将字符串输入限制为19 (2 != sscanf(buf, " %19[^,], %d", nbuf.name, &nbuf.id)
(为终止char
留出空间,当字段为数组时不使用'\0'
,并且检查是否成功扫描了2个字段。
在&
结束之前,代码应该释放分配的数据。