为何一个函数中的数组与另一函数创建的数组始终分配相同内存地址?
为何一个函数中的数组与另一函数创建的数组始终分配相同的内存地址?
无论在other_function()中创建多少个数组,最后创建的hello数组的内存地址始终与mkarray1中的arr数组相同,使得printf("%d %d %d\n", ptr[0], ptr[1], ptr[2])输出1、2、3。请解释该现象的原因,谢谢。
#include <stdlib.h> #include <limits.h> #include <stdio.h> #include <errno.h> int *mkarray1(int a, int b, int c) { int arr[3] = {a, b, c}; int *p = arr; printf("the address of arr in mkarray1 is %p\n", &arr); // 原代码笔误:&arr[12]应为&arr[2],已修正 printf("the address of arr[0] is %p, arr[1] is %p, arr[2] is %p\n", &arr[0], &arr[1], &arr[2]); return p; } void other_function(){ int arr[3] = {70, 80, 90}; printf("the address of arr in other_function is %p\n", &arr); int notarr[3] = {40, 50, 60}; printf("the address of notarr in other_function is %p\n", ¬arr); int hello[3] = {1, 2, 3}; printf("the address of hello in other_function is %p\n", &hello); } int main() { int *ptr = mkarray1(10, 20, 30); // 原代码笔误:&arr[12]应为&arr[2],已修正 printf("the address of ptr[0] is %p, ptr[1] is %p, ptr[2] is %p\n", &ptr[0], &ptr[1], &ptr[2]); printf("the address of ptr in main is %p\n", &ptr); other_function(); printf("the address of ptr after other_function is %p\n", &ptr); printf("%d %d %d\n", ptr[0], ptr[1], ptr[2]); }
原因解析
1. 栈内存的复用特性
你看到的地址重复是栈内存复用的直接结果:
- C语言中,函数内的局部变量(如
mkarray1的arr、other_function的hello)都存储在程序的栈空间中。栈是后进先出的内存区域,函数调用时会为局部变量分配栈帧,函数返回后,该栈帧会被标记为可复用,但不会立即清除内存数据。 - 当
mkarray1执行完毕返回后,它占用的栈帧被释放;后续调用other_function时,由于hello数组的大小和arr完全一致,且栈的分配方向是从高地址向低地址延伸,hello刚好占用了之前arr释放的那块栈内存,因此地址完全相同。
2. 返回局部变量指针的未定义行为
mkarray1返回局部数组arr的指针是严重的未定义行为:
- 局部变量在函数返回时就已销毁,对应的栈内存不再属于该变量。后续通过这个指针访问内存的操作,结果完全不可预测——可能刚好读取到后续函数复用该内存的值,也可能输出垃圾数据,甚至导致程序崩溃。
- 你的例子中刚好
other_function的hello复用了这块内存,所以才看到输出1、2、3,但这只是巧合,并非必然结果。
3. 栈帧的分配逻辑
对于mkarray1和other_function这种没有嵌套调用、局部变量布局相似的函数,它们的局部变量在栈中的位置会高度重合。当函数返回后栈帧被释放,新函数的局部变量会优先复用这些已释放的空间,这也是地址相同的核心原因。
正确的解决方式
如果需要在函数间传递数组,推荐以下两种做法:
- 堆内存分配:使用
malloc在堆上分配内存,用完后用free释放,示例:int *mkarray1(int a, int b, int c) { int *arr = malloc(3 * sizeof(int)); if (arr == NULL) { // 处理内存分配失败 return NULL; } arr[0] = a; arr[1] = b; arr[2] = c; return arr; } // 在main中使用后要调用free(ptr); - 调用者提供数组:让调用者传入数组作为参数,函数直接修改该数组:
void mkarray1(int *arr, int a, int b, int c) { arr[0] = a; arr[1] = b; arr[2] = c; } // main中调用:int arr[3]; mkarray1(arr, 10,20,30);
内容的提问来源于stack exchange,提问作者grass
相关产品推荐
相关产品推荐

