C语言读取txt文件字符串实现登录校验异常排查
C语言登录校验功能异常修复
核心问题成因
现有代码存在6处逻辑错误,直接导致校验失败、输出乱码:
- 缓冲区长度定义错误:使用
strlen(usuario)/strlen(contrasenia)作为读取缓冲区长度与fgets的读取长度参数,既没有为字符串结束符\0预留空间,也没有考虑fgets会读取行尾换行符的特性,直接造成缓冲区溢出、字符串截断,你看到的单字符'd'、乱码拼接内容就是溢出的典型表现。 - 文件遍历逻辑完全失效:在遍历文件的
while(!feof)循环内第一行就执行fseek(docInicioSesion, 0, SEEK_SET)重置文件指针到开头,循环会无限执行,永远无法逐行遍历所有账号密码对,最终只会读到截断的异常内容。 - 匹配判断逻辑写反:
strcmp函数在两个字符串完全相等时返回值为0,现有判断条件strcmp(usuario, stringUser) && strcmp(contrasenia, stringPassword)的含义是「用户名和密码都不匹配时判定为登录成功」,逻辑完全颠倒。 - 换行符未做清理:
fgets读取文件行时会将行尾的换行符\n存入字符串,而scanf读取的用户输入不带换行符,即便账号密码完全正确,也会因为多了换行符导致比对失败。 - 循环条件错误:do-while循环判断用了
||逻辑,即便是登录成功(ingreso=1),只要尝试次数小于3就会继续循环,无法正常跳出登录流程。 - 环境兼容问题:Replit运行环境为Linux,原代码用的
system("cls")(Windows清屏)、system("pause")(Windows暂停)、system("exit")命令均无法正常执行。
修复后可直接运行的代码
1. iniciarSesion.h
#define maxIntentos 3 void iniciarSesion();
2. iniciarSesion.c
适配标准C语法,兼容Replit Linux环境:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include "iniciarSesion.h" // 辅助函数:去除fgets读取到的行尾换行符 void trimNewline(char* str) { int len = strlen(str); if (len > 0 && str[len-1] == '\n') { str[len-1] = '\0'; } } void iniciarSesion() { FILE *docInicioSesion; // 缓冲区开固定足够长度,避免溢出 char usuario[40], contrasenia[30]; char fileUser[40], filePass[30]; int tries = 0, ingreso = 0; docInicioSesion = fopen("saveData.txt", "r"); if (docInicioSesion == NULL) { printf("\nError al abrir el archivo\n"); return; } do { // 兼容Linux/Windows清屏 #ifdef _WIN32 system("cls"); #else system("clear"); #endif printf("\n\t\t INICIO DE SESION\n\n"); printf("Usuario: "); scanf("%39s", usuario); // 限制输入长度避免溢出 printf("Contrasena: "); scanf("%29s", contrasenia); // 清空输入缓冲区残留的换行符 while(getchar() != '\n'); // 每次校验前把文件指针重置到开头 fseek(docInicioSesion, 0, SEEK_SET); ingreso = 0; // 逐组读取用户名+密码,直到文件末尾 while (fgets(fileUser, sizeof(fileUser), docInicioSesion) != NULL) { trimNewline(fileUser); // 用户名读完读对应密码,判断是否读到文件末尾 if (fgets(filePass, sizeof(filePass), docInicioSesion) == NULL) { break; } trimNewline(filePass); // 两个字符串都相等才判定匹配成功 if (strcmp(usuario, fileUser) == 0 && strcmp(contrasenia, filePass) == 0) { ingreso = 1; break; } } if (ingreso == 1) { #ifdef _WIN32 system("cls"); #else system("clear"); #endif printf("\nAcceso Concedido!\n"); printf("Bienvenido/a %s!\n", usuario); printf("Presione Enter para continuar..."); getchar(); break; } else { printf("Acceso denegado\nLa clave y/o usuario son incorrectos...\n"); tries++; if (tries < maxIntentos) { printf("Intentos restantes: %d\nPresione Enter para continuar...", maxIntentos - tries); getchar(); } } } while(tries < maxIntentos && ingreso != 1); if (tries == maxIntentos) { printf("Ha sobrepasado el limite maximo de intentos.\n"); printf("Presione Enter para salir..."); getchar(); fclose(docInicioSesion); exit(1); } fclose(docInicioSesion); }
修复说明
- 所有缓冲区使用固定长度,
scanf/fgets均限制最大读取长度,从根源避免缓冲区溢出 - 修正文件遍历逻辑:每次用户输入后重置文件指针,逐组读取用户名、密码对,读到文件末尾自动结束
- 新增换行符清理函数,统一处理文件读入内容的行尾换行,保证比对逻辑一致
- 修正
strcmp判断条件,仅当用户名、密码完全匹配时判定登录成功 - 增加跨平台适配,自动识别Windows/Linux环境调用对应清屏命令,用标准输入函数实现暂停逻辑,兼容Replit环境
- 修正循环判断逻辑,登录成功直接跳出流程,尝试次数耗尽直接退出
- 补充空指针判断,文件打开失败直接返回,避免野指针操作
内容的提问来源于stack exchange,提问作者DaSe
相关产品推荐
相关产品推荐

