C语言中引用字符数组引发栈溢出的原因及性质疑问
C语言中引用字符数组引发栈溢出的原因及性质疑问
先给你明确结论:这绝对是真实的运行时错误,不是IDE的虚假警告。栈溢出检测是编译器/操作系统的内存保护机制触发的,说明你的代码已经破坏了栈内存的完整性——这次碰巧输出了正确结果纯属运气,属于C语言里的“未定义行为”,下次运行可能直接崩溃、输出乱码,甚至引发更严重的问题。
下面给你拆解代码里的两个核心问题:
1. memset调用的致命错误
你在函数里写了:
memset(arr, 0, sizeof(arr));
这里的arr是函数参数里的char*指针——在C语言中,当你把数组名传递给函数时,它会自动退化为指针类型。所以sizeof(arr)计算的是指针本身的大小(64位系统是8字节,32位是4字节),而不是原字符数组str的实际大小。
原数组str定义为char str[] = "1 2";,它的实际大小是4字节(包含字符'1'、' '、'2'和末尾的\0)。当你用memset往这个数组里写入超过4字节的内容时,就会覆盖栈上数组后面的其他数据(比如函数的返回地址、其他局部变量),直接触发栈溢出检测机制。
2. 数组空间不足导致越界写入
原数组str只有4字节的空间,但处理后的结果是"10 20",加上末尾的\0一共需要6字节的空间。你用strcat把这些内容拼接到arr时,会超出原数组的边界,继续往栈上的其他内存区域写数据,这同样会破坏栈的结构,也是触发错误的原因之一。
修正方案
要解决这个问题,核心是让函数知道目标数组的大小,或者确保数组有足够空间容纳结果。这里给你一个安全的修改版本:
修改后的函数
#include <string.h> #include <stdio.h> #include <stdlib.h> void read_and_mul(char *arr, size_t arr_size, int scale) { int num_arr[2]; char *ch = strtok(arr, " "); num_arr[0] = scale * atoi(ch); ch = strtok(NULL, " "); num_arr[1] = scale * atoi(ch); // 用arr_size限制memset的范围,避免越界 memset(arr, 0, arr_size); // 用snprintf替代sprintf+strcat,自动处理缓冲区大小,防止溢出 snprintf(arr, arr_size, "%d %d", num_arr[0], num_arr[1]); }
修改后的main函数
int main(int argc, char *argv[]) { // 定义足够大的数组,确保能容纳处理后的结果 char str[20] = "1 2"; // 直接传数组名即可,无需强制转换为(char*)&str read_and_mul(str, sizeof(str), 10); printf("string after call: %s\n", str); return 0; }
额外提醒几个细节:
- 不要用
(char *)&str这种多余的写法,数组名本身会退化为指向首元素的指针,直接传str就行 - 尽量用
snprintf代替sprintf,前者可以指定缓冲区大小,是更安全的字符串格式化方式 strtok会修改原字符串(把分隔符替换为\0),如果需要保留原字符串,记得先做拷贝
备注:内容来源于stack exchange,提问作者HeapUnderStop
相关产品推荐
相关产品推荐

