c语言中的安培错误与生存期

c语言中的安培错误与生存期,c,pointers,compiler-warnings,local-variables,C,Pointers,Compiler Warnings,Local Variables,正如我们所知,局部变量具有局部范围和生存期。考虑下面的代码: int* abc() { int m; return(&m); } void main() { int* p=abc(); *p=32; } int* abc() { int m;

正如我们所知,局部变量具有局部范围和生存期。考虑下面的代码:

      int* abc()
      {
            int m;
            return(&m);
       }
       void main()
       {
             int* p=abc();
             *p=32;
        }
      int* abc()
      {
           int m;
           return(&m);
           int p=9;
       }
       void main()
       {
           int* p=abc();
           *p=32;
       }
这给了我一个警告,函数返回局部变量的地址。 我认为这是合理的: 一旦abc完成,本地可验证m将被解除分配。因此,我们在主函数中解除对无效内存位置的引用

但是,请考虑下面的代码:

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

在这里,我得到了同样的警告。但我猜m在返回时仍将保留其生命。发生了什么事?请解释一下错误。我的理由不对吗?

int m应该是局部可见的。您应该将其创建为int*m并直接返回

一旦遇到return关键字,控件就会传回调用者,被调用的函数就会超出范围。因此,所有局部变量都会从堆栈中弹出。因此,第二个示例中的最后一个语句是无关紧要的,警告是正确的。首先,请注意int p=9;将永远无法访问,因此您的两个版本在功能上是相同的。程序将为m分配内存并返回该内存的地址;return语句下面的任何代码都是不可检查的


其次,在函数返回后,局部变量m实际上并没有取消分配。相反,程序会考虑内存可用空间。该空间可能会被用于其他用途,也可能会保持未使用状态并永远保持其原有价值。由于您无法保证一旦abc函数退出,内存会发生什么变化,因此您不应尝试以任何方式访问或修改它。

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

int* abc()
{
           static int m;
           m = 42;
           return &m;
}
返回后的任何内容都是永远不会执行的死分支。

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

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

从语言标准来看:

6.2.4物品的储存期限 ... 2对象的生存期是程序执行期间存储被删除的部分 保证为它保留。一个对象存在,有一个固定地址,25并保留 它在整个生命周期中的最后一个存储值。26如果对象在其 在生命周期中,行为未定义。指针的值在以下情况下变得不确定: 它指向的对象已到达其生命周期的末尾。 25术语“恒定地址”表示指向在可能不同的位置构造的对象的两个指针 时间将是平等的。在两次不同的执行相同操作期间,地址可能不同 程序 26对于易失性对象,最后一个存储不需要在程序中显式显示。
我的。基本上,您正在做一些语言定义明确称为未定义行为的事情,这意味着编译器可以自由地以任何方式处理这种情况。它可以发出编译器正在执行的诊断,它可以在不发出诊断的情况下翻译代码,它可以在此时停止翻译,等等。

为什么你认为在第二个版本中m应该保持活动状态?你的两个代码片段之间没有区别。@Krizz肯定有区别:在第二个版本中,abc包含一个称为p的局部变量的无法访问的定义,而在第一个版本中,它没有。只是没有相关的区别。请阅读并学习如何接受答案。然后将这些知识应用到这个问题和前面的问题上。你对第二个代码片段的期望是非常奇怪的,并且是基于关于C如何工作的非常错误但不确定的假设。为了帮助我们,您必须详细解释为什么您认为添加完全不相关的int p=9;欢迎来到Stack Overflow,并感谢您发布如此详尽和解释充分的答案!