C 当本地函数在堆栈上清除内存时?

C 当本地函数在堆栈上清除内存时?,c,memory-management,C,Memory Management,我想知道什么时候堆栈中的内存被清除,该堆栈被分配给本地函数调用。我在一些视频教程中看到,当函数调用返回到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

我想知道什么时候堆栈中的内存被清除,该堆栈被分配给本地函数调用。我在一些视频教程中看到,当函数调用返回到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;
}
#包括
作废打印(){
printf(“测试”);
}
int*sum(int*a,int*b){
int c=*a+*b;
返回&c;
}
int main(){
INTA=3,b=2;
int*ptr=总和(&a和&b);
打印();
printf(“总和为:%d”,*ptr);
返回0;
}
当我运行上述程序时,它正在打印预期的垃圾值。但如果我在main中注释“print()”函数,然后运行该程序,它将打印正确的sum值

  • 这是否意味着即使本地函数的执行在堆栈中完成,直到有另一个对堆栈的函数调用,之前分配的内存也不会被清除

  • 如果我删除“print()”中的“printf”语句,并将“print()”调用保留在main中,那么我可以正常看到sum的结果。为什么它没有覆盖堆栈中的内存

  • C没有堆栈,标准中甚至没有提到单词堆栈(C89、C99或C11)。实现可以使用堆栈来提供C抽象机的行为方面,但标准指定的是抽象机本身

    所以,至于何时清除堆栈(假设它存在),这完全取决于实现。您所做的基本上是未定义的行为,即在对象生命周期结束后访问对象,因此结果可以是实现选择的任何内容

    至于为什么您可以在特定实现的生命周期结束后访问这些项,很可能是因为进入和退出函数并没有清除堆栈,它只是调整堆栈指针(比清除内存要高效得多)

    因此,除非某个内容覆盖了该内存位置上的内容(例如后续调用
    printf
    ),否则它可能会保持上次设置的状态

    作为示例,下面是函数的示例prolog代码:

    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.
    
    请注意,无论是空间的分配(
    sub
    在prolog中),还是空间的释放(
    mov
    在epilog中),实际上都不会清除它正在使用的内存


    但是,如上所述,这不是您应该依赖的。

    您的问题的答案是特定于操作系统的。在从头开始创建进程(VMS/NT)的系统中,只有在创建进程时,堆栈才会被清除。堆栈是从需求零页面创建的。首次访问堆栈页时,操作系统将创建一个新的零页

    在分叉系统中,每当加载新的可执行文件时,堆栈就会被清除。通常过程与上述相同

    创建堆栈后,任何放在那里的内容都会保留在那里,直到被覆盖


    堆栈由操作系统管理;不是编程语言。

    我认为你最好把时间花在学习好的实践上,而不是试图突破未定义行为的界限。不要返回指向本地存储的指针。Peroid.“这是预期的”这是不预期的。这是未定义的行为。任何事情都有可能发生。这个问题没有实际意义。函数:“sum()”返回堆栈上某个值的地址。但是,当函数退出时,该函数的所有堆栈都“超出范围”。尝试引用“超出范围”堆栈上的任何内容是未定义的行为。任何事情都可能发生,包括seg故障事件。建议:不要编写行为未定义的代码。