为什么我的printfs给出不同的值?

时间:2012-09-06 12:12:39

标签: c scope printf

  

可能重复:
  Can a local variable's memory be accessed outside its scope?

第二个printf有什么问题?

#include<stdio.h>
int* fun() {
   int a =10;
   return &a;
}
int main() {
   int *a;
   a = fun();
   printf("%d",*a);
   printf("%d",*a);
   return 0;
}

我已经返回了局部变量的地址并将其传递给printf。它第一次正确打印为“10”,但第二次显示垃圾值。

如果最初a是指向10地址的悬空指针,为什么不是第二次?

任何人都能解释一下吗?

我甚至在第一次调用printf之前尝试调用其他函数,但我仍然得到相同的输出。

在BeniBela的回答之后我试了这个......

#include<stdio.h>
int* fun()
{
int a =10;
return &a;
}
void fun2(int d)
{
int a,b,c;
}

int main()
{
int *a,b;
a = fun();
fun2(5);
printf("%d",*a);
printf("%d",*a);
return 0;
}

仍然是相同的输出.. :(

4 个答案:

答案 0 :(得分:9)

printf没有问题,您的代码有未定义的行为
您返回函数本地变量的地址,变量的 生命周期 仅限于范围({})函数,一旦函数的范围结束,变量就越长。标准不再需要变量存在。

所以你的指针引用了一些不存在的东西(虽然它可能)。简单地说,它是未定义的行为,你是编译器的怜悯,它可能会向您显示任何行为并且不提供相同的解释。

答案 1 :(得分:3)

实际发生的是:

所有局部变量都存储在堆栈中。

  1. 在调用fun之前,堆栈只包含*变量main,如:|int *a = undefined||

  2. 当调用fun时,fun的参数(即none),main的地址和fun的局部变量被添加到堆栈中:|int *a = undefined| return to main | int a = 10 ||(还有帧指针但是没关系)

  3. 乐趣返回后,堆栈为|int *a = 2nd next stack var|| return to main | int a = 10 |。最后2个堆栈变量无效,但它们仍然存在。

  4. 当第一个printf被调用printf的参数时(按逆序* a然后是“%d”),在* a之后再次添加printf的返回地址和局部变量并覆盖旧值:
    它首先变为|int *a = 2nd next stack var| int a = 10 || int a = 10 |
    然后|int *a = 2nd next stack var| int a = 10 | "%d" |
    然后|int *a = 2nd next stack var| int a = 10 | "%d" | return to main ||
    最后|int *a = 2nd next stack var| int a = 10 | "%d" | return to main | local vars of printf ||

  5. 当第二个printf被调用时,* a仍然指向第二个bin,但是那个现在包含“%d”,这将显示为一个奇怪的数字
  6. [编辑:]

    fun2不会覆盖堆栈上的10,因为gcc会在堆栈上保留空容器,其中放置了被调用函数的参数。所以它不是我上面写的|int *a = 2nd next stack var| return to main | int a = 10 |,而更像是|int *a = 4th next stack var | empty | empty | return to main | int a = 10 | 当调用fun2时,它变为|int *a = 4th next stack var | empty | 5 | return to main | int a = 10 |,而10仍未被覆盖。

    函数中的int *a,b,c无关紧要,因为它们没有赋值。

    使用gdb,您可以查看实际堆栈(它向后增长):

    开心之前:

    0xffffd454:    0x080496f0    0xffffd488    0x080484eb    0x00000001
                     noise     (framepointer)  address      noise/empty bin     
                                               in main
    

    有趣之后,在fun2及其论点之前:

    0xffffd454:    0x0000000a    0xffffd488    0x08048441    0x00000001
                     a         (framepointer)   address     noise/empty bin     
                                                in main
    

    在fun2之后:

    0xffffd454:    0x0000000a    0xffffd488    0x08048451    0x00000005
    
                     a         (framepointer)   address       argument     
                                                in main       for fun2
    

答案 2 :(得分:1)

编译时注意警告:

yourfile.c: In function ‘fun’:
yourfile.c:6:14: warning: function returns address of local variable [enabled by default]

这是范围问题,变量“a”在“fun”函数中有一个本地scope。当您尝试从main(在其范围之外)访问该局部变量的地址时,它的含义不再有效。 如果你想解决这个问题,你可以将变量设为全局变量(但是更改名称!)然后你会看到代码按预期工作:

int b;

int* fun() 
{  
  b = 10;
  return &b; 
} 

int main() 
{ 
  int *a; 
  a = fun(); 
  printf("%d",*a); 
  printf("%d",*a);
  getc(stdin);
  return 0; 
}

输出:

> 1010

答案 3 :(得分:0)

返回在函数内创建的对象的地址,因此在函数终止后可能不再有效。改为创建一个指针!