在C语言中通过文件处理验证学生ID输入的问题排查
学生ID重复验证功能异常排查与修复
问题场景
- 功能需求:添加学生时需验证ID唯一性,若ID已存在则禁止重复添加
- 异常现象:尝试添加ID为2016的学生时,系统错误提示该ID已存在(实际文件中仅存ID为2015的学生)
原代码
void add_student(){ int isFound = 0; FILE *fp; // to open a file, fopen, fclose. fp = fopen("record.txt","ab+"); //fopen() function creates the file if it does not exist. --ab+ Open a binary file in append mode for writing at the end of the file. fflush(stdin); printf("\nStudent Name: ");gets(students.name); printf("\nStudent ID Number: ");scanf("%s",students.ID); printf("\nCourse: ");scanf("%s",students.course); printf("\nYear Level: ");scanf("%d",&students.yrlvl); printf("\nAge: ");scanf("%d",&students.age); FILE *fa; fa = fopen("record.txt","r"); while(fread(&students,sizeof(students),1,fa) == 1) // { if(strcmp(students.ID,students.ID) == 0) // Check if the user already in the file { isFound = 1; break; } } if(isFound == 1) { printf("\nStudent ID Number: %s already in the System. Please select Edit to modify same Student ID", students.ID); } else { fwrite(&students, sizeof(students), 1, fp); // Add Student printf("\nAdded Successfully"); } fclose(fa); fclose(fp);// close the file return; }
问题分析
- ID对比逻辑完全错误:
strcmp(students.ID, students.ID)是将当前从文件读取的学生ID和自身比较,结果永远为0,导致第一次循环就标记isFound=1,无论输入ID是否重复。 - 输入数据被覆盖:读取文件时直接把数据写入
students变量,覆盖了用户刚输入的信息,后续提示的ID是文件中读取的旧ID,而非用户输入的新ID。 - 文件操作冗余且不安全:同时打开两个文件指针操作同一文件,易引发指针位置混乱;
gets()存在缓冲区溢出风险,fflush(stdin)属于未定义行为,不同编译器处理结果不一致。
修复后的代码
#include <string.h> #include <stdio.h> // 假设students是全局结构体,补充示例定义 typedef struct { char name[50]; char ID[20]; char course[50]; int yrlvl; int age; } Student; Student students; void add_student(){ int isFound = 0; char inputID[20]; // 临时存储用户输入的ID,避免被覆盖 FILE *fp; // 安全清理输入缓冲区 int c; while ((c = getchar()) != '\n' && c != EOF); printf("\nStudent Name: "); fgets(students.name, sizeof(students.name), stdin); // 去除fgets读取的换行符 students.name[strcspn(students.name, "\n")] = '\0'; printf("\nStudent ID Number: "); scanf("%s", inputID); strcpy(students.ID, inputID); // 同步到结构体 printf("\nCourse: "); scanf("%s", students.course); printf("\nYear Level: "); scanf("%d", &students.yrlvl); printf("\nAge: "); scanf("%d", &students.age); // 打开文件(可读可写) fp = fopen("record.txt", "rb+"); if (fp == NULL) { // 文件不存在则创建 fp = fopen("record.txt", "wb"); if (fp == NULL) { printf("\nFailed to open file!"); return; } fwrite(&students, sizeof(students), 1, fp); printf("\nAdded Successfully"); fclose(fp); return; } // 遍历文件验证ID唯一性 Student tempStudent; while (fread(&tempStudent, sizeof(tempStudent), 1, fp) == 1) { if (strcmp(tempStudent.ID, inputID) == 0) { isFound = 1; break; } } if (isFound == 1) { printf("\nStudent ID Number: %s already in the System. Please select Edit to modify same Student ID", inputID); } else { // 移动指针到文件末尾写入新数据 fseek(fp, 0, SEEK_END); fwrite(&students, sizeof(students), 1, fp); printf("\nAdded Successfully"); } fclose(fp); return; }
关键修改点
- 新增
inputID临时变量存储用户输入的ID,避免读取文件时被覆盖 - 修正ID对比逻辑:用文件中读取的
tempStudent.ID和用户输入的inputID对比 - 替换
gets()为fgets()并处理换行符,消除缓冲区溢出风险 - 用安全方式清理输入缓冲区,替代
fflush(stdin) - 合并文件操作,使用单个文件指针完成验证与写入,避免指针混乱
- 增加文件打开失败的异常处理
内容的提问来源于stack exchange,提问作者anna
相关产品推荐
相关产品推荐

