5

在堆栈中,我们为函数main调用堆栈帧保留了内存。main

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

现在,当Add函数执行完成时,堆栈中的内存空间也被释放,所以当我们尝试在mainwith 指针中访问这个地址时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;
}
4

5 回答 5

8

假设c是局部int变量,c在函数调用之后访问是undefined-behavior并且可能会打印预期的结果,或者可能会做一些意想不到的事情。

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


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

                       +-----------------+
                       .(local variables).
                       |'''''''''''''''''|
                       |                 |
+----------------+     . PRINTF FUNCTION .
|  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);
}

可以打印42main.

于 2015-01-15T12:36:12.533 回答
1

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

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

Mothit Jain 先生回答对此给出了非常详细的解释。

于 2015-01-15T12:34:28.487 回答
1

为了完全理解这一点,我建议您学习处理器的汇编,并了解您的代码是如何编译的。在这一点上,我认为如果我说从函数返回不调用任何内存释放函数,它只是调整寄存器,并且由于在 Add 和 print 之间你没有做任何会改变“释放”堆栈上的值的事情,我认为这会有所帮助,你得到号码。尝试调用一个返回的函数.. pfft i dunno 77 介于两者之间(但请务必将其保存到局部变量!),您将打印不同的结果。不过,学习汇编,做一个合适的程序员。

于 2015-01-15T12:39:32.967 回答
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");
}
于 2015-01-15T12:40:48.817 回答
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,无论如何我认为它们都是意想不到的价值。

于 2015-01-15T12:42:29.547 回答