在堆栈中,内存是为main保留的,我们称之为main函数的堆栈帧.
当我们调用Add函数时,内存保留在堆栈顶部.在Add函数堆栈帧中,a和b是局部指针,c是一个计算总和的整数,然后我们返回引用. c是Add函数的局部变量.
现在当Add函数执行完成时,堆栈中的内存空间也被释放,所以当我们尝试使用指针p访问main中的这个地址时,我们试图访问的内容基本上是一个释放空间.编译器发出警告,但为什么它仍然正确打印值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; }
解决方法
假设c是局部int变量,在函数调用之后访问c是未定义的行为并且可能打印预期结果,或者可能做一些意外的事情.
虽然C没有强制要求,但通常使用堆栈来实现.出于性能原因,当函数返回时,它会使堆栈区域保持不变.这就是为什么你看到价值5即1 4的原因.但你永远不要指望这一点.
当您使用第二个函数时,行为仍然未定义,因此您可以获得任何输出.实际上,如果在第二个函数中定义另一个变量并使用它,输出可能会改变.
+----------------+ | c = 42 | |''''''''''''''''| +----------------+ | | | | . ADD FUNCTION . . HELLO FUNCTION . | | | | +----------------+ +----------------+ | b = 4 | | b = 4 | |''''''''''''''''| |''''''''''''''''| | a = 1 | | a = 1 | |''''''''''''''''| |''''''''''''''''| | | | | . MAIN FUNCTION . . MAIN FUNCTION . | | | | +----------------+ +----------------+
在上图中,我试图直观地表示当你在Add函数和Hello函数里面时堆栈可能如何堆叠.你可以看到Hello没有搞乱在Add函数中为c保留的堆栈内存.
您可以通过重写Hello函数来验证这一点
void Hello() { int i = 42; printf("Yay - %d\n",i); }
可以在主要打印42.