我想知道何时在堆栈中清除了内存,这是为本地函数调用分配的。我在一些视频教程中看到,当函数调用返回到main时,为本地函数分配的内存被清除。我对下面的程序提出的问题很少,请解释一下。
#include<stdio.h>
void print(){
printf("testing \n");
}
int* sum(int* a, int* b){
int c = *a + *b;
return &c;
}
int main(){
int a=3,b=2;
int *ptr = sum(&a,&b);
print();
printf("sum is: %d",*ptr);
return 0;
}
当我运行上述程序时,它正在打印预期的垃圾值。但是如果我在main中注释“print()”函数然后运行程序则打印正确的sum值。
这是否意味着即使本地函数的执行在堆栈中完成,在对堆栈进行另一个函数调用之前,先前分配的内存不会被清除?
如果我删除“print()”中的“printf”语句并在main中保持“print()”调用,那么我可以看到sum的结果正常。为什么它没有覆盖堆栈中的内存?
答案 0 :(得分:6)
C 没有堆栈,标准中甚至没有提到单词堆栈(C89,C99 或 C11)。 实现可以使用堆栈来提供C抽象机器的行为方面,但它是标准指定的抽象机器本身。
因此,关于何时清除堆栈(假设它甚至存在),这完全取决于实现。你正在做的基本上是未定义的行为,在它的生命周期结束后访问一个对象,所以结果可以是实现选择的任何东西。
至于为什么你可以在特定实现的生命周期结束后访问这些项目,很可能是因为进入和退出函数没有清除堆栈,它只是调整堆栈指针(比清除内存更有效)。
因此,除非某些内容覆盖了该内存位置的内容(例如后续调用printf
),否则它可能会保留在上次设置的内容中。
举例来说,这是一个函数的示例序言代码:
push ebp ; Save the frame pointer.
mov ebp, esp ; Set frame pointer to current stack pointer.
sub esp, XX ; Allocate XX space for this frame.
及其等效的结语:
mov esp, ebp ; Restore stack pointer.
pop ebp ; Get previous frame pointer.
ret ; Return.
请注意,prolog中的空间分配(sub
)和epilog中的mov
的释放实际上都不会清除它正在使用的内存。< / p>
但是,如上所述,这不是你应该依赖的东西。
答案 1 :(得分:0)
您的问题的答案是特定于操作系统。在从头开始创建进程的系统(VMS / NT)中,只有在创建进程时才会清除堆栈。堆栈是从需求零页面创建的。首次访问堆栈页面时,操作系统会创建一个新的零页面。
在分叉系统中,只要加载新的可执行文件,就会清除堆栈。通常该过程与上述过程相同。
创建堆栈后,无论放在哪里,都会一直存在,直到被覆盖。
堆栈由操作系统管理;不是编程语言。