scanf输入超出malloc分配内存为何不崩溃?如何修复?
内存越界未崩溃的原因及修复方案
示例代码
#include <stdio.h> #include <string.h> #include <stdlib.h> int main() { int len; char* str_input; printf("Enter len of str: "); scanf("%d", &len); str_input = (char*) malloc(len * sizeof(char)); printf("Enter str. & to end: "); scanf("%s", str_input); printf("%s", str_input); }
问题
当输入长度为1,分配1字节内存后,输入长度超过1的字符串(如"hello"),程序仍能完整打印该字符串。为何未因内存不足崩溃?该如何修复此问题?
为什么没崩溃?
这是典型的内存越界访问,没崩溃纯粹是运气使然:
- C语言本身不做内存边界检查,
malloc分配的1字节内存后面的空间,暂时仍属于当前进程的地址空间,且没有被其他关键数据(比如函数返回地址、全局变量)占用,所以写入和读取操作都没立刻触发错误。 - 这种行为属于未定义行为——不是不会崩溃,只是这次没踩到“雷区”。换个运行环境、多执行几次,或者后续代码用到被覆盖的内存时,就可能出现崩溃、数据错乱等诡异问题。
修复方案
可以从三个层面彻底解决这个问题:
- 分配内存时预留字符串结束符空间
C字符串必须以\0结尾,所以分配内存时要多留1字节空间:
str_input = (char*) malloc((len + 1) * sizeof(char));
- 限制输入长度,强制避免越界
使用scanf的格式化参数限制读取长度,最多读取len个字符(预留1个位置给\0):
scanf("%.*s", len, str_input);
或者用更安全的fgets函数,它能明确限制读取的字节数,还能避免scanf遗留的换行符问题:
// 清除scanf输入len后留下的换行符 getchar(); // 最多读取len+1个字节(含\0) fgets(str_input, len + 1, stdin); // 去掉fgets可能读取到的换行符 size_t input_len = strlen(str_input); if (input_len > 0 && str_input[input_len - 1] == '\n') { str_input[input_len - 1] = '\0'; }
- 检查内存分配是否成功
malloc可能因为系统内存不足返回NULL,必须处理这种情况,避免后续操作空指针:
if (str_input == NULL) { fprintf(stderr, "Memory allocation failed\n"); return 1; }
内容的提问来源于stack exchange,提问作者nat34
相关产品推荐
相关产品推荐

