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

fscanf()返回数据异常导致C语言登录系统验证失败问题排查

C语言登录逻辑调试:始终提示账号密码错误

这是一个基于C语言实现的登录项目,以txt文件作为数据存储。创建users.txt并填入指定数据后运行代码,登录时始终提示“Login id or password is incorrect...”,authenticated值始终为0。推测问题出在登录核心逻辑的if(valid_user_id)代码块中,怀疑是fscanf()未正确读取数据导致。

登录逻辑代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void login_menu();
void title_printer(const char* title); // 补充缺失的函数声明
void dashboard_menu(users user); // 补充缺失的函数声明

typedef struct {
    char user_id[6];
    char name[50];
    char password[50];
    char email[50];
    char role[50];
} users;

/* Main function */
int main() {
    login_menu();

    return 0; // return 0 to indicate successful execution
}

void login_menu() {
    title_printer("Login page");
    FILE *users_file = fopen("users.txt", "r");

    users user;
    int authenticated = 0;
    int login_attempts = 0;

    const int max_login_attempts = 3;

    while (login_attempts < max_login_attempts) {
        int valid_user_id = 0;
        char user_id[50];
        char password[50];

        printf("Please enter your User ID (TP number or Tutor code)  down below: \n");
        scanf("%s", user_id);
        printf("Please enter your password down below: \n");
        scanf("%s", password);

        if ((user_id[0] == 'T' && user_id[1] == 'P') || (user_id[0] == 't' && user_id[1] == 'p')) {
            valid_user_id = 1;
            for (int i = 0; i < 50; i++) {
                user_id[i] = user_id[i + 2];
            }
        } else if ((user_id[0] == 'T') || (user_id[0] == 't')) {
            valid_user_id = 1;
            for (int i = 0; i < 50; i++) {
                user_id[i] = user_id[i + 1];
            }
        } else if ((user_id[0] == 'A') || (user_id[0] == 'a')) {
            valid_user_id = 1;
            for (int i = 0; i < 50; i++) {
                user_id[i] = user_id[i + 1];
            }
        }

        if (valid_user_id) {
            // use while loop to read the file line by line
            while (fscanf(users_file, "%s;%s;%s;%s;%s", user.user_id, user.name, user.password, user.email, user.role) != EOF) {
                if (strcmp(user.user_id, user_id) == 0 && strcmp(user.password, password) == 0) {
                    printf("Login successful %s (%s) !\n", user.name, user.role);
                    fclose(users_file);
                    dashboard_menu(user);
                    authenticated = 1;
                    break;
                }
            }
        }

        if (authenticated) {
            break;
        } else {
            login_attempts++;
            printf("Login id or password is incorrect, %d attempts left. Please try again.\n", (3 - login_attempts));
        }
    }

    if (!authenticated) {
        printf("Max login attempts reached. Exiting program.\n");
        exit(1);
    }

    fclose(users_file);
}

两种users.txt格式

格式1(分号分隔)

988955;John;123456;admin@edu.my;admin;
265663;Mary;123456;marry@edu.my;tutor;
009650;Peter;123456;peter@edu.my;tutor;
544654;James;123456;james@edu.my;tutor;
577001;Johnny;123456;john@edu.my;tutor;
683357;David;123456;david@edu.my;tutor;

格式2(空格分隔)

988955 John 123456 admin@edu.my admin 
265663 Mary 123456 marry@edu.my tutor 
009650 Peter 123456 peter@edu.my tutor 
544654 James 123456 james@edu.my tutor 
577001 Johnny 123456 john@edu.my tutor 
683357 David 123456 david@edu.my tutor 

问题根源与修复方案

1. 文件指针未重置

第一次登录尝试时,fscanf会将文件指针移动到文件末尾,后续循环中fscanf直接返回EOF,无法再读取任何数据。
修复:在if(valid_user_id)代码块开头添加rewind(users_file);,每次读取文件前将指针重置到文件开头。

2. fscanf格式串不匹配(针对分号分隔的格式1)

当前格式串"%s;%s;%s;%s;%s"中,%s以空白符作为分隔符,不会识别分号,导致第一个字段会读取到988955;John这类包含分号的内容,完全不符合预期。同时每行末尾的多余分号会导致最后一个字段读取异常。
修复:

  • 修改fscanf格式串为:
    fscanf(users_file, "%[^;];%[^;];%[^;];%[^;];%[^\n]\n", user.user_id, user.name, user.password, user.email, user.role)
    
    其中%[^;]表示读取直到遇到分号为止的字符串,%[^\n]表示读取到换行符为止,确保最后一个字段正确读取。
  • 去掉users.txt每行末尾的分号,调整后每行格式为:988955;John;123456;admin@edu.my;admin

3. 用户ID处理的数组越界风险

处理用户ID时的for (int i = 0; i < 50; i++)会超出原字符串的长度范围,导致内存访问异常。
修复:用memmove替换循环,只复制有效长度的内容:

// 以TP开头的情况为例
size_t id_len = strlen(user_id);
if (id_len >= 2) {
    memmove(user_id, user_id + 2, id_len - 1); // 包含字符串终止符
}

4. 未检查文件打开结果

fopen后没有判断文件是否成功打开,若文件不存在或权限不足会直接导致程序崩溃。
修复:添加文件打开检查:

FILE *users_file = fopen("users.txt", "r");
if (!users_file) {
    perror("Failed to open users.txt");
    exit(1);
}

内容的提问来源于stack exchange,提问作者James Wong

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 21:25:02