[英]Free the stack implemented in C
我用C語言實現了堆棧及其功能。現在,在調用所有功能之后,我想釋放堆棧。
我的問題是我應該先釋放堆棧“ st”的基指針還是直接釋放堆棧“ st”? 兩者似乎都在我的代碼中工作。
#include <stdio.h>
#include <stdlib.h>
#define init_size 10
#define increment 1
typedef struct sqStack
{
int* top;
int* base;
int stack_size;
}sqStack;
int init_stack(sqStack* sq)
{
if(sq->base==NULL)
{
sq->base = (int*)malloc(init_size*sizeof(int));
}
if(sq->base==NULL) exit(-1);
sq->stack_size=init_size;
sq->top=sq->base;
return 1;
}
int push(sqStack* sq, int e)
{
if(sq==NULL) exit(-1);
if(sq->top-sq->base==sq->stack_size-1)//pointer top reaches the top of the stack
{
int* q = (int*)realloc(sq->base,(sq->stack_size+increment)*sizeof(int));
if(q==NULL) exit(-1);
sq->base=q;
sq->top=sq->base+sq->stack_size-1;
sq->stack_size += increment;
}
*sq->top++=e;
return 1;
}
int pop(sqStack* sq,int* e)
{
if(sq==NULL) exit(-1);
if(sq->base==sq->top) exit(-1);
sq->top--;
*e=*sq->top;
sq->stack_size--;
return *e;
}
int top(sqStack* sq,int* e)
{
if(sq==NULL) exit(-1);
if(sq->base==sq->top) exit(-1);
*e=*(sq->top-1);
return *e;
}
int empty(sqStack* sq)
{
if(sq->base==sq->top) return 1;
else return 0;
}
int main() {
sqStack* st= (sqStack*)calloc(1,sizeof(sqStack)) ;
int e;
init_stack(st);
for(int i=0;i<12;i++)
{
push(st,i+1);
}
for(int i=0;i<12;i++)
{
printf("%d\n",top(st,&e));
printf("%d\n",pop(st,&e));
}
free(st->base);
free(st);
return 0;
}
結果是:12 12 11 11 10 10 9 9 8 8 7 7 6 6 5 5 4 4 3 3 2 2 1 1每個數字都位於一行上。
就malloc
和free
而言,您所擁有的是正確的。
您只應free
malloc
或realloc
返回的內容。 您為結構和堆棧分配空間,然后釋放兩者,因此不會泄漏任何內存。
您不希望先free(st)
因為這樣做之后, st
指向的內存不再有效,並且您隨后無法安全地free(st->base)
。 同樣,由於free
對給定內存的內容一無所知,因此它不會嘗試釋放該內存可能包含的任何指針。 因此,僅調用free(st)
泄漏st->base
的內存。
每個分配都應與相應的free
配對,因此在您的情況下,這意味着要同時釋放st->base
和st
。 但是您的程序僅在終止之前立即執行釋放,如果程序終止,則它免費釋放的所有內容都會被OS收回。 諸如Valgrind之類的內存使用分析器可以為您檢測出差異,但實際上並不重要。
您的代碼是正確的。 相反的順序可能會起作用,但是如果確實如此,那將是偶然的。
原因是free(st)
取消分配了存儲對象*st
的內存。 指針st->base
被存儲在此內存的一部分中。 假設某個其他任務或線程在釋放后立即獲取了相同的內存。 然后怎樣呢? 也就是說,最終調用free(st->base)
會發生什么?
答:會發生什么是不確定的。
即使仍然可以從st->base
檢索地址(並且不可能),該地址也可能已被任意數據覆蓋,在這種情況下, free(st->base)
將任意數據解釋為一個地址將要求操作系統解除分配......好吧,你不知道它會要求操作系統解除分配。 在這種情況下,人們幾乎不能指望取得好的結果。
你做得很好。 您的排序是正確的。
其他注意事項
為了安全起見,現代操作系統內核有時會自動用空或隨機數據覆蓋釋放的內存。 同樣,他們有時會撤消程序對已通過(虛擬)方式釋放內存的硬件頁面的訪問,或者收緊允許訪問的范圍。 其中一些比其他可能性更大,但我已經看到這三個中至少有兩個發生了。 關鍵在於,根據內核最新的內存管理和安全算法,內核可以自由選擇立即,早,晚或根本不執行這些操作,因為內核不希望您的程序在乎釋放的內容程序重新分配后的內存。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.