内存分配堆栈

时间:2015-01-15 12:32:27

标签: c++ c pointers memory-management dangling-pointer

在堆栈中,为main保留了内存,我们称之为main函数的堆栈帧。

当我们调用Add函数时,内存保留在堆栈顶部。在Add函数堆栈帧中,ab是本地指针,c是一个计算总和的整数,然后我们返回引用。 cAdd函数的局部变量。

现在当Add函数执行完成时,堆栈中的内存空间也被释放,所以当我们尝试使用指针main访问p中的这个地址时,我们是什么试图访问基本上是一个解除分配的空间。编译器发出警告,但为什么它仍然正确打印值5?

答案可能是机器没有释放内存空间,因为它没有必要,因为没有更多的功能。但是如果我们编写另一个函数Hello那么它肯定应该释放调用堆栈中Add函数的空间,但程序仍会打印

Yay     5

是否因为在堆中我们需要在释放它之后指定一个指向null的指针,否则我们仍然可以访问它?有类似的东西吗?

/* void Hello()
   {
     printf("Yay");
   } */

int* Add(int *a,int *b)
{
  int c=*a+*b;
  return &c;
}

int main()
{
  int a=1,b=4;
  int *p=Add(&a,&b);
  // Hello();
  printf("\t%d",*p);
  return 0;
}

5 个答案:

答案 0 :(得分:8)

假设c是本地int变量,在函数调用后访问cundefined-behavior并且可能会打印预期结果,或者可能会发生意外情况。

虽然C没有强制要求,但通常是使用堆栈实现的。出于性能原因,当函数返回时,它会使堆栈区域保持不变。这就是您看到值51+4的原因。但你永远不要指望这一点。


当您使用第二个函数时,行为仍然未定义,因此您可以获得任何输出。实际上,如果在第二个函数中定义另一个变量并使用它,输出可能会改变。

+----------------+
|  c = 42        |
|''''''''''''''''|     +----------------+
|                |     |                |
.  ADD FUNCTION  .     . HELLO FUNCTION .
|                |     |                |
+----------------+     +----------------+
|  b = 4         |     |  b = 4         |
|''''''''''''''''|     |''''''''''''''''|
|  a = 1         |     |  a = 1         |
|''''''''''''''''|     |''''''''''''''''|
|                |     |                |
.  MAIN FUNCTION .     .  MAIN FUNCTION .
|                |     |                |
+----------------+     +----------------+

在上图中,我尝试直观地表示当您在Add函数和Hello函数内时堆栈的堆叠外观。您可以看到Hello没有搞乱c函数中为Add保留的堆栈内存。

您可以通过将Hello函数重写为

来验证这一点
void Hello()
{
  int i = 42;
  printf("Yay - %d\n", i);
}

可以在42中打印main

答案 1 :(得分:1)

TL; DR回答,这是未定义的行为。您不能推理上述执行的任何输出。如果最终打印您的手机号码或邮政编码,请不要感到惊讶。 : - )

在作用域到期后,堆栈位置会发生什么,取决于环境。如果不需要,为c分配的堆栈空间可能不会被重用,因此您会看到假定正确的输出,但仍然 未定义。有一天,在不同的环境中,你可能会看到不同的答案。

Mr. Mothit Jain' answer对此进行了非常详细的解释。

答案 2 :(得分:1)

为了完全理解这一点,我建议您学习处理器的程序集,并查看代码的编译方式。此时我认为如果我说从函数返回不会调用任何内存释放函数可以帮助它,它只是调整寄存器,因为在Add和print之间你没有做任何会改变“deallocated”堆栈上的值的事情,你得到了这个号码。尝试调用一个返回... pfft i dunno 77之间的函数(但请将其保存到局部变量!),然后打印出不同的结果。尽管如此,要学习组装,成为一名合适的程序员。

答案 3 :(得分:0)

Hello函数不会在堆栈上放置任何新内容,因为它没有自动变量。因此,先前由c占用的内存位置仍未更改。更改Hello以便修改内存,然后更改p处的值。

void Hello(void)
{
    //This will overwrite the memory previously containing '5' with '3`, the number
    //of characters output by the printf() function.
    int grub = printf("Yay");
}

答案 4 :(得分:0)

我认为这是因为当我运行以下程序时你没有在Hello函数中定义“堆栈变量”:

#include <stdio.h>

void Hello()
{
  int tt = 100;
  int tt1 = 5000;
  printf("Yay");
}

int* Add(int *a,int *b)
{
  int c=*a+*b;
  return &c;
}

int main()
{
  int a=1,b=4;
  int *p=Add(&a,&b);
  Hello();
  printf("\t%d",*p);
  return 0;
}

它在我的Linux中打印 5000 而在我的Mac中打印 1 ,无论如何我认为它们都是意想不到的值。