【问题标题】:Stack in C: why do i have memory leaks?C 中的堆栈:为什么我有内存泄漏?
【发布时间】:2014-02-18 20:32:20
【问题描述】:

只是在这里修改 C。我刚刚运行了 valgrind,结果发现我的程序中有内存泄漏,即使我释放了我分配的内存。我错过了什么?

stack.c:

#include <stdlib.h>
#include <stdio.h>
#include "stack.h"

struct node {
  int element;
  Node *next;
};

struct stack {
  Node *tos;
};

Stack *stack_create() {
  Stack *S;
  if ((S = (Stack *)malloc(sizeof(Stack))) != NULL)
      S->tos = NULL;
  return S;
}

void stack_destroy(Stack *S) {
  Node *temp = S->tos;
  while (S->tos != NULL) {
    temp = S->tos;
    free(S->tos);
    S->tos = temp->next;
  }
  free(S);
}

void push(Stack *S, int element) {
  Node *N;
  if ((N = (Node *)malloc(sizeof(Node))) != NULL) {
    N->element = element;
    N->next = (S->tos == NULL) ? NULL : S->tos;
    S->tos = N;
  }
}

int pop(Stack *S) {
  Node *tos = S->tos;
  S->tos = tos->next;  
  return (int) tos->element;
}

int peek(Stack *S) {
  return (int) S->tos->element;
}

void to_string(Stack *S) {
  Node *cursor = S->tos;
  while (cursor != NULL) {
    printf("[%d] ", cursor->element);
    cursor = cursor->next;
  }
  printf("\n");
}


int main() 
{
  Stack *S;

  S = stack_create();

  push(S, 5);
  push(S, 6);
  push(S, 4);
  push(S, -55);

  to_string(S);

  printf("Pop %d\n", pop(S));
  printf("Pop %d\n", pop(S));

  to_string(S);

  stack_destroy(S);

  return 0;  
}

【问题讨论】:

  • 也许它太明显了,但我很确定你只需要改变你的“stack_destroy”。在保存“S->tos->next”之前释放“S->tos”。
  • 为什么不包括 valgrind 输出?
  • 在 stack_destroy 中,而不是 temp 调用它 Node* next;然后下一个 = S->tos->下一个;然后 s->tos = 下一个;这样你就不会引用释放的内存,尽管这不是你的问题
  • 因为 valgrind 在 VM 中。无法复制输出

标签: c memory-leaks valgrind


【解决方案1】:

实际的问题是你的 Pop 杀死了节点,但它并没有释放它

Node* node_destroy(Node* n)

    Node* next;
    if(n == NULL) return NULL;
    next = n->next;
    free(n);
    return next;
}


int stack_pop(Stack *s) {
      int element;
      if(s == NULL || s->tos == NULL) return 0;  // no really good result you can give
      element = s->tos->element;    
      s->tos = node_destroy(s->tos);
      return element;
    }

那你就可以了

void stack_destroy(Stack *S) {
  while (S->tos != NULL) {
    s->tos = node_destroy(s->tos);
  }
  free(S);
}

【讨论】:

  • 哦,是的,我只是取消引用它,就这样 - 它丢失了
  • 你还需要考虑提供一个is_stack_empty 函数,因为如果你弹出一个空堆栈,弹出是奇怪的
【解决方案2】:

问题在于您的销毁方法。你释放了 temp 所指的S-&gt;tos。然后你使用temp-&gt;next

将温度设置为S-&gt;tos-&gt;next

【讨论】:

    【解决方案3】:

    问题在于你的失败:

    void stack_destroy(Stack *S) {
      Node *temp = S->tos;
      while (S->tos != NULL) {
        temp = S->tos;
        free(S->tos);
        S->tos = temp->next;
      }
      free(S);
    }
    

    Temp 指向 S-&gt;tos 来自:

    temp = S->tos;
    

    但是之后你立即释放它:

    free(S->tos);
    

    那么当你调用temp-&gt;next;时,临时已经被释放了。

    试试这个:

    void stack_destroy(Stack *S) {
      Node *temp; //Also, no need to assign here from the original (you assign to it immediately within the while)
      while (S->tos != NULL) {
        temp = S->tos->next; //You need to get the pointer to node "next" before you free S->tos
        free(S->tos);
        S->tos = temp;
      }
      free(S);
    }
    

    EDIT1:根据Keith Nicholas - See here for his elegant solution

    Pop 也不会释放您从中提取元素的节点:

    旧:

    int pop(Stack *S) {
      Node *tos = S->tos;
      S->tos = tos->next;  
      return (int) tos->element;
    }
    

    新:

    int pop(Stack *S) {
      Node *tos = S->tos;
      int element = tos->element;
      S->tos = tos->next;  
      free(tos);
      return element;
    }
    

    【讨论】:

    • 除非你不需要第一个作业
    • 只是节点 *temp;很好
    • 不错的收获!我对其进行了编辑并添加了有用的评论。
    • 我可能会在循环内部提取一个函数 Node* node_destroy(Node* n);如果没有下一个,则返回下一个或 NULL。 stack_destroy 是while(S-&gt;tos != null) s-&gt;tos = node_destroy(S-&gt;tos); free(S);
    • 用截图更新了代码。仍然丢失 16 个字节
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多