[英]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.