字符串内存分配疑问:分配10字符空间输入11字符为何结果正常?
关于C语言字符串内存越界的疑问与解答
问题描述
我知道给字符串分配内存时,因为要存储NULL终止符,得分配n+1的空间,但我有个疑问:如果只分配10个字符的内存空间,却输入11个字符的字符串会发生什么?我运行了测试代码,结果居然和分配n+1空间时的表现一致,代码如下:
#include <stdlib.h> #include <stdio.h> // 注:原代码遗漏该头文件,printf/scanf需依赖它 int main(){ int n; char *str; printf("How long is your string? "); scanf("%d", &n); str = malloc(n+1); if (str == NULL) printf("Uh oh.\n"); scanf("%s", str); printf("Your string is: %s\n", str); }
解答
首先明确:这种输入长度超过分配内存的行为属于缓冲区溢出,是C语言里的未定义行为,绝非正常程序逻辑。
为什么测试时表现和正常情况一致?
这纯粹是运气好——你写入的额外字符刚好覆盖了当前内存块后方的“空闲”区域,暂时没破坏程序的关键数据(比如函数返回地址、其他变量的值),所以程序还能正常执行。但这种情况完全随机,换个编译环境、操作系统,甚至同一程序多运行几次,结果可能天差地别:- 轻则程序直接崩溃(段错误);
- 重则破坏其他变量的值,导致程序逻辑混乱,输出错误结果;
- 极端情况下,恶意输入可利用该漏洞执行任意代码,引发安全风险。
为什么
scanf("%s")存在风险?
这个函数不会检查目标缓冲区的大小,不管你分配了多少空间,它都会持续读取输入直到遇到空白字符,一旦输入长度超过缓冲区,必然引发溢出。正确的做法是限制读取长度,比如用scanf("%10s", str)(这里的10是缓冲区可容纳的最大字符数,不含NULL终止符),或者使用更安全的fgets读取字符串,后续再处理换行符。补充说明:原代码还有一个问题——未包含
<stdio.h>头文件,printf和scanf属于该头文件中的函数,虽然部分编译器能通过编译,但这不符合C标准规范,同样会导致未定义行为。
内容的提问来源于stack exchange,提问作者Affectionate Mango
相关产品推荐
相关产品推荐

