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

使用fscanf和fseek读写结构体时仅存储最后一个学生数据的问题

问题排查与解决:学生成绩读取函数仅保留最后一条数据

核心问题定位

loadGrades函数中用于遍历学生数组的索引变量i始终为0,所有学生数据都被写入到students[0]位置,后续数据直接覆盖之前的内容,最终仅保留最后一个学生的信息。

修复后的loadGrades函数

int loadGrades(char filename[], Student students[]) {
    char buffer[MAX_STR];
    int n_students = 0;
    int i = 0;
    int j = 0;
    FILE *fitxer = NULL;
    fitxer = fopen(filename, "r");
    if (NULL == fitxer) {
        printf("文件打开错误");
        return 0; // 错误场景返回0,避免后续处理无效数据
    } else {
        // 用fscanf返回值判断读取是否成功,替代不可靠的feof判断
        while (fscanf(fitxer, "%s", students[i].first_name) == 1) {
            fscanf(fitxer, "%s", students[i].last_name1);
            fscanf(fitxer, "%s", students[i].last_name2);
            fscanf(fitxer, "%s", buffer); // 读取分隔符|
            for (j = 0; j < 10; j++) {
                fscanf(fitxer, "%f", &students[i].CA[j]);
            }
            fscanf(fitxer, "%s", buffer); // 读取分隔符|
            for (j = 0; j < 3; j++) {
                fscanf(fitxer, "%f", &students[i].Project[j]);
            }
            fscanf(fitxer, "%f", &students[i].report);
            fscanf(fitxer, "%s", buffer); // 读取分隔符|
            fscanf(fitxer, "%f", &students[i].final_exam);
            n_students++;
            i++; // 关键修正:每次读取完一个学生后,索引递增到下一个数组位置
            // 防止数组越界
            if (i >= MAX) {
                printf("学生数量超过上限%d,停止读取", MAX);
                break;
            }
        }
        fclose(fitxer);
    }
    return n_students;
}

额外隐藏问题修复

1. computeGrades函数的计算逻辑错误

原代码中项目加权计算重复使用了Project[0],应改为Project[2]:

void computeGrades(Student students[], int n_students) {
    int i = 0;
    int j = 0;
    float average = 0;
    float kg = 0;
    float pg = 0;
    for (i = 0; i < n_students; i++) {
        average = 0;
        kg = 0;
        pg = 0;
        for (j = 0; j < 10; j++) {
            average += students[i].CA[j];
        }
        average /= 10;
        // 修正:将重复的Project[0]替换为Project[2]
        pg = students[i].Project[0] * 0.3 + students[i].Project[1] * 0.3 +
             students[i].Project[2] * 0.3 + students[i].report * 0.1;
        kg = 0.7 * students[i].final_exam + 0.3 * average;
        if (students[i].final_exam > kg) {
            kg = students[i].final_exam;
        }
        students[i].sem_grade = 0.5 * kg + 0.5 * pg;
    }   
}

2. updateFile函数的文件位置与写入错误

原代码中fseek偏移计算错误,写入大小参数错误,修正如下:

void updateFile() {
    Student student;
    FILE *fitxer = NULL;
    long pos; // 用long存储文件位置,避免溢出
    fitxer = fopen("students.bin", "rb+");
    if (NULL != fitxer) {
        // 用fread返回值判断是否读取到有效数据
        while (fread(&student, sizeof(Student), 1, fitxer) == 1) {
            pos = ftell(fitxer); // 记录当前读取后的文件位置
            if ((student.sem_grade >= 5.0) && (student.final_exam < 4.0)){
                student.sem_grade = 4.0;
                // 回退到当前学生数据的起始位置
                fseek(fitxer, pos - sizeof(Student), SEEK_SET);
                fwrite(&student, sizeof(Student), 1, fitxer);
                // 恢复到读取后的位置,继续下一次循环
                fseek(fitxer, pos, SEEK_SET);
            }
        }
        fclose(fitxer);
    } else {
        printf("二进制文件打开错误");
    }
}

修复要点总结

  • loadGrades:添加i++实现数组索引递增,改用fscanf返回值判断读取状态(比feof更可靠),增加数组越界检查。
  • computeGrades:修正项目加权计算的变量错误,确保三个项目分别参与计算。
  • updateFile:用ftell记录文件位置,修正fseek偏移量,写入时使用正确的结构体大小,用fread返回值控制循环。

内容的提问来源于stack exchange,提问作者Pepinho02

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 21:34:59