为什么局部变量没有超出范围?

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( ) 调用一次。

请比较以下两段代码

  1. 以下代码输出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;
}
  1. 以下代码输出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 放在同一位置。因此,堆栈中的相同地址 0x7ffeadacc084x 的新值 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.

地址的地址