销毁(免费)链接列表样式堆栈中的所有东西?

时间:2017-09-19 06:20:44

标签: c function pointers memory-management data-structures

//目前它不是一个非常成熟的LINK-Stack,我会稍后更新。 当我遇到这个错误时,我试图释放linklist-style堆栈中的每个节点:

根据解决方案1,这是一个可编译但不可执行的脚本。当我想为(* S)分配一个地址时,我的问题可能发生了,BUT(* S)被释放了ALREADY?

关于destroy函数,我想释放之前分配给(S)的RAM中的每个节点,使RAM可重用。

那么为什么第一个功能不可用????

PS:我不知道在C中删除变量,删除的意思是删除它的地址。也许通常的变量不能被FREE()释放?

PPS:当我使用free()时,我认为它只是释放RAM,但保留变量的名称或标识符可能指向NULL或somwhere,这是危险的,但在Solution1中,似乎我必须这样做。

//IDE:Dev C++ 5.11 
#include<stdio.h>
#include <stdlib.h>
typedef int ElemType;

typedef struct Stack
{
    struct Stack *next;
    ElemType data;
} Stack,*LinkStack;

int InitStack(LinkStack *S) {
    *S = (LinkStack)malloc(sizeof(struct Stack));
    if(!*S) return -1;
    (*S)->next=NULL;
    (*S)->data =0;
    printf("Maybe successfully initialized.\n");
    return 0;
}

int Push(LinkStack *S, ElemType e)
{
    LinkStack pt = (LinkStack)malloc(sizeof(struct Stack));
    LinkStack newpt = (LinkStack)malloc(sizeof(struct Stack));
    newpt->data = e;
    pt = (*S)->next;
    int number = 0;

    if (!pt)
    {
        printf("#a one time \n");
        (*S)->next = newpt;
        (*S)->data++;
        return 1;
    }
    else
    {
        while (number < (*S)->data)
        {
            pt = pt->next;
            number++;
        }
        pt->next = newpt;
        newpt->next = NULL;
        (*S)->data++;
        return 0;
    }
}

int StackTraverse(LinkStack S)
{
    LinkStack pt = (LinkStack)malloc(sizeof(struct Stack));
    pt = (S)->next;
    while (pt)
    {
        printf("%d__", pt->data);
        pt = pt->next;
    }
    return 0;
}

Solution1:  //unavailable
void DestroyStack(LinkStack *S)
{
    while (*S)
    {
        LinkList pt = (*S)->next;
        free(*S);
        (*S) = pt;
    }
    printf("Node destroyed!\n");
}

int main()
{
    LinkStack Sb;
    InitStack(&Sb);
    ElemType *e = (ElemType *)malloc(sizeof(ElemType));
    while (scanf("%d", e))
    {
        Push(&Sb, *e);
        printf("you have entered : %d.\n", *e);
    }
    free(e);
    printf("%d\n", Sb->next->next->data);
    StackTraverse(Sb);
    DestroyStack(&Sb);
    if (!Sb)
    {
        printf("succeed\n");
    }
    return 0;
}

所以我提出了另一个函数!使用递归,但是当我向linklist-style堆栈插入3个节点时,似乎“ LinkStack销毁”被打印6次。当我插入4个节点时,它会打印7次。

solution2:  //available ,but not work well
void DestroyStack(LinkStack *S) {
    while(*S){
        LinkStack pt=(*S);
        (*S)=(*S)->next;
        printf("#a\n");
        DestroyStack(S);
    }
    printf("LinkStack Destroyed!");
}

感谢您的帮助!

4 个答案:

答案 0 :(得分:0)

你的解决方案1是错误的。

void DestroyStack(LinkStack *S){
    if(S){
        LinkStack pt = S;
        S = S->next;
        free(pt);
        printf("#a\n");
        DestroyStack(S);
        printf("LinkStack Destroyed!");
    }
}

请注意您传递指针*S ,因此请勿混淆->和解除引用操作符(一元* )。另请记住freemalloc分配的任何内容。

对于解决方案2,正确的代码应如下所示:

void DestroyStack(LinkStack *S){
    while(S){
        LinkStack pt = S->next;
        free(S);
        S = pt;
    }
    printf("Node destroyed!\n");
}

请记住,S->next相当于(*S).next,不要混淆它们。也不要混淆指针((*S)=pt肯定是错误的)。 S是一个指针,*S是用户定义的结构。您无法指定结构的指针。

答案 1 :(得分:0)

您的整个代码存在问题,可能是因为您不了解mallocfree真正做了什么。

  • malloc分配一定大小的块,并为您提供该内存的句柄。该句柄是一个指针。这意味着您只在创建对象时调用malloc。在您的代码中,您应该调用它的唯一位置是Push,因为您创建了一个新节点。
  • 您不需要为仅遍历堆栈的指针分配内存。特别是这样的事情:

    LinkStack pt = malloc(sizeof(struct Stack));
    pt = (S)->next;
    

    错误:您通过分配pt来分配内存并立即丢失其句柄。抛弃malloc并仅保留第二行。

  • free给出之前分配回系统的内存。每个malloc都需要相应的free。如果不这样做会被称为内存泄漏。
  • 在指针上调用free后,您可能无法再访问其背后的数据。系统函数free不会将指针设置为NULL,因此您必须注意这一点。
  • 空堆栈是没有节点的堆栈。因此,分配虚节点是没有意义的。您的堆栈由指向其头节点的指针定义。您可以将此节点初始化为NULL

    Stack *Sb = NULL;
    

    同样,您可以检查堆栈中是否还有项目:

    if (Sb) ...
    
  • 这更像是一个风格问题:typedef远离指针性质被认为是不好的做法。您可以typedef结构,而不是LinkStack,只需使用Stack *,这样一眼就能明白您在这里处理指针。

  • main中,您可以执行以下操作:

    printf("%d\n", Sb->next->next->data);
    

    这很危险,因为您不知道用户是否输入了至少三个项目。在解除引用之前,您必须检查NULL的指针。

让我们付诸实践:推动意味着创建一个新节点并将其插入头部,以便新头部是新节点:

typedef int ElemType;

typedef struct Stack Stack;

struct Stack {
    Stack *next;
    ElemType data;
};

void Push(Stack **S, ElemType e)
{
    Stack *newpt= malloc(sizeof(*newpt));

    newpt->data = e;
    newpt->next = (*S);
    *S = newpt;
}

你的代码实现了对堆栈的破坏,但更常见的是,堆栈耗尽了弹出的项目。所以,让我们感到:

ElemType Pop(Stack **S)
{
    ElemType res;
    Stack *rem = *S;

    if (*S == NULL) {
        fprintf(stderr, "Stack underflow\n");
        exit(1);
    }

    res = (*S)->data;
    *S = (*S)->next;
    free(rem);

    return res;
}

请注意我们必须保留数据和旧指针的副本,因为free数据使其无法访问。

现在我们可以重写销毁功能:我们从堆栈中弹出项目,直到用完为止。

void DestroyStack(Stack **S)
{
    while (*S) Pop(S);
}

最后,一个没有分配任何内容的遍历函数:

void StackTraverse(const Stack *S)
{
    while (S) {
        printf("%d ", S->data);
        S = S->next;
    }

    puts("");
}

此功能仅检查堆栈;它没有它,所以它足以通过恒定的头部poiner。最后,主要功能:

int main(){
    Stack *Sb = NULL;        
    ElemType e;

    while (scanf("%d", &e) == 1){
        Push(&Sb, e);
    }

    StackTraverse(Sb);
    DestroyStack(&Sb);

    return 0;
}

元素类型只是int,因此为它动态分配内存有点过分。使用自动变量更容易。

此程序完成后,将释放所有已分配的块。

答案 2 :(得分:0)

在soluting1中,无论是真还是假,你的代码都会打印“destory”,因此你插入的次数不等于你失去的次数。这是一个逻辑错误,你也需要自由,你几乎完成了它。 我不擅长英语,希望你能理解我

答案 3 :(得分:-1)

你没有在解决方案1中调用free(pt),它会进入所有节点的循环,并且不会释放任何内容。

C中的free()释放了指针指向的内存,指针仍然存在于内存中,因此程序员通常会编写一个包装器函数来释放内存并将指针指向NULL。