如何限制终端输入字符串长度以避免缓冲区溢出?
解决字符串输入缓冲区溢出问题
问题根源分析
你当前代码存在两个致命问题:
scanf("%5s", str1)中,%5s会读取最多5个字符,再自动追加终止符\0,但str1的数组大小仅为5(MAX_STRG/2=5),直接导致数组越界溢出。正确的格式符应该是%4s,限制读取字符数为数组大小减1,预留终止符的位置。- 你用
sizeof(str1)+sizeof(str2)判断输入长度,这是数组的固定内存大小,和实际输入的字符串长度无关,所以这个检查完全无效。
两种可行的解决方案
方案1:改进scanf用法,实时检测输入溢出
#include<stdio.h> #include<stdlib.h> #include<string.h> #define MAX_STRG 10 #define SUB_STR_LEN (MAX_STRG/2) // 每个子串数组大小为5 int main() { char str1[SUB_STR_LEN] = "One", str2[SUB_STR_LEN] = "Two"; int check = 1; char leftover; while(check == 1) { // 读取第一个字符串,限制最多4个字符 printf("请输入第一个字符串(最多4个字符)...\n"); scanf("%4s", str1); // 清空输入缓冲区的剩余字符,同时判断是否有溢出 if ((leftover = getchar()) != '\n' && leftover != EOF) { printf("错误:第一个字符串超出长度限制!\n"); // 彻底清空缓冲区 while(getchar() != '\n' && getchar() != EOF); continue; } // 读取第二个字符串,同样处理 printf("请输入第二个字符串(最多4个字符)...\n"); scanf("%4s", str2); if ((leftover = getchar()) != '\n' && leftover != EOF) { printf("错误:第二个字符串超出长度限制!\n"); while(getchar() != '\n' && getchar() != EOF); continue; } // 检查总长度是否符合要求 if(strlen(str1) + strlen(str2) <= MAX_STRG) { check = 0; } else { printf("错误:两个字符串总长度超过%d字符!\n", MAX_STRG); } } printf("\n最终输入结果:\n字符串1:%s\t字符串2:%s\n总长度:%zu\n", str1, str2, strlen(str1)+strlen(str2)); return 0; }
方案2:用fgets实现更安全的读取
fgets支持指定最大读取长度,会自动保留终止符,还能读取带空格的整行输入,安全性比scanf更高:
#include<stdio.h> #include<stdlib.h> #include<string.h> #define MAX_STRG 10 #define SUB_STR_LEN (MAX_STRG/2) int main() { char str1[SUB_STR_LEN] = "One", str2[SUB_STR_LEN] = "Two"; int check = 1; while(check == 1) { printf("请输入第一个字符串(最多4个字符)...\n"); fgets(str1, SUB_STR_LEN, stdin); // 去掉fgets读取到的换行符(如果存在) str1[strcspn(str1, "\n")] = '\0'; // 检测输入是否溢出:若读取的字符串长度等于数组大小-1,且缓冲区还有剩余字符 if(strlen(str1) == SUB_STR_LEN - 1 && getchar() != '\n') { printf("错误:第一个字符串超出长度限制!\n"); // 清空剩余字符 while(getchar() != '\n' && getchar() != EOF); continue; } printf("请输入第二个字符串(最多4个字符)...\n"); fgets(str2, SUB_STR_LEN, stdin); str2[strcspn(str2, "\n")] = '\0'; if(strlen(str2) == SUB_STR_LEN - 1 && getchar() != '\n') { printf("错误:第二个字符串超出长度限制!\n"); while(getchar() != '\n' && getchar() != EOF); continue; } if(strlen(str1) + strlen(str2) <= MAX_STRG) { check = 0; } else { printf("错误:两个字符串总长度超过%d字符!\n", MAX_STRG); } } printf("\n最终输入结果:\n字符串1:%s\t字符串2:%s\n总长度:%zu\n", str1, str2, strlen(str1)+strlen(str2)); return 0; }
核心注意事项
- 用
scanf时,%Ns中的N必须是数组大小-1,预留终止符\0的位置。 - 无论用哪种读取方式,都要清空输入缓冲区的剩余字符,避免影响下一次输入。
- 检测溢出的关键逻辑:若读取的字符串长度达到数组最大可用长度(数组大小-1),且输入缓冲区中还有未读取的非换行字符,说明输入超出限制。
内容的提问来源于stack exchange,提问作者sake
相关产品推荐
相关产品推荐

