请考虑以下代码:
int *foo (int x) {
int a[2];
a[0] = x;
a[1] = x + 1;
return a;
}
…
int *p1 = foo(2);
int *p2 = foo(3);
在此代码段结束时,以下各项的值是什么? (给出答案)
p1[0] = 3
p1[1] = 4
p2[0] = 3
p2[1] = 4
由于在堆栈上分配了a,因此在调用返回时内存不会保持分配状态,并且可能会被其他内容重用。在这种情况下,由于foo(3)在foo(2)之后立即在相同的调用深度处调用(即它们使用相同的堆栈空间),因此它们都将返回相同的指针 - 即p1等于p。
我不明白上面的解释。它到底意味着什么?为什么我们对p2和p1有完全相同的值?我知道你不能在C中返回指向局部变量的指针。但我不明白为什么p2和p1具有相同的值....
答案 0 :(得分:7)
这是未定义的行为,您的程序也可能崩溃。
局部变量存储在堆栈中,其生命周期仅在函数范围内。
在您的情况下,程序下次重用相同的位置,因此您的值将被覆盖,但它并不总是相同,并且永远不会返回局部变量的地址。
答案 1 :(得分:7)
使用指向其范围之外的自动存储变量(作用于函数的变量)的指针是未定义的,这正是从不执行此操作的原因,并且从不依赖于它的行为。
但是,如果你想剥离编译器/机器/操作系统上的封面,原因是自动存储恰好在两个函数调用的同一地址分配。
一个例子......
#include "stdio.h"
int* foo(int x) {
int a[2];
printf("&a[0] = %p\n", &a[0]);
printf("&a[1] = %p\n\n", &a[1]);
a[0] = x;
a[1] = x + 1;
return a;
}
int main(int argc, char* argv[]) {
printf("foo(2)\n");
int* p1 = foo(2);
printf("foo(3)\n");
int* p2 = foo(3);
printf("p1[0] = %i\n", p1[0]);
printf("p1[1] = %i\n\n", p1[1]);
printf("p2[0] = %i\n", p2[0]);
printf("p2[1] = %i\n", p2[1]);
return 0;
}
...输出
foo(2)
&a[0] = 0x7fff4dd0f054
&a[1] = 0x7fff4dd0f058
foo(3)
&a[0] = 0x7fff4dd0f054
&a[1] = 0x7fff4dd0f058
p1[0] = 3
p1[1] = 4
p2[0] = 3
p2[1] = 4
因此,&a[0]
和&a[1]
在foo(2)
和foo(3)
中都具有相同的地址。
当你输入一个函数时,它通常会创建一个堆栈帧(通过递减x86上的堆栈指针)。这会在堆栈上为自动存储变量分配内存。离开函数时,堆栈帧被销毁(堆栈指针返回其原始值)。因此,如果再次输入相同的函数,通常会对堆栈帧使用相同的内存(堆栈指针递减到与上次调用函数相同的值)。
答案 2 :(得分:1)
每个函数调用内存在堆栈上为函数变量分配,堆栈指针向前移动。函数执行后,由于效率原因,不会擦除堆栈内存,并且所有数据都保留在那里。因此,如果您第二次调用相同的函数并保留一些未初始化的变量,您可以在上一次函数调用中找到一些有趣的值。 C中的每个数组都存储为一大块内存,通过移位指针找到元素。 至于你的问题:foo返回指向整数的指针,这实际上是一个内存地址。 在foo(2)之后,p1将存储一些地址,例如0x00。将带有索引的大括号[]添加到整数指针意味着将整数大小*索引添加到内存地址。我们可以向指针添加任何随机索引并尝试从那里获取数据。如果我们幸运并且内存可读 - 我们将有一些垃圾数据。第一次调用函数后
p1 points to a stack array and values are:
p1[0] == 2;
p2[1] == 3;
p1 == 0x00; (for example)
执行函数并返回堆栈指针。下一个函数调用foo(3)在堆栈上获得相同的内存块。第二次调用使用新值重写变量。第二次通话后,我们得到:
p2[0] == 3;
p2[1] == 4;
p2 == 0x00; (same memory address)
问题是p1指向堆栈上的相同内存地址。如果你调用任何其他函数 - p1和p2都将再次更改,因为堆栈的相同区域将再次被重用。
答案 3 :(得分:0)
在你的函数foo()中你有一个局部变量,你正试图返回局部变量的地址。不要你的编译器抛出以下错误:
warning: function returns address of local variable
如果你必须得到你发布的答案,那么你需要使数组int a[2]
全局。
否则我们在这里有一个未定义的行为。
答案 4 :(得分:0)
从函数调用返回时,堆栈展开将释放为该数组分配的内存。那个记忆不再可用。行为未定义。