-4

众所周知,局部变量具有局部作用域和生命周期。考虑以下代码:

      int* abc()
      {
            int m;
            return(&m);
       }
       void main()
       {
             int* p=abc();
             *p=32;
        }

这给了我一个警告,一个函数返回一个局部变量的地址。我认为这是合理的:一旦 abc() 完成,本地可验证 m 就会被释放。所以我们在主函数中取消引用一个无效的内存位置。

但是,请考虑以下代码:

      int* abc()
      {
           int m;
           return(&m);
           int p=9;
       }
       void main()
       {
           int* p=abc();
           *p=32;
       }

在这里,我得到了同样的警告。但我猜 m 返回时仍然会保留它的生命周期。怎么了?请解释错误。我的理由错了吗?

4

5 回答 5

10

首先,请注意int p=9;永远不会达到,因此您的两个版本在功能上是相同的。程序将为该内存分配内存m并返回该内存的地址;return 语句下面的任何代码都是无法访问的。

其次,局部变量m在函数返回后实际上并没有被释放。相反,程序会考虑内存可用空间。该空间可能用于其他目的,或者它可能保持未使用状态并永远保持其旧值。因为您无法保证函数退出后内存会发生什么,所以abc()您不应尝试以任何方式访问或修改它。

于 2012-05-14T21:33:20.543 回答
8

一旦遇到 return 关键字,控制权就会返回给调用者,并且被调用的函数超出范围。因此,所有局部变量都从堆栈中弹出。因此,第二个示例中的最后一条语句无关紧要,警告是合理的

于 2012-05-14T21:31:44.397 回答
3

从逻辑上讲m从函数返回时不再存在,一旦函数退出,对它的任何引用都是无效的。

物理上,图片有点复杂。占用的内存单元m肯定仍然存在,如果您在其他任何东西有机会写入它们之前访问这些单元,它们将包含在函数中写入它们的值,因此在正确的情况下可能您可以在返回后读取存储的m内容。 不要依赖这种行为是可重复的;这是一个编码错误pabc

从语言标准(C99):

6.2.4 对象的存储持续时间
...
2 对象的生命周期是程序执行期间保证为其保留存储的部分。一个对象存在,具有一个常量地址,25)并在其整个生命周期中保留其最后存储的值。26) 如果对象在其生命周期之外被引用,则行为未定义。当指针指向的对象到达其生命周期的末尾时,指针的值变得不确定。
25) 术语“恒定地址”意味着在可能不同时间构造的两个指向对象的指针将比较相等。在同一程序的两次不同执行期间,地址可能不同。

26) 在 volatile 对象的情况下,最后的存储不需要在程序中明确显示。

强调我的。基本上,您正在做一些语言定义明确称为未定义行为的事情,这意味着编译器可以自由地以任何它想要的方式处理这种情况。它可以发出诊断(你的编译器正在做的),它可以在发出诊断的情况下翻译代码,它可以在那个时候停止翻译,等等。

于 2012-05-14T22:21:28.040 回答
2

退出函数时,使 m 仍然有效内存(与代码保持最大相似性)的唯一方法是在它前面加上 static 关键字

int* abc()
{
           static int m;
           m = 42;
           return &m;
}

返回后的任何内容都是永远不会执行的“死分支”。

于 2012-05-14T21:37:42.587 回答
-1

int m should be locally visible. You should create it as int* m and return it directly.

于 2012-05-14T21:28:03.340 回答