C语言for循环、strcmp比对及文件读取功能异常问题求助
C身份验证代码修复方案
核心错误点
- 缓冲区溢出:
name数组仅分配5字节,无法容纳最长5位的用户名、空格、5位PIN码及结束符,拼接字符串时内存越界,结果不可预期 - 文件操作顺序错误:先执行文件读取操作,再判断文件指针是否为空,文件打开失败时会直接触发崩溃;仅读取了文件第一行内容,没有遍历所有账户行;在循环内提前关闭文件,后续操作的是野指针
- 首字符丢失:调用
getc(file)吃掉了第一行的第一个字符,导致第一行账户内容残缺,永远匹配失败 - 换行符未处理:
fgets读取的行末尾自带换行符,和用户输入拼接的无换行字符串比对时永远不相等 - for循环逻辑错误:循环条件写为
i=3(赋值语句永远为真),导致死循环,无法实现3次尝试后终止的逻辑 - 匹配逻辑残缺:仅与单次读取的一行内容比对,没有遍历所有账户信息,且匹配成功/失败后没有正确的分支跳转逻辑
修复后代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_TRY 3 #define MAX_NAME 16 #define MAX_PIN 8 #define MAX_LINE 32 int main() { char input[MAX_LINE]; char name[MAX_NAME], pin[MAX_PIN]; char line_buf[MAX_LINE]; FILE *file = NULL; int try_cnt = 0; int matched = 0; // 先判断文件是否打开成功 file = fopen("ident.txt", "r"); if (file == NULL) { printf("Error: could not open ident.txt\n"); return 1; } // 最多允许3次尝试 for (try_cnt = 0; try_cnt < MAX_TRY; try_cnt++) { printf("\n\tEnter your name: "); scanf("%s", name); printf("\n\tEnter your pin number: "); scanf("%s", pin); // 拼接用户输入,避免缓冲区溢出 snprintf(input, sizeof(input), "%s %s", name, pin); printf("\n Entry: %s \n", input); // 重置文件指针到开头,遍历所有行比对 rewind(file); matched = 0; while (fgets(line_buf, sizeof(line_buf), file) != NULL) { // 去掉fgets读取的末尾换行符 line_buf[strcspn(line_buf, "\n")] = '\0'; if (strcmp(line_buf, input) == 0) { matched = 1; break; } } if (matched) { printf("It's a Match\n"); break; } else { if (try_cnt == MAX_TRY - 1) { printf("3 attempts failed, access denied\n"); } else { printf("Invalid Entry. Try Again. \n"); } } } fclose(file); return 0; }
关键修改说明
- 扩大了所有字符串缓冲区的大小,使用
snprintf拼接用户输入避免溢出 - 调整文件操作顺序,打开后先判断是否为空,使用
rewind每次比对前重置文件指针,遍历所有账户行 - 去掉了多余的
getc调用,避免首字符丢失 - 用
strcspn去除fgets读取的换行符,保证比对逻辑正确 - 修正for循环条件为
try_cnt < MAX_TRY,实现3次尝试后自动终止 - 增加匹配标志位,匹配成功直接退出,失败则计数累计直到3次
内容的提问来源于stack exchange,提问作者Sydney Warsaw
相关产品推荐
相关产品推荐

