【问题标题】:How does C manage stack with pointers?C如何使用指针管理堆栈?
【发布时间】:2020-06-04 23:35:12
【问题描述】:

所以我搞砸了动态内存和指针,我想知道当涉及到指向局部变量的指针时,C 是如何管理堆栈的。 我想出了这个简单的功能:

int* dummy(){
  int test = 4;
  int *t2;
  t2 = &test;
  return t2;
}

此函数初始化一个指针,并将一个 int 初始化为局部变量(不应在我的函数之外访问,因为一旦我退出函数,堆栈状态将恢复)。但是,我将指针作为函数的结果返回。 我可以取回指针并打印我的局部变量的值:

#include <stdio.h>

int main(void){
   int* p = dummy();
// some other calls to other functions to mess up the bellow stack, 
// where my local variable "test" was supposed to be landing
   printf("%d\n", *p); // printing the value of "test" (which is 4)
}

结果

$ ./a.out
4

为什么打印出正确的结果?指针不是从其他状态指向堆栈中的变量吗?我很困惑。

如果内存在没有动态分配的情况下停留在某个地方,它会停留在哪里?是不是永远失去了? (没有办法“释放”它)

在 cmets 之后编辑

行为未定义。为警告添加编译器选项(例如pedantic)将打印一条警告,指出我正在返回一个指向局部变量的指针,并且可执行文件会出现错误。

原因是当程序存在函数时dummy的堆栈状态会丢失,因此不能保证局部变量的值,因为它们是......局部的。

【问题讨论】:

  • 虽然技术上未定义行为,但它只是“碰巧起作用”,因为堆栈地址仍然存在。在dummyprintf 之间调用其他函数,堆栈内存会被其他函数的局部变量值覆盖。
  • 尝试在通话后添加int x, y, z = 1, 2, 3
  • @selbie 这就是我一直在尝试的。可能不足以覆盖变量。
  • 基本上,int test = 4; 将 4 放在某个内存位置或寄存器或其他东西中。然后你从函数返回,编译器会忘记它。然后你访问那个位置,它仍然包含值 4 是巧合,因为编译器没有看到任何理由花费时钟周期来删除它。该值仍然存在,这完全是巧合——如果你在运行函数和使用返回值之间运行了其他代码,任何事情都可能发生(计算机甚至可能着火——我是认真的)
  • @selbie 用 -O2 编译确实给我打印了一个警告,告诉我我正在返回一个指向局部变量的指针,并使整个事情变得错误。这就是我一直在寻找的,非常感谢。

标签: c pointers memory


【解决方案1】:

未定义行为的可能结果之一是 - 按预期行事。

一旦dummy 返回,test 就不再存在 - 逻辑上 说。但是,它占用的堆栈区域可能不会立即被覆盖,因此该值可能会在该(虚拟)位置保留一段时间。

指针无效 - 我们使用它来访问该对象生命周期之外的对象 - 所以行为肯定是未定义的。但这并不意味着该值必须不是4

【讨论】:

    【解决方案2】:

    未定义的行为是未定义的。该程序无法打印任何价值,即在任何意义上“正确”。让您感到困惑的是,您认为该程序可以打印一些“正确”的值,因此您想知道为什么它会打印“正确”的值。

    问题完全在于您错误地理解某些值比其他值更“正确”。对于这个程序,所有值都同样“正确”。

    【讨论】:

    • 好吧,它会打印我的测试变量的值。这就是我所说的“正确”。
    • 仅仅因为它做了某事绝对不会影响它是否“正确”。未定义的行为意味着它可能不会一直有效。由于您的代码具有未定义的行为,因此根据定义它是不正确的。
    【解决方案3】:

    我想知道当涉及到指向局部变量的指针时,C 是如何管理堆栈的

    它没有。 C 甚至不需要堆栈。您正在做的是未定义的行为,这意味着 C 标准不会对编译器施加任何要求。

    因此,您的问题的答案与 C 标准无关。它可以归结为“通常如何处理”。但是当你做这样的事情时,正如我所提到的,未定义的行为。所以这种代码很可能一打开编译器优化就搞砸了。

    可以对行为做出有根据的猜测,但您无法保证。

    实际上,这有点像看着你邻居的窗户,惊讶地发现它是你多年来的同一个邻居。以完全相同的方式,您无法保证您的邻居没有突然搬家,也没有其他人搬进来。好吧,就您而言,这发生了。你的邻居还没有搬出去。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-24
      • 2021-12-26
      • 2013-01-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多