C语言单链表从文件加载数据问题:重启后无法恢复链表数据
问题分析与修复方案
核心问题点
- 文件读写格式不匹配:插入数据时写入带描述文本的内容(如
visitor info has been added: ...),但读取时直接按四个字符串解析,导致读取内容完全错误,无法还原数据。 - 文件路径不一致:插入时写入
output.txt,读取时打开ticket.txt,文件不对应,读不到之前存储的数据。 - 链表传递与构建错误:
readfile用值传递指针,无法更新主函数的链表头;构建链表时未遍历到尾部,新节点不断覆盖前一个节点的next,最终链表仅保留最后一个节点。 - 缺少错误处理:未判断文件是否成功打开,可能导致空指针访问崩溃。
修正后的代码
1. 修正插入函数(addinfo)
调整文件写入格式为纯数据,统一使用ticket.txt存储可恢复的数据:
tick *addinfo(tick *previous, char* serial, char* ticketno, char* name, char* id) { tick *info = malloc(sizeof(tick)); info->nextPtr = NULL; info->visitor.SrNo = strdup(serial); info->visitor.ticketNo = strdup(ticketno); info->visitor.Name = strdup(name); info->visitor.ID = strdup(id); if (previous != NULL) { previous->nextPtr = info; } printf("visitor info has been added: %s %s %s %s\n", info->visitor.SrNo, info->visitor.ticketNo, info->visitor.Name, info->visitor.ID); // 写入纯数据到ticket.txt,用于后续恢复 FILE *ptroutfile = fopen("ticket.txt", "a"); if (ptroutfile != NULL) { fprintf(ptroutfile, "%s %s %s %s\n", info->visitor.SrNo, info->visitor.ticketNo, info->visitor.Name, info->visitor.ID); fclose(ptroutfile); } return info; }
2. 修正读取文件函数(readfile)
改为返回链表头指针,正确遍历链表尾部添加节点,增加文件打开失败判断:
tick* readfile() { tick *startPtr = NULL; tick *currentPtr = NULL; FILE* cfptr = fopen("ticket.txt", "r"); if (cfptr == NULL) { printf("No existing data file found.\n"); return startPtr; } char srno[20], ticketNo[20], name[30], id[20]; while (fscanf(cfptr, "%s %s %s %s", srno, ticketNo, name, id) == 4) { tick *info = malloc(sizeof(tick)); info->nextPtr = NULL; info->visitor.SrNo = strdup(srno); info->visitor.ticketNo = strdup(ticketNo); info->visitor.Name = strdup(name); info->visitor.ID = strdup(id); if (startPtr == NULL) { // 第一个节点作为链表头 startPtr = info; currentPtr = info; } else { // 追加到链表尾部 currentPtr->nextPtr = info; currentPtr = info; } } fclose(cfptr); return startPtr; }
3. 修正主函数调用
接收readfile返回的链表头指针,可正常恢复数据:
int main () { tick *visitorinfo = NULL; // 从文件恢复链表 visitorinfo = readfile(); // 测试:遍历打印恢复的数据 tick *temp = visitorinfo; while (temp != NULL) { printf("Loaded data: %s %s %s %s\n", temp->visitor.SrNo, temp->visitor.ticketNo, temp->visitor.Name, temp->visitor.ID); temp = temp->nextPtr; } // 后续可调用addinfo添加新节点,需注意维护尾指针或遍历到尾部再添加 // 程序结束前需释放链表内存(自行实现) return 0; }
额外说明
- 若需要保留日志式的输出,可以同时写入
output.txt(带描述)和ticket.txt(纯数据)。 - 若数据包含空格,不能用
fscanf("%s")读取,需改用fgets配合字符串分割处理。 - 程序退出前务必释放链表所有节点的内存,避免内存泄漏。
内容的提问来源于stack exchange,提问作者user19766923
相关产品推荐
相关产品推荐

