C语言程序故障求助:input.txt数据插入record.txt无输出问题
C语言学生数据插入程序异常排查与修复
需求说明
从input.txt文件中提取有效学生数据(包含学生ID、姓名、课程),并按学生ID升序插入到record.txt文件中。
文件内容
input.txt
1 2012 Bob CS21 1999 Teddy CS35 2 3 2001 Eric CS11 2011 CS12 CS87
record.txt初始内容
1287 Nancy CS11 1865 Brown CS33
预期结果
有效插入的数据:
2012 Bob CS21 1999 Teddy CS35 2001 Eric CS11
插入后record.txt(按ID升序排列):
1287 Nancy CS11 1865 Brown CS33 1999 Teddy CS35 2001 Eric CS11 2012 Bob CS21
现有代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX 100 typedef struct { int id; char name[20]; char course[5]; } Student; int read_records(Student s[]) { FILE *fp; int i=0; fp = fopen("record.txt", "r"); if (fp == NULL) { printf("File doesn't exist\n"); return 0; } while (!feof(fp)) { fscanf(fp, "%d %s %s\n", &s[i].id, s[i].name, s[i].course); i++; } fclose(fp); return i; } void write_records(Student s[], int n) { FILE *fp; fp = fopen("record.txt", "w"); if (fp == NULL) { printf("File doesn't exist\n"); return; } for (int i=0; i<n; i++) { fprintf(fp, "%d %s %s\n", s[i].id, s[i].name, s[i].course); } fclose(fp); } void insert_records(Student s[], int n) { FILE *fp; fp = fopen("input.txt", "r"); if (fp == NULL) { printf("File doesn't exist\n"); return; } int i=n; while (!feof(fp)) { fscanf(fp, "%d %s %s\n", &s[i].id, s[i].name, s[i].course); i++; } fclose(fp); write_records(s, i); printf("Insertion is done.\n"); } void display_records(Student s[], int n) { for (int i=0; i<n; i++) { printf("%d %s %s\n", s[i].id, s[i].name, s[i].course); } } int main() { int n; Student s[MAX]; n = read_records(s); int opt; while (1) { printf("1. Insert\n"); printf("2. Display\n"); printf("3. Exit\n"); printf("Choose an option: "); scanf("%d", &opt); switch(opt) { case 1: insert_records(s, n); break; case 2: display_records(s, n); break; case 3: exit(0); } } }
问题现象
运行程序后,选择选项2可正常显示record.txt内容,但选择选项1执行插入操作时,程序无任何输出,未按预期完成数据插入。
问题排查与修复
核心问题分析
feof循环逻辑错误:feof仅在读取失败后返回真,直接用while(!feof(fp))会导致读取格式不匹配时陷入死循环或读取无效数据。比如input.txt中的单行数字,fscanf读取ID后无法获取姓名和课程,读取失败但feof未触发,循环持续执行。- 未过滤无效数据:
input.txt中存在单行数字、格式错误的行,原代码未判断读取字段数量,直接将无效数据写入。 - 记录数量未更新:
insert_records新增记录后,主函数的n值未同步更新,导致display_records仍只显示初始记录。 - 缺少排序逻辑:原代码未对合并后的学生数据按ID升序排序,无法满足需求。
修复后的完整代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX 100 typedef struct { int id; char name[20]; char course[5]; } Student; // 比较函数,用于qsort按ID升序排序 int compare_students(const void *a, const void *b) { const Student *s1 = (const Student *)a; const Student *s2 = (const Student *)b; return s1->id - s2->id; } int read_records(Student s[]) { FILE *fp; int i = 0; fp = fopen("record.txt", "r"); if (fp == NULL) { printf("File doesn't exist\n"); return 0; } // 用fscanf返回值判断是否成功读取3个字段 while (fscanf(fp, "%d %s %s", &s[i].id, s[i].name, s[i].course) == 3) { i++; if (i >= MAX) break; // 防止数组越界 } fclose(fp); return i; } void write_records(Student s[], int n) { FILE *fp; fp = fopen("record.txt", "w"); if (fp == NULL) { printf("File doesn't exist\n"); return; } // 按ID升序排序后写入 qsort(s, n, sizeof(Student), compare_students); for (int i = 0; i < n; i++) { fprintf(fp, "%d %s %s\n", s[i].id, s[i].name, s[i].course); } fclose(fp); } int insert_records(Student s[], int n) { FILE *fp; fp = fopen("input.txt", "r"); if (fp == NULL) { printf("File doesn't exist\n"); return n; } int i = n; int read_count; // 读取每行,仅保留成功读取3个字段的有效数据 while ((read_count = fscanf(fp, "%d %s %s", &s[i].id, s[i].name, s[i].course)) != EOF) { if (read_count == 3 && i < MAX) { i++; } // 跳过当前行剩余字符,避免干扰下一次读取 char buf[100]; fgets(buf, sizeof(buf), fp); } fclose(fp); write_records(s, i); printf("Insertion is done.\n"); return i; // 返回更新后的记录总数 } void display_records(Student s[], int n) { // 排序后显示,保证顺序正确 qsort(s, n, sizeof(Student), compare_students); for (int i = 0; i < n; i++) { printf("%d %s %s\n", s[i].id, s[i].name, s[i].course); } } int main() { int n; Student s[MAX]; n = read_records(s); int opt; while (1) { printf("1. Insert\n"); printf("2. Display\n"); printf("3. Exit\n"); printf("Choose an option: "); scanf("%d", &opt); switch(opt) { case 1: n = insert_records(s, n); // 更新记录总数 break; case 2: display_records(s, n); break; case 3: exit(0); default: printf("Invalid option, try again.\n"); } } return 0; }
修复细节说明
- 替换
feof循环为fscanf返回值判断,确保仅读取包含ID、姓名、课程的有效行 - 新增
compare_students函数,配合qsort实现按ID升序排序,写入文件和显示前都会执行排序 insert_records返回更新后的记录数,主函数同步更新n,保证后续显示正确- 用
fgets跳过无效行的剩余字符,避免格式错误影响后续读取 - 增加数组越界判断,防止数据溢出
内容的提问来源于stack exchange,提问作者Bob
相关产品推荐
相关产品推荐

