繁体   English   中英

释放用C实现的堆栈

[英]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每个数字都位于一行上。

mallocfree而言,您所拥有的是正确的。

您只应free mallocrealloc返回的内容。 您为结构和堆栈分配空间,然后释放两者,因此不会泄漏任何内存。

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

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

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

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

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

即使仍然可以从st->base检索地址(并且不可能),该地址也可能已被任意数据覆盖,在这种情况下, free(st->base)将任意数据解释为一个地址将要求操作系统解除分配......好吧,你不知道它会要求操作系统解除分配。 在这种情况下,人们几乎不能指望取得好的结果。

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

其他注意事项

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM