You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 06:15:03