C语言带3次尝试限制的用户名密码文件比对问题求助
修复你的C语言用户名密码验证程序
我来帮你搞定这个问题,你的代码主要在函数参数、文件读取逻辑、字符串比较和循环控制这几个地方出了问题,下面我先梳理问题点,再给出修复后的完整代码。
原代码的核心问题
- 函数参数不匹配:
identfilecreate和passverify的声明与定义参数不一致,比如identfilecreate声明要求传入char数组,但定义里没有参数,这会导致编译错误或未定义行为。 - 文件读取重复且指针混乱:
passverify每次调用都尝试从全局文件指针fpr读取,但第一次读完后指针已经到文件末尾,后续调用读不到任何内容;而且没必要每次验证都读文件,应该一次性加载所有用户信息。 - 字符串比较逻辑错误:你读完文件后用
line[i](此时i是总行数,已经超出数组索引范围)去和用户输入比较,正确的做法是遍历所有已加载的用户行逐个匹配。 - 循环控制逻辑错误:main里的for循环不管验证成功与否都会执行3次,而且
if ((i = 2))是赋值操作不是判断,完全起不到“3次失败后结束”的作用。 - 全局变量滥用:全局文件指针容易引发意外问题,比如指针位置混乱,不如提前加载用户信息到数组中。
修复后的完整代码
#define LSIZ 128 #define RSIZ 10 #include <stdio.h> #include <stdlib.h> #include <string.h> // 全局存储用户信息数组,提前加载所有用户数据 char user_records[RSIZ][LSIZ]; int total_users = 0; // 创建用户文件并加载所有用户信息到数组 void identfilecreate() { FILE *fpw = fopen("ident.txt", "w"); if (!fpw) { perror("Failed to create file"); exit(EXIT_FAILURE); } // 写入预设用户和密码,用制表符分隔 fprintf(fpw, "Mark\t12345\nHannah\t23456\nJohn\t34567\nSammy\t45678\nDom\t56789\nOlivia\t67890\n"); fclose(fpw); FILE *fpr = fopen("ident.txt", "r"); if (!fpr) { perror("Failed to open file"); exit(EXIT_FAILURE); } // 读取所有用户信息到全局数组,同时去掉换行符 while (fgets(user_records[total_users], LSIZ, fpr) && total_users < RSIZ) { // 替换换行符为字符串结束符 size_t len = strlen(user_records[total_users]); if (len > 0 && user_records[total_users][len - 1] == '\n') { user_records[total_users][len - 1] = '\0'; } total_users++; } fclose(fpr); } // 验证用户输入,返回1表示验证成功,0表示失败 int passverify() { char user[LSIZ], pin[LSIZ], user_input[LSIZ]; printf("Please enter your username: "); scanf("%s", user); printf("Please enter your pin: "); scanf("%s", pin); // 拼接用户名和密码,和文件中的格式保持一致(制表符分隔) snprintf(user_input, sizeof(user_input), "%s\t%s", user, pin); // 遍历所有用户记录,寻找匹配项 for (int i = 0; i < total_users; i++) { if (strcmp(user_input, user_records[i]) == 0) { printf("You entered the correct username and password.\n"); return 1; // 验证成功,返回1 } } printf("You have entered the wrong username and password.\n"); return 0; // 验证失败,返回0 } int main() { // 初始化用户文件并加载数据 identfilecreate(); int attempts = 3; for (int i = 0; i < attempts; i++) { if (passverify() == 1) { // 验证成功,直接退出循环 return 0; } // 提示剩余次数,注意最后一次失败后不需要提示 if (i < attempts - 1) { printf("You have %d more tries\n", attempts - i - 1); } } // 3次失败后结束程序 printf("The program will now end\n"); return 0; }
关键修改说明
- 全局用户数组:提前把所有用户信息加载到
user_records数组中,后续验证直接用数组数据,避免重复读取文件,也解决了文件指针混乱的问题。 - 函数参数修正:统一了函数的声明和定义,
identfilecreate改为无参数的void函数(因为不需要返回值,也不需要传入参数),passverify返回int类型表示验证结果。 - 字符串比较逻辑:用
snprintf更安全地拼接用户输入(避免strcat可能的缓冲区溢出),然后遍历所有用户记录逐个比较,找到匹配项就立即返回成功。 - 循环控制优化:main函数中根据
passverify的返回值决定是否终止循环,验证成功直接退出程序;失败后提示剩余次数,3次失败后才结束程序。 - 错误处理:添加了文件打开失败的错误提示,用
perror打印具体错误信息,方便调试。
内容的提问来源于stack exchange,提问作者Vigij
相关产品推荐
相关产品推荐

