C语言登录系统strcmp仅返回±1、首字符相同即登录故障求助
问题根因
strcmp无法返回0的核心原因
fgets()读取文件内容时会保留行末尾的换行符\n,但你用scanf("%s")读取用户输入时,%s会自动截断空白字符,不会包含换行符,导致从文件读出的账号/密码末尾多了一个\n,和用户输入的字符串永远不相等,自然无法返回0。- 文件路径格式错误:C语言字符串中反斜杠需要转义,
"C:\Users\..."要改成"C:\\Users\\...",否则fopen大概率打开失败,你没有判断fopen的返回值,一旦打开失败,fgets读到的是乱码,无法正常匹配。 - 你打开了两次相同的
login.txt文件,完全多余,打开一次依次读两行(第一行用户名、第二行密码)即可。
首字符一致就通过校验的核心原因
- 校验逻辑完全不符合
strcmp的标准定义:strcmp仅在两个字符串完全相等时返回0,第一个字符串更大返回正数、更小返回负数,返回的正负值不一定是1或-1。你代码里写if(o == 1)才判定密码正确,while(i != 1)作为用户名循环退出条件,逻辑完全错误,只要strcmp返回值不是1就会跳出循环,自然出现首字符一致就通过的问题。 - 用户名校验失败时递归调用
LogIN(),导致逻辑混乱,前一次的校验结果被覆盖。 - 密码部分连续调用两次
fgets(password, 50, fpointerp),虽然刚好能跳过用户名行读到密码,但写法极不规范,容易出问题。
修复代码示例
#include <stdio.h> #include <string.h> #include <stdlib.h> void MainMeni(); void PisanjeDnevnika(); // 移除fgets读取的换行符 void trim_newline(char *str) { char *p = strchr(str, '\n'); if (p) *p = '\0'; } void LogIN(){ char username[50]; char password[500]; // 修正路径转义,只打开一次文件 FILE *fp = fopen("C:\\Users\\marmun\\Desktop\\dnevnik\\login.txt", "r"); if (!fp) { printf("配置文件打开失败!"); exit(1); } fgets(username, 50, fp); trim_newline(username); fgets(password, 500, fp); trim_newline(password); fclose(fp); char Username[50]; char Password[500]; int i; // 用户名校验 while(1) { printf("Input user\n"); scanf("%s", Username); i = strcmp(username, Username); if(i == 0){ printf("Login success!\n"); break; } else { printf("Login unsuccessful!\n"); } system("cls"); } int o; // 密码校验 while(1){ printf("Input password\n"); scanf("%s", Password); o = strcmp(password, Password); if(o == 0){ printf("Password correct!\n"); break; } else { printf("Password incorrect!\n"); } } system("cls"); char Izbor; // 吃掉scanf残留的换行符 getchar(); printf("Login successful!"); printf("\n\tChoose 1 out of 3 options!"); printf("\t1.Meni\n\t2.Writing diary.\n\t3.Exit"); scanf("%c", &Izbor); while(Izbor != '1' && Izbor != '2' && Izbor != '3') { printf("输入不合法,请重新输入:"); // 清空缓冲区 while(getchar() != '\n'); scanf("%c", &Izbor); } switch(Izbor){ case '1': MainMeni(); break; case '2': PisanjeDnevnika(); break; case '3': exit(0); break; } }
其他注意事项
switch每个分支要加break,否则会贯穿执行后面的分支- 菜单的循环条件原来写的是
||逻辑,永远为真,要改成&&才会在输入合法值时退出 - 不要用递归做重试逻辑,会导致栈溢出,用循环重试即可
内容的提问来源于stack exchange,提问作者Luka
相关产品推荐
相关产品推荐

