You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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执行插入操作时,程序无任何输出,未按预期完成数据插入。


问题排查与修复

核心问题分析

  1. feof循环逻辑错误:feof仅在读取失败后返回真,直接用while(!feof(fp))会导致读取格式不匹配时陷入死循环或读取无效数据。比如input.txt中的单行数字,fscanf读取ID后无法获取姓名和课程,读取失败但feof未触发,循环持续执行。
  2. 未过滤无效数据:input.txt中存在单行数字、格式错误的行,原代码未判断读取字段数量,直接将无效数据写入。
  3. 记录数量未更新:insert_records新增记录后,主函数的n值未同步更新,导致display_records仍只显示初始记录。
  4. 缺少排序逻辑:原代码未对合并后的学生数据按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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 04:05:55