释放用C实现的堆栈

时间:2019-02-13 14:36:01

标签: c stack free

我用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个 每个数字都位于一行上。

3 个答案:

答案 0 :(得分:3)

根据mallocfree,您所拥有的是正确的。

您应仅将freemalloc返回的内容传递给realloc。您可以为结构和堆栈分配空间,并且可以释放两者,因此不会泄漏任何内存。

您不希望先free(st),因为这样做之后st指向的内存不再有效,并且随后您不能安全地free(st->base)。另外,由于free对给定内存的内容一无所知,因此它不会尝试释放该内存可能包含的任何指针。因此,仅调用free(st)就会泄漏st->base中的内存。

答案 1 :(得分:1)

每个分配都应与相应的free配对,因此在您的情况下,这意味着要同时释放st->basest(按此顺序)。但是您的程序仅在终止之前立即执行释放,如果程序终止,则它免费释放的所有内容都会被OS收回。诸如Valgrind之类的内存使用分析器可以为您检测出差异,但实际上并不重要。

答案 2 :(得分:1)

您的代码正确。相反的顺序可能会起作用,但是如果确实如此,那将是偶然的。

原因是free(st)释放了存储对象*st的内存。指针st->base存储在该内存的一部分中。假设某个其他任务或线程在释放后立即获取了相同的内存。然后怎样呢?也就是说,当最终调用free(st->base)时会发生什么?

答案:会发生什么是不确定的。

即使仍然有可能从st->base检索地址(并且不可能),该地址也可能已被任意数据覆盖,在这种情况下,free(st->base) –解释了任意地址数据作为地址-会要求操作系统重新分配...好吧,您不知道什么会要求操作系统重新分配。在这种情况下,人们很难指望取得好的结果。

您做得很好。您的排序是正确的。

其他注意事项

为了安全起见,现代操作系统内核有时会自动用空或随机数据覆盖释放的内存。此外,他们有时会撤消程序对通过硬件(已)(实际上)解决了分配的内存的硬件 page 的访问,或者收紧允许访问的范围。其中一些比其他可能性更大,但我已经看到这三个中至少有两个发生了。关键在于,根据内核最新的内存管理和安全算法,内核可以自由选择立即,早,晚或根本不执行这些操作,因为内核不希望您的程序在乎释放的内容程序重新分配内存之后。