我用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个 每个数字都位于一行上。
答案 0 :(得分:3)
根据malloc
和free
,您所拥有的是正确的。
您应仅将free
或malloc
返回的内容传递给realloc
。您可以为结构和堆栈分配空间,并且可以释放两者,因此不会泄漏任何内存。
您不希望先free(st)
,因为这样做之后st
指向的内存不再有效,并且随后您不能安全地free(st->base)
。另外,由于free
对给定内存的内容一无所知,因此它不会尝试释放该内存可能包含的任何指针。因此,仅调用free(st)
就会泄漏st->base
中的内存。
答案 1 :(得分:1)
每个分配都应与相应的free
配对,因此在您的情况下,这意味着要同时释放st->base
和st
(按此顺序)。但是您的程序仅在终止之前立即执行释放,如果程序终止,则它免费释放的所有内容都会被OS收回。诸如Valgrind之类的内存使用分析器可以为您检测出差异,但实际上并不重要。
答案 2 :(得分:1)
您的代码正确。相反的顺序可能会起作用,但是如果确实如此,那将是偶然的。
原因是free(st)
释放了存储对象*st
的内存。指针st->base
存储在该内存的一部分中。假设某个其他任务或线程在释放后立即获取了相同的内存。然后怎样呢?也就是说,当最终调用free(st->base)
时会发生什么?
答案:会发生什么是不确定的。
即使仍然有可能从st->base
检索地址(并且不可能),该地址也可能已被任意数据覆盖,在这种情况下,free(st->base)
–解释了任意地址数据作为地址-会要求操作系统重新分配...好吧,您不知道什么会要求操作系统重新分配。在这种情况下,人们很难指望取得好的结果。
您做得很好。您的排序是正确的。
其他注意事项
为了安全起见,现代操作系统内核有时会自动用空或随机数据覆盖释放的内存。此外,他们有时会撤消程序对通过硬件(已)(实际上)解决了分配的内存的硬件 page 的访问,或者收紧允许访问的范围。其中一些比其他可能性更大,但我已经看到这三个中至少有两个发生了。关键在于,根据内核最新的内存管理和安全算法,内核可以自由选择立即,早,晚或根本不执行这些操作,因为内核不希望您的程序在乎释放的内容程序重新分配内存之后。