C语言中strcmp()未按预期返回0:用户名密码验证异常排查
密码对比异常问题排查与修复
问题场景
对比用户输入的用户名和密码,待验证的字符串从文件userdata.txt读取。目前用户名对比正常,但密码对比时strcmp()始终无法返回0,导致校验失败。
原代码
#include <stdio.h> #include <stdlib.h> #include <string.h> const int MAX_SIZE = 100; int main() { FILE *fp; char *filename = "userdata.txt"; char arr[100][MAX_SIZE]; //open for writing fp = fopen(filename, "r"); //verify open if(fp == NULL) { printf("%s does not exist", filename); return 0; } int index = 0; //read file into array while(fgets(arr[index], MAX_SIZE, fp) != NULL) { index++; } //username input char username[100]; printf("Username: "); scanf("%s", username); //password input char password[100]; printf("Password: "); scanf("%s", password); int check1 = 0; int check2 = 0; int x; for (int i = 0 ; i<index ; i++) { char *token = strtok(arr[i], " "); while (token != NULL) { x = strcmp(token,username); printf("%d\n",x); printf("%s %s\n",token,username); if(!strcmp(token,username)) { check1 = 1; } token = strtok(NULL, " "); x = strcmp(token,username); printf("%d\n",x); printf("%s %s\n",token,password); if(!strcmp(token,username)) { check2 = 1; } token = strtok(NULL, " "); if(check1&&check2) { printf("The amount is: %s\n",token); return 0; } token = strtok(NULL, " "); check1=0; check2=0; } } printf("Username/Password mismatch!!!\n"); return 0; }
控制台输出
Username: user1 Password: password1 0 user1 user1 -5 password1 password1 1 user2 user1 -5 password2 password1 2 user3 user1 -5 password3 password1 3 user4 user1 -5 password4 password1 4 user5 user1 -5 password5 password1 5 user6 user1 -5 password6 password1 Username/Password mismatch!!!
错误原因
- fgets读取的字符串包含换行符:
fgets()会将文件中的换行符\n一并读入到数组元素中,导致分割后的密码字符串末尾带有\n。而scanf("%s", password)读取用户输入时,会自动忽略换行符,因此两个字符串实际内容不一致,strcmp()返回非0值。 - 密码校验的对比对象错误:代码中校验密码时,错误地使用
strcmp(token, username)进行对比,正确的应该是strcmp(token, password)。这个逻辑错误直接导致check2永远无法被设置为1,最终无法触发校验成功的分支。
修复后的代码
#include <stdio.h> #include <stdlib.h> #include <string.h> const int MAX_SIZE = 100; int main() { FILE *fp; char *filename = "userdata.txt"; char arr[100][MAX_SIZE]; fp = fopen(filename, "r"); if(fp == NULL) { printf("%s does not exist\n", filename); return 0; } int index = 0; // 读取文件时去除换行符 while(fgets(arr[index], MAX_SIZE, fp) != NULL) { // 去掉fgets读取的换行符 arr[index][strcspn(arr[index], "\n")] = '\0'; index++; } fclose(fp); // 关闭文件,避免资源泄漏 char username[100]; printf("Username: "); scanf("%s", username); char password[100]; printf("Password: "); scanf("%s", password); for (int i = 0 ; i<index ; i++) { char *user_token = strtok(arr[i], " "); if (user_token == NULL) continue; char *pwd_token = strtok(NULL, " "); if (pwd_token == NULL) continue; char *amount_token = strtok(NULL, " "); if (amount_token == NULL) continue; // 同时校验用户名和密码 if (strcmp(user_token, username) == 0 && strcmp(pwd_token, password) == 0) { printf("The amount is: %s\n", amount_token); return 0; } } printf("Username/Password mismatch!!!\n"); return 0; }
修复说明
- 用
strcspn(arr[index], "\n")定位换行符位置,将其替换为字符串结束符\0,去除fgets读取的换行符。 - 简化
strtok的使用逻辑:每一行固定分割出用户名、密码、金额三个字段,直接依次获取后对比,避免嵌套循环的逻辑混乱。 - 修正密码校验的对比对象,改为
strcmp(pwd_token, password)。 - 添加
fclose(fp)关闭文件,避免资源泄漏。
内容的提问来源于stack exchange,提问作者Devon Whitaker
相关产品推荐
相关产品推荐

