局部变量在堆栈中分配。当您从 main() 调用 fun() 时,堆栈显示为:
+---------------+ <---- Stack pointer
| local var x |
+---------------+ <---- Address of 'x'
| Return addr |
| in main() |
+---------------+
|Local vars of |
| main() |
+---------------+
| ... |
+---------------+
当你回到main()时,局部变量、返回地址和参数从堆栈中弹出。但是堆栈没有被清除(顺便说一下,它会消耗太多的CPU!)。所以,只有堆栈指针移动:
+---------------+
| local var x |
+---------------+ <---- Address of 'x'
| Return addr |
| in main() |
+---------------+ <---- Stack pointer moved with the pops
|Local vars of |
| main() |
+---------------+
| ... |
+---------------+
堆栈指针上方的所有内容都被认为是无效的,即使它没有被清除。所以,这就是为什么你有幸在 main() 函数中获得了x 的值。
但是假设你在 fun() 之后调用了另一个函数:
#include<stdio.h>
#include<string.h>
int *p = NULL;
void fun2()
{
int var = 18;
int var2 = 43;
printf("fun2() called, var@%p=%d, var2@%p=%d\n", &var, var, &var2, var2);
}
int *fun()
{
int x = 5;
p= &x;
return p;
}
// Driver Code
int main(int argc, char *argv[])
{
int *px;
px = fun();
printf("x@%p=%d\n", px, *px);
if (argc != 1) {
fun2();
}
printf("x@%p=%d\n", px, *px);
return 0;
}
当程序没有调用fun2()时,它的行为和你的一样,但我添加了x地址的显示:
$ gcc try.c -o try
$ ./try
x@0x7ffd5beb5f04=5
当程序传递任何参数时,我们在 fun() 之后调用 fun2() 并在调用 fun2 之前和之后显示 x ():
$ ./try any_param
x@0x7ffeadacc084=5
fun2() called, var@0x7ffeadacc080=18, var2@0x7ffeadacc084=43
x@0x7ffeadacc084=43
我们可以看到在调用fun2()之后x的值变成了43,因为fun2()中的局部变量var2 fun() 运行时已与x 放在同一位置。因此,堆栈中的相同地址0x7ffeadacc084,当然还有x 的新值43,这实际上是var2 的值。
下面是调用fun2()后栈的样子(_fun()之前的数据已经被fun2()的数据覆盖了):
+---------------+
|local var var |
+---------------+ <---- Address of 'var' = 0x7ffeadacc080
|local var var2 |
+---------------+ <---- Address of 'var2' = 0x7ffeadacc084
| Return addr |
| in main() |
+---------------+ <---- Stack pointer moved with the pops
|Local vars of |
| main() |
+---------------+
| ... |
+---------------+
PS:堆栈从高地址向低地址增长。因此,var 的地址低于var2 的地址。