繁体   English   中英

解释 output

[英]Explain the output

#include<stdio.h>

int * fun(int a1,int b)
{
    int a[2];
    a[0]=a1;
    a[1]=b;
    return a;
}
int main()
{
    int *r=fun(3,5);
    printf("%d\n",*r);
    printf("%d\n",*r);
}

Output 运行代码后:

3
-1073855580

我知道 a[2] 是 fun() 本地的,但为什么值会改变同一个指针?

变量 a 确实很有趣。 当您从该 function 返回时,堆栈被弹出。 memory 本身保持不变(目前)。 当您第一次取消引用 r 时,memory 就是您所期望的。 由于取消引用是在调用 printf之前发生的,因此不会发生任何不好的事情。 当 printf 执行时,它会修改堆栈并且值被擦除。 第二次通过时,您会看到第一次通过 printf 时发生的任何值。

“正常”调用约定的事件顺序(我知道,我知道 - 没有这样的事情):

  • 解引用r (第一次通过,应该是这个)
  • 将值压入堆栈(注意这是复制值)(可能会清除 a)
  • 将其他参数推入堆栈(顺序通常是从右到左,IIRC)(可能会清除 a)
  • 在堆栈上为返回值分配空间(可能会清除 a)
  • 致电 printf
  • 将本地 printf 变量推入堆栈(可能会清除 a)
  • 做你的事情
  • 从 function 返回

如果你改变int a[2]; static int a[2]; 这将缓解问题。

因为r指向堆栈上可能被 function 调用覆盖的位置。

在这种情况下,这是对printf本身的第一次调用,它正在更改该位置。

详细地说,从fun的返回具有保留该特定位置的原因仅仅是因为尚未覆盖它。

然后评估*r (作为 3)并传递给printf以进行打印。 printf的实际调用会更改该位置的内容(因为它使用 memory 作为自己的堆栈帧),但该值已经在此时提取,因此它是安全的。

在随后的调用中, *r具有不同的值,由第一次调用更改。 这就是为什么在这种情况下有所不同。

当然,这只是可能的解释。 实际上,任何事情都可能发生,因为您在那里编写的代码是未定义的行为。 一旦你这样做了,所有的赌注都没有了。

当您使用以下命令编译代码时:

$ gcc -Wall yourProgram.c 

它会产生一个警告,上面写着。

In function ‘fun’:
warning: function returns address of local variable

在第一个r语句中取消引用printf时,可以保留 memory。 但是,第二个printf语句覆盖了堆栈,因此我们得到了不希望的结果。

正如您所提到的, a[2]fun()本地的; 这意味着它是在fun()中的代码开始执行之前在堆栈上创建的。 fun退出时,堆栈被弹出,这意味着它被展开,因此堆栈指针指向它在fun开始执行之前的位置。

编译器现在可以自由地将任何它想要的东西粘贴到那些未展开的位置。 因此,由于各种原因,可能会跳过a的第一个位置。 也许它现在代表一个未初始化的变量。 也许是另一个变量的 memory alignment。 简单的答案是,通过从 function 返回指向局部变量的指针,然后取消引用该指针,您正在调用未定义的行为并且任何事情都可能发生,包括恶魔飞出你的鼻子

因为 printf 正在使用堆栈位置,并在打印第一个值后更改它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM