C语言输入用户名密码触发Run-Time Check Failure #2栈损坏异常求助
解决栈溢出引发的Run-Time Check Failure #2异常
问题背景
编写了读取用户名和密码的代码,要求输入长度不超过最大值,超出则重新提示。但进入循环后,程序执行到return 0时抛出异常:Run-Time Check Failure #2 - Stack around the variable 'username_input' was corrupted. 尝试过scanf_s和fgets仍未解决。
原代码如下:
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #define MAXNAME 30 int main() { char username_input[MAXNAME]; char password_input[MAXNAME]; username_input[MAXNAME - 1] = '\0'; password_input[MAXNAME - 1] = '\0'; printf("Please enter your username: "); while (scanf("%s", username_input) != 1 || strlen(username_input) > MAXNAME) { printf("Improper input.\nPlease enter your username: "); } printf("Please enter your password: "); while (scanf("%s", password_input) != 1 || strlen(password_input) > MAXNAME) { printf("Improper input.\nPlease enter your password: "); } return 0; }
问题分析
- 无限制的
scanf("%s")导致栈溢出:当输入字符串长度超过MAXNAME-1(即29)时,scanf会直接向数组写入超出其容量的数据,覆盖栈上的其他内存区域,破坏栈结构,最终触发栈损坏检测异常。 - 错误的长度判断条件:数组
username_input的大小是MAXNAME(30),最多只能存储29个有效字符+1个终止符\0,原判断条件strlen(username_input) > MAXNAME不符合数组实际存储能力。 - 输入缓冲区残留问题:输入超长时,超出部分会留在输入缓冲区中,后续
scanf会直接读取这些残留数据,导致循环逻辑混乱。
解决方案
修改代码,限制scanf读取长度,修正判断条件,并处理输入缓冲区残留数据:
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #define MAXNAME 30 #define MAX_INPUT_LEN (MAXNAME - 1) int main() { char username_input[MAXNAME]; char password_input[MAXNAME]; int ret; int c; printf("Please enter your username: "); while (1) { // 限制读取字符数为MAX_INPUT_LEN,避免溢出 ret = scanf("%29s", username_input); if (ret != 1 || strlen(username_input) > MAX_INPUT_LEN) { printf("Improper input.\nPlease enter your username: "); // 清空输入缓冲区残留数据 while ((c = getchar()) != '\n' && c != EOF); continue; } break; } printf("Please enter your password: "); while (1) { ret = scanf("%29s", password_input); if (ret != 1 || strlen(password_input) > MAX_INPUT_LEN) { printf("Improper input.\nPlease enter your password: "); while ((c = getchar()) != '\n' && c != EOF); continue; } break; } return 0; }
关键修改说明
- 限制
scanf读取长度:使用%29s格式,确保最多读取29个字符,数组末尾自动添加\0,不会超出数组容量。 - 修正长度判断逻辑:检查长度是否超过
MAX_INPUT_LEN(即29),匹配数组实际存储能力。 - 清空输入缓冲区:输入无效时,用
getchar()循环读取缓冲区残留字符直到换行或EOF,避免后续读取错误数据。
若偏好使用fgets,可按以下方式实现(需处理读取到的换行符):
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #define MAXNAME 30 #define MAX_INPUT_LEN (MAXNAME - 1) int main() { char username_input[MAXNAME]; char password_input[MAXNAME]; char *newline; printf("Please enter your username: "); while (1) { if (fgets(username_input, MAXNAME, stdin) == NULL) { printf("Input error.\nPlease enter your username: "); continue; } // 去除fgets读取到的换行符 newline = strchr(username_input, '\n'); if (newline != NULL) { *newline = '\0'; } else { // 输入超长时清空缓冲区 int c; while ((c = getchar()) != '\n' && c != EOF); } if (strlen(username_input) > MAX_INPUT_LEN) { printf("Improper input.\nPlease enter your username: "); continue; } break; } printf("Please enter your password: "); while (1) { if (fgets(password_input, MAXNAME, stdin) == NULL) { printf("Input error.\nPlease enter your password: "); continue; } newline = strchr(password_input, '\n'); if (newline != NULL) { *newline = '\0'; } else { int c; while ((c = getchar()) != '\n' && c != EOF); } if (strlen(password_input) > MAX_INPUT_LEN) { printf("Improper input.\nPlease enter your password: "); continue; } break; } return 0; }
内容的提问来源于stack exchange,提问作者Toasty
相关产品推荐
相关产品推荐

