C语言中输入字符串超出char数组大小为何能正常读取?
为什么长度为10的char数组用scanf输入超长字符串后strlen输出33?
先看你的代码:
#include <stdio.h> #include <string.h> int main(void) { char user[] = { [0 ... 9 ] = '\0' }; // 初始化长度为10的char数组,所有元素默认值为'\0' printf("Enter your name >> "); // 标准输出:Enter your name >> scanf("%[^\n]c", user); // 标准输入:`aldjflajdflajdflajfdlajfdlajfd` 注:输入字符串长度大于10 printf("%zu\n", strlen(user)); // 输出33 return 0; }
问题原因拆解:
scanf的无边界写入
你使用的%[^\n]c格式符存在致命问题:它会读取输入中所有直到换行符的字符,完全不检查目标数组的容量。你的user数组只有10个字节的空间,但输入的33个字符会直接越过数组边界,写入到数组后面的内存区域——这就是典型的缓冲区溢出。strlen的计数逻辑
strlen的工作机制是从传入的地址(这里是user数组的起始地址)开始,逐个字符遍历,直到找到第一个'\0'为止,统计中间的字符数量。因为你输入的33个字符覆盖了数组原本的10个'\0',而且数组后面的内存区域里刚好没有被覆盖到的'\0',直到第33个字符之后才遇到第一个'\0',所以strlen返回33。未定义行为的风险
这种越界写入属于C语言中的未定义行为——标准没有规定程序会如何表现,不同环境下可能出现不同结果:比如输出不同的数字、程序直接崩溃,甚至被恶意利用执行非法代码。你这次输出33只是刚好内存布局导致的巧合结果。
正确的处理方式:
- 用scanf时限制读取长度:把格式符改成
%9[^\n],这样最多读取9个字符,留一个位置自动添加'\0',避免溢出:scanf("%9[^\n]", user); - 更推荐使用
fgets,它天生支持指定最大读取长度,安全性更高:fgets(user, sizeof(user), stdin); // 可选:去掉fgets读取到的换行符 user[strcspn(user, "\n")] = '\0';
内容的提问来源于stack exchange,提问作者Pritam
相关产品推荐
相关产品推荐

