为什么局部变量没有超出范围?
Why isn't the local variable going out of scope?
x
是局部变量,在执行 fun()
后应该超出范围
结束了。
它的地址可通过返回的指针和全局指针 p
获得,后者指向不再有效的内容。但是,打印的输出仍然是 5
.
为什么?
#include <stdio.h>
int *p = NULL;
int *fun() {
int x = 5;
p = &x;
return p;
}
// Driver Code
int main() {
printf("%d", *(fun()));
return 0;
}
超出范围。
仍然访问它是无效的并导致未定义的行为。
仅仅因为您碰巧从那里读取了一个“可识别的”值并不意味着它没有超出范围。
任何东西,包括但不限于用局部变量调用另一个函数might/will改变你在那里读到的值。然而,这并不意味着只要你不做那些事情,你就可以 use/read/write.
我不知道编译器的实现细节,但我猜这是因为保存 x 的堆栈 space 仍然没有被其他一些变量擦除,因为你只有这个函数 fun( ) 调用一次。
请比较以下两段代码
- 以下代码输出5\n4\n
在此代码中,每次 printf
调用都会将函数结果刷新到屏幕。同样,存放x的栈space仍然没有被其他一些变量擦除,所以可以看到打印出来的变量值
#include<stdio.h>
int *p = NULL;
int *fun(int y)
{
int x = y;
p= &x;
return p;
}
// Driver Code
int main()
{
printf("%d\n", *(fun(5)));
printf("%d\n", *(fun(4)));
return 0;
}
- 以下代码输出4\n168558721\n
在这段代码中,您可以将第 15 行更改为先打印 *r
。你仍然会得到 4。你永远不会得到 5。当从第 14 行到第 15 行的翻译指令被执行时,指针 q 和指针 r 必须指向相同的 space。因为我们调用的是同一个函数,所以第13行和第14行的栈帧应该有相同的结构,所以x分配在同一个地址下。
#include<stdio.h>
int *p = NULL;
int *fun(int y)
{
int x = y;
p= &x;
return p;
}
// Driver Code
int main()
{
int *q = fun(5); // line 13
int *r = fun(4); // line 14
printf("%d\n", *q); // line 15
printf("%d\n", *r);
return 0;
}
局部变量分配在栈中。当您从 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(),显示x
在调用 fun2():
之前和之后
$ ./try any_param
x@0x7ffeadacc084=5
fun2() called, var@0x7ffeadacc080=18, var2@0x7ffeadacc084=43
x@0x7ffeadacc084=43
我们可以看到调用fun2()后x
的值变成了43,因为,var2
中的局部变量[当 fun() 为 运行 时,=45=]fun2() 已与 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
.
地址的地址
x
是局部变量,在执行 fun()
后应该超出范围
结束了。
它的地址可通过返回的指针和全局指针 p
获得,后者指向不再有效的内容。但是,打印的输出仍然是 5
.
为什么?
#include <stdio.h>
int *p = NULL;
int *fun() {
int x = 5;
p = &x;
return p;
}
// Driver Code
int main() {
printf("%d", *(fun()));
return 0;
}
超出范围。
仍然访问它是无效的并导致未定义的行为。
仅仅因为您碰巧从那里读取了一个“可识别的”值并不意味着它没有超出范围。
任何东西,包括但不限于用局部变量调用另一个函数might/will改变你在那里读到的值。然而,这并不意味着只要你不做那些事情,你就可以 use/read/write.
我不知道编译器的实现细节,但我猜这是因为保存 x 的堆栈 space 仍然没有被其他一些变量擦除,因为你只有这个函数 fun( ) 调用一次。
请比较以下两段代码
- 以下代码输出5\n4\n
在此代码中,每次 printf
调用都会将函数结果刷新到屏幕。同样,存放x的栈space仍然没有被其他一些变量擦除,所以可以看到打印出来的变量值
#include<stdio.h>
int *p = NULL;
int *fun(int y)
{
int x = y;
p= &x;
return p;
}
// Driver Code
int main()
{
printf("%d\n", *(fun(5)));
printf("%d\n", *(fun(4)));
return 0;
}
- 以下代码输出4\n168558721\n
在这段代码中,您可以将第 15 行更改为先打印 *r
。你仍然会得到 4。你永远不会得到 5。当从第 14 行到第 15 行的翻译指令被执行时,指针 q 和指针 r 必须指向相同的 space。因为我们调用的是同一个函数,所以第13行和第14行的栈帧应该有相同的结构,所以x分配在同一个地址下。
#include<stdio.h>
int *p = NULL;
int *fun(int y)
{
int x = y;
p= &x;
return p;
}
// Driver Code
int main()
{
int *q = fun(5); // line 13
int *r = fun(4); // line 14
printf("%d\n", *q); // line 15
printf("%d\n", *r);
return 0;
}
局部变量分配在栈中。当您从 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(),显示x
在调用 fun2():
$ ./try any_param
x@0x7ffeadacc084=5
fun2() called, var@0x7ffeadacc080=18, var2@0x7ffeadacc084=43
x@0x7ffeadacc084=43
我们可以看到调用fun2()后x
的值变成了43,因为,var2
中的局部变量[当 fun() 为 运行 时,=45=]fun2() 已与 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
.