使用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
相关产品推荐
相关产品推荐

