C中函数的局部变量范围

时间:2009-12-01 05:55:05

标签: c++ c scope

当我开始使用C编程时,我听说过以下情况。

尝试从外部访问,函数局部变量将导致错误(或垃圾值)。因为当我们从函数返回时堆栈被清除

但我的下面的代码示例打印的值为50.我正在使用最新的GCC编译器编译代码。

#include <stdio.h>

int * left();

int main()
{
      int *p=left();
      printf("%d\n",*p);
      return 0;
}

int * left()
{
        int i=50;
        return &i;
}

在这个问题上启发我。

我能否知道C ++中的行为?它是否类似于c ..

8 个答案:

答案 0 :(得分:12)

变量'i'在堆栈上创建,当函数'left'返回时,堆栈被清除。当我说清除时,这意味着变量'i'使用的地址被标记为可以重复使用。直到其他部分代码使用相同的地址,该值将保持不变。在你的情况下,这是一个幸运的,给你想要的结果。如果你在打电话给'左'之后再调用几个函数,我相当肯定你会得到错误的结果。

答案 1 :(得分:7)

修改它以添加对printf的第二次调用,您将从第一次看到不同的值。在启用优化的情况下编译它,您将看到另一组值。使用该值任何,并且您正在进入未定义的区域,这意味着编译器可以通过您的鼻段自由地召唤恶魔。

在我的系统上,我看到50然后0;通过优化,我看到0然后32767

如果你创建局部变量static,那么你可以返回它的地址,因为它变得像一个全局变量(但请记住它只有一个实例)。

当一个函数返回时,它在堆栈上使用的本地存储现在被程序视为“未使用”,因为堆栈不再那么高了。但通常情况下,值仍然存在,因为没有迫切需要清除它们。内存也仍然由程序拥有,因为将内存一次几个字节返回给操作系统是没有意义的。因此,对于您的具体示例,在您编译它的情况下,指向的内存仍包含值50。但是,正式地说,*p的值是不确定,并且尝试使用它会导致未定义的行为。

C语言的一个存在主义危机是,一方面它没有说明堆栈和构成运行过程的各种十六进制污泥;另一方面,有必要了解这些,以保护自己免受崩溃,缓冲区溢出和未定义的行为。请记住,你很幸运GCC会对此发出警告。

答案 2 :(得分:6)

根据C标准的行为未定义而不是垃圾值。因此,有可能,有时可能,价值将保持不变。无论如何都无法保证这一点。

这是运气/机会/事故而没有别的。不要依赖这种行为,因为回来咬你。

答案 3 :(得分:3)

看看这个修改过的例子,它清楚地显示了是否存在某些内容:

int *p=left();
// right here
printf("%d\n",*p);

您可以轻松获得损坏的堆栈。这个想法是你不拥有那个地方,其他人可以使用它!

int main()
{
    int *p=left();
    right(); // Look here!  
    printf("%d\n",*p); // prints -50 instead of 50
    return 0;
}
...
int * right()
{
    int i=-50;
    return &i;
}

答案 4 :(得分:2)

它的工作原理是意外。 调用p时,printf()指向的内存位置仍包含整数值50。 但是,在main()left()之间调用printf()内的任何函数都会覆盖它。

例如,如果您将printf()调用更改为:

,我不知道您的实施会发生什么
printf("abs(%d) = %d ???\n", *p, abs(*p));

不要这样做!

答案 5 :(得分:2)

您指的是超出其生命周期的对象(left()的范围)。这导致了未定义的行为 - 我猜你仍然得到50,因为没有任何东西覆盖了i尚未覆盖的区域。

答案 6 :(得分:2)

就C标准而言,该值未定义。

实际上,只要在引用返回值之前没有任何东西被推送到堆栈,它就可以工作,但是下次调用函数时,返回地址和新堆栈帧被推送到堆栈并可能覆盖引用的值

这不被视为可接受的编码(因为未定义的性质)。

答案 7 :(得分:1)

未定义的行为。离开i后,left()被销毁。您在p中有垃圾地址。编译器还没有通过运气销毁i