C语言链表头指针异常移动求助:从文件构建链表失败
C语言链表构建问题:从文件读取数据时的节点连接错误
我是编程初学者,编写了一个从文本文件读取数据构建C语言链表的程序,但遇到问题:添加新节点时head指针不断移动。尝试修改后,又出现头指针无法连接到第二个节点的新问题。
初始代码
#include<stdio.h> #include<stdlib.h> #include<string.h> #include <stdbool.h> //Visitor information struct visitData { char *SrNo; char *ticketNo; char *Name; char *ID; }; //Ticket linked list struct ticket { struct visitData visitor; struct ticket *nextPtr; }; int main() { //main FILE *fPtr = NULL; fPtr = fopen("Tickets.txt", "a+"); if (fPtr == NULL) { printf("Error, please try again.\n"); return 0; } FILE *outfPtr = NULL; outfPtr = fopen("output.txt", "w"); if (outfPtr == NULL) { puts("Error, could not create output file, please try again."); return 0; } else { struct ticket *head = NULL; struct ticket *new = NULL; struct visitData *nextPtr = NULL; char sr[2]; char ticketNumber[20]; char name[30]; char id[24]; rewind(fPtr); if (fscanf(fPtr, "%2s%20s%29s%24s", sr, ticketNumber, name, id) == 4) { new = malloc(sizeof(struct ticket)); new->visitor.SrNo = strdup(sr); new->visitor.ticketNo = strdup(ticketNumber); new->visitor.Name = strdup(name); new->visitor.ID = strdup(id); new->nextPtr = NULL; head = new; printf("%s\n", head->visitor.SrNo); while (!feof(fPtr)) { if (fscanf(fPtr, "%2s%20s%29s%24s", sr, ticketNumber, name, id) == 4) new->visitor.SrNo = sr; new->visitor.ticketNo = ticketNumber; new->visitor.Name = name; new->visitor.ID = id; new->nextPtr = malloc(sizeof(struct ticket)); new = new->nextPtr; new->nextPtr = NULL; } } } else { printf("%d",fscanf(fPtr, "%2s%20s%29s%24s", sr, ticketNumber, name, id)); new->visitor.SrNo = "0"; } if (head == NULL) { printf("List is empty\n"); } struct ticket *Ptr = NULL; Ptr = head; printf("%s\n", Ptr->visitor.SrNo); while (Ptr != NULL) { printf("%s %s\n", Ptr->visitor.SrNo, Ptr->visitor.ticketNo); Ptr = Ptr->nextPtr; } } }
修改后的代码
#include<stdio.h> #include<stdlib.h> #include<string.h> #include <stdbool.h> //Visitor information struct visitData { char *SrNo; char *ticketNo; char *Name; char *ID; }; //Ticket linked list struct ticket { struct visitData visitor; struct ticket *nextPtr; }; int main() { //main FILE *fPtr = NULL; fPtr = fopen("Tickets.txt", "a+"); if (fPtr == NULL) { printf("Error, please try again.\n"); return 0; } FILE *outfPtr = NULL; outfPtr = fopen("output.txt", "w"); if (outfPtr == NULL) { puts("Error, could not create output file, please try again."); return 0; } else { struct ticket *head = NULL; struct ticket *new = NULL; struct visitData *nextPtr = NULL; char sr[2]; char ticketNumber[20]; char name[30]; char id[24]; rewind(fPtr); if (fscanf(fPtr, "%2s%20s%29s%24s", sr, ticketNumber, name, id) == 4) { new = malloc(sizeof(struct ticket)); new->visitor.SrNo = strdup(sr); new->visitor.ticketNo = strdup(ticketNumber); new->visitor.Name = strdup(name); new->visitor.ID = strdup(id); new->nextPtr = NULL; head = new; printf("%s\n", head->visitor.SrNo); while (!feof(fPtr)) { if (fscanf(fPtr, "%2s%20s%29s%24s", sr, ticketNumber, name, id) == 4) { new = malloc(sizeof(struct ticket)); new->visitor.SrNo = sr; new->visitor.ticketNo = ticketNumber; new->visitor.Name = name; new->visitor.ID = id; new->nextPtr = malloc(sizeof(struct ticket)); new = new->nextPtr; new->nextPtr = NULL; } } } else { printf("%d",fscanf(fPtr, "%2s%20s%29s%24s", sr, ticketNumber, name, id)); new->visitor.SrNo = "0"; } if (head == NULL) { printf("List is empty\n"); } struct ticket *Ptr = NULL; Ptr = head; printf("%s\n", Ptr->visitor.SrNo); while (Ptr != NULL) { printf("%s %s\n", Ptr->visitor.SrNo, Ptr->visitor.ticketNo); Ptr = Ptr->nextPtr; } } }
问题分析与解决方案
初始代码的核心问题
- 节点内容被覆盖:循环中没有为新数据分配新节点,而是直接修改当前
new节点的字段,导致之前的节点数据被覆盖,看起来像head指针在移动。 - if语句无大括号:
if(fscanf(...))后面没有加{},导致后续代码不管fscanf是否成功都会执行,逻辑混乱。 - 野指针风险:修改后的代码中直接将栈数组(如
sr)的地址赋值给结构体指针,栈内存会在函数结束后释放,导致指针指向无效内存。
修改后代码的新问题
新分配了节点,但没有将上一个节点的nextPtr指向新节点,所有新节点都是孤立的,head始终只指向第一个节点,后续节点无法被访问。另外还多分配了一个空节点,导致链表末尾出现无效节点。
修正后的完整代码
#include<stdio.h> #include<stdlib.h> #include<string.h> // 访客信息结构体 struct visitData { char *SrNo; char *ticketNo; char *Name; char *ID; }; // 链表节点结构体 struct ticket { struct visitData visitor; struct ticket *nextPtr; }; // 释放链表内存 void freeList(struct ticket *head) { struct ticket *temp; while (head != NULL) { temp = head; head = head->nextPtr; // 释放字符串内存 free(temp->visitor.SrNo); free(temp->visitor.ticketNo); free(temp->visitor.Name); free(temp->visitor.ID); // 释放节点内存 free(temp); } } int main() { FILE *fPtr = fopen("Tickets.txt", "r"); // 只读模式即可,不需要a+ if (fPtr == NULL) { printf("Error opening file.\n"); return 1; } FILE *outfPtr = fopen("output.txt", "w"); if (outfPtr == NULL) { puts("Error creating output file."); fclose(fPtr); return 1; } struct ticket *head = NULL; struct ticket *tail = NULL; // 用tail跟踪链表末尾 struct ticket *newNode = NULL; char sr[3]; // 留一位给字符串结束符 char ticketNumber[21]; char name[31]; char id[25]; // 用fscanf返回值控制循环,避免feof的陷阱 while (fscanf(fPtr, "%2s%20s%29s%24s", sr, ticketNumber, name, id) == 4) { // 分配新节点 newNode = malloc(sizeof(struct ticket)); if (newNode == NULL) { printf("Memory allocation failed.\n"); freeList(head); fclose(fPtr); fclose(outfPtr); return 1; } // 复制字符串,避免野指针 newNode->visitor.SrNo = strdup(sr); newNode->visitor.ticketNo = strdup(ticketNumber); newNode->visitor.Name = strdup(name); newNode->visitor.ID = strdup(id); newNode->nextPtr = NULL; if (head == NULL) { // 链表为空时,head和tail都指向第一个节点 head = newNode; tail = newNode; } else { // 将tail的next指向新节点,更新tail tail->nextPtr = newNode; tail = newNode; } } // 打印链表内容 struct ticket *current = head; if (current == NULL) { printf("List is empty.\n"); } else { while (current != NULL) { printf("%s %s\n", current->visitor.SrNo, current->visitor.ticketNo); fprintf(outfPtr, "%s %s %s %s\n", current->visitor.SrNo, current->visitor.ticketNo, current->visitor.Name, current->visitor.ID); current = current->nextPtr; } } // 清理资源 freeList(head); fclose(fPtr); fclose(outfPtr); return 0; }
关键修正点
- 用tail指针管理链表末尾:每次新节点创建后,将上一个节点的
nextPtr指向它,确保链表连续。 - 正确的循环控制:直接用
fscanf的返回值判断是否读取到有效数据,避免feof的常见陷阱。 - 安全的字符串处理:所有字符串都用
strdup分配堆内存,避免栈内存失效导致的野指针。 - 资源清理:添加了链表内存释放函数,避免内存泄漏;及时关闭文件。
内容的提问来源于stack exchange,提问作者THKing
相关产品推荐
相关产品推荐

