解释输出

时间:2011-07-19 14:32:40

标签: c

#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);
}

运行代码后的输出:

3
-1073855580

我知道a [2]对于fun()来说是本地的,但是为什么值被改变了相同的指针?

5 个答案:

答案 0 :(得分:7)

变量a确实很有趣。从该函数返回时,将弹出堆栈。记忆本身保持不变(暂时)。当您第一次取消引用时,内存就是您期望的内存。由于取消引用在调用printf之前发生了,所以没有任何不好的事情发生。当printf执行时,它会修改堆栈并清除值。第二次通过你看到第一次通过printf发生的任何价值。

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

  • 取消引用r(第一次通过,这就应该是它)
  • 将值推送到堆栈上(注意这是复制值)(可能会消除a)
  • 将其他参数推送到堆栈(订单通常是从右到左,IIRC)(可能会消灭a)
  • 为堆栈上的返回值分配空间(可能会消除a)
  • 致电printf
  • 将本地printf变量推送到堆栈上(可能会消除a)
  • 做你的尝试
  • 从功能返回

如果您将int a[2];更改为static int a[2];,则可以缓解此问题。

答案 1 :(得分:2)

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

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

详细地说,fun的返回仅仅因为没有覆盖它而保留了该特定位置。

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

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

当然,这只是可能的解释。实际上,任何都可能发生,因为您编码的内容存在未定义的行为。完成后,所有投注均已关闭。

答案 2 :(得分:1)

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

编译器现在可以自由地将任何想要的东西粘贴到那些被解开的位置。因此,有可能出于各种原因跳过a的第一个位置。也许现在它代表了一个未初始化的变量。也许是为了另一个变量的内存对齐。简单的回答是,通过从函数返回指向局部变量的指针,然后取消引用该指针,您将调用未定义的行为并且可能发生任何,包括demons flying out of your nose。< / p>

答案 3 :(得分:1)

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

$ gcc -Wall yourProgram.c 

它将产生一个警告,说。

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

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

答案 4 :(得分:0)

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