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

C语言登录验证:输入用户名与文件存储内容匹配失败问题排查

问题原因分析

以下是导致用户名匹配失败的核心问题:

  • 换行符干扰:create()函数用fprintf(fptr, "%s\n", username)写入用户名时,会在末尾添加换行符\n;而usernamef()里用scanf("%s", username)读取输入时,不会包含换行符。strcmp对比时,输入的用户名(如"alex")和文件中读取的内容(如"alex\n")自然不相等。
  • strcmp语法错误:代码中写的是if(0 = strcmp(username, theString)),这是赋值操作而非比较,应该写成if(strcmp(username, theString) == 0)。
  • 缓冲区长度不匹配+溢出风险:usernamef()里定义的username[5]和theString[5]长度太小,而create()允许用户名最多9个字符(数组username[10]),会导致读取时截断;同时scanf("%s")未限制长度,存在缓冲区溢出风险。
  • 文件操作不规范:usernamef()中fopen后未检查文件是否成功打开,读取完成后也未关闭文件;全局FILE *fptr容易引发资源冲突。
  • passwordf逻辑顺序错误:先执行strcmp(password, passwordn)再读取密码,此时passwordn是未初始化的垃圾值,逻辑完全颠倒。
修正后的完整代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 提前声明函数
void usernamef();
void passwordf(const char *correct_pwd);
void shade();
void create();

int main() {
    char a;
    printf("Welcome! Do you have an account ?\n");
    printf("\tType \"y\" for yes or type \"n\" for no.\n");
    // 吃掉输入残留的换行符,避免读取y/n时出错
    getchar();
    scanf("%c", &a);
    if(a == 'y' || a == 'Y'){ 
        usernamef(); 
    } else { 
        create(); 
    }
    return 0;
}

void usernamef() {
    // 匹配create函数的长度,留足'\0'和处理换行的空间
    char username[10];
    char theString[11]; // 多1位存储换行符
    FILE *fptr = fopen("accounts.txt", "r");
    if(!fptr){
        printf("Failed to open accounts file!\n");
        return;
    }
    printf("Enter your username\n");
    // 限制输入长度,避免缓冲区溢出
    scanf("%9s", username);
    
    // 逐行读取文件内容
    while(fgets(theString, sizeof(theString), fptr)) {
        // 去掉换行符(如果存在)
        size_t len = strlen(theString);
        if(len > 0 && theString[len-1] == '\n'){
            theString[len-1] = '\0';
        }
        // 正确的strcmp比较逻辑
        if(strcmp(username, theString) == 0) {
            printf("Username matched!\n");
            // 读取对应密码(创建时用户名和密码各占一行)
            fgets(theString, sizeof(theString), fptr);
            len = strlen(theString);
            if(len > 0 && theString[len-1] == '\n'){
                theString[len-1] = '\0';
            }
            passwordf(theString);
            fclose(fptr);
            return;
        }
        // 跳过密码行,继续查找下一个用户名
        fgets(theString, sizeof(theString), fptr);
    }
    printf("Username not found!\n");
    fclose(fptr);
}

void passwordf(const char *correct_pwd) {
    char passwordn[10];
    printf("Enter your password\n");
    scanf("%9s", passwordn);
    if(strcmp(correct_pwd, passwordn) == 0){
        shade();
    } else {
        printf("Password incorrect, try again or type r to create an account\n");
    }
}

void shade() {
    printf("Welcome back! Hope you're having a good day :)\n");
}

void create(){
    char username[10];
    char password[10];
    printf("Create an account to continue\n");
    printf("Make sure to follow these instructions\n");
    printf("\t1. Username and password must be shorter than 10 characters.\n");
    printf("\t2. No spaces, use a single word.\n");
    printf("\t3. No special characters.\n");
    printf("Now enter the username: ");
    scanf("%9s", username);
    FILE *fptr = fopen("accounts.txt", "a");
    if(!fptr){
        printf("Failed to open accounts file!\n");
        return;
    }
    fprintf(fptr, "%s\n", username);
    fclose(fptr);
    
    printf("Enter the password: ");
    scanf("%9s", password);
    fptr = fopen("accounts.txt", "a");
    if(!fptr){
        printf("Failed to open accounts file!\n");
        return;
    }
    fprintf(fptr, "%s\n", password);
    fclose(fptr);
    shade();
}
关键修改说明
  • 处理换行符:读取文件行后,检查末尾是否有\n,如果有就替换为\0,确保和输入的用户名格式一致。
  • 修正strcmp语法:把赋值操作改为比较操作,保证逻辑正确。
  • 缓冲区安全:定义足够长度的数组,scanf用%9s限制输入长度,避免缓冲区溢出。
  • 规范文件操作:使用局部FILE指针,每次打开后检查是否成功,用完及时关闭,避免资源泄漏。
  • 调整passwordf逻辑:先读取用户输入的密码,再和正确密码对比,同时传递正确密码作为参数,修正逻辑顺序。
  • 修复输入残留问题:main里用getchar()吃掉输入残留的换行符,避免读取y/n时出错。

内容的提问来源于stack exchange,提问作者Alaa Younsi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 09:25:54