2011-07-19 156 views
0
#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 

据我所知,[2]是本地的乐趣(),但为什么值得到改变同一个指针的?

+0

任何影响堆栈的操作都可以改变输出。有时你可能**看到'printf'输出相同的值 - 这是因为编译器对你的代码进行了优化 - 但是,我们不能依赖不确定的结果。 – Stan

回答

2

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

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

详细地说,从fun返回的具体位置被保留,因为没有任何东西已经覆盖它。

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

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

当然,这只是可能的解释。实际上,任何东西都可能发生,因为你在那里编码的是未定义的行为。一旦你这样做,全部下注。

+0

因此,''funoc'在'fun'(''''''中的某些内存使代码正常工作? – 2011-07-19 14:37:18

+0

@Jack:是的,但它必须在某个地方发布。 – paxdiablo

+1

是的。如果它在'main'中('return'声明之前)是'free',那么这样可以工作吗?我对C(以及一般的编程)是一个新手,所以我倾向于潜伏并阅读很多问题和答案。 :) – 2011-07-19 14:43:37

0

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

7

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

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

  • 取消引用r(第一次通过,这是它应该是什么)
  • 推值入堆栈(注意这是使值的副本)(可擦出)上堆叠
  • 推其他参数(顺序通常是从右到左,这个)(可擦出)
  • 为堆栈上的返回值分配空间(可能会擦除)
  • 调用printf
  • 按当地的printf变量入堆栈(可消灭一)
  • 做你的唐卡从功能

  • 返回如果更改int a[2];static int a[2];这将缓解这个问题。

  • 1

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

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

    1

    当你编译你用下面的命令代码:

    $ gcc -Wall yourProgram.c 
    

    这将产生一个警告,它说。

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

    r在第一printf语句被废弃时,它作为记忆中保留了也没关系。但是,第二个printf语句会覆盖堆栈,因此我们会得到不希望的结果。