未传递数组参数的C语言函数为何能正常运行?
为什么未传递数组的C代码能“正常”运行?
我编写了一段C语言代码,用getArray函数输入数组内容,DisplayArray函数打印数组内容,但并未将数组传递给DisplayArray函数,可代码却能正常运行。请问这一现象的原因是什么?
程序代码
void getArray(); void DisplayArray(); int main(void) { getArray(); DisplayArray(); return EXIT_SUCCESS; } void getArray() { int limit, b[10]; printf("Enter the limit:"); scanf("%d", &limit); printf("Enter the values of the array:"); for (i = 0; i < limit; i++) { scanf("%d", &b[i]); } } void DisplayArray() { int i, n, array[10]; printf("The values of Array is: \n"); for (i = 0; i < n; i++) { printf("%d\t", array[i]); } }
运行输出
输入限制值:4 输入数组元素值:2 4 6 8 数组元素值为: 2 6 8
本质原因:这是未定义行为导致的巧合结果
这段代码能“正常”输出完全是运气,并非C语言的正常机制,核心是以下两个栈内存相关的巧合:
- 栈帧复用导致内存数据残留
getArray和DisplayArray都是无参数、无返回值的函数,调用时的栈帧结构高度相似。当getArray执行完毕返回后,它的栈帧会被标记为可用,但栈内存里的原始数据并不会被主动清除。紧接着调用DisplayArray时,新的栈帧刚好复用了之前getArray栈帧的内存区域:
DisplayArray里的array[10]数组,刚好和getArray里的b[10]数组在栈上的存储位置完全重叠;DisplayArray里未初始化的n变量,刚好对应getArray里limit变量的存储位置,所以意外拿到了之前输入的4。
- 未初始化变量读取垃圾值的巧合
代码里存在多处未定义行为的隐患:
getArray里的循环变量i没有声明(旧C标准允许隐式声明为int,但C99及以后属于编译错误);DisplayArray里的n和array都未初始化,它们的值是栈里的随机垃圾数据,只是刚好和getArray残留的数据匹配,才出现了“正确”的输出。
这种行为完全依赖编译器的栈布局、优化等级、运行环境,换个编译器(比如从GCC换到Clang)、开启编译优化(比如-O2)、甚至调整函数里的变量顺序,结果都会彻底改变——可能输出乱码,可能直接崩溃。
正确的写法示例
要避免这种依赖巧合的错误,应该通过参数传递数组和长度:
#include <stdio.h> #include <stdlib.h> void getArray(int array[], int *limit); void DisplayArray(const int array[], int limit); int main(void) { int arr[10]; int len; getArray(arr, &len); DisplayArray(arr, len); return EXIT_SUCCESS; } void getArray(int array[], int *limit) { int i; printf("Enter the limit:"); scanf("%d", limit); printf("Enter the values of the array:\n"); for (i = 0; i < *limit; i++) { scanf("%d", &array[i]); } } void DisplayArray(const int array[], int limit) { int i; printf("The values of Array is:\n"); for (i = 0; i < limit; i++) { printf("%d\t", array[i]); } }
内容的提问来源于stack exchange,提问作者joyalgeorgekj
相关产品推荐
相关产品推荐

