在C中堆栈:为什么我有内存泄漏?

时间:2014-02-18 20:32:21

标签: c memory-leaks valgrind

在这里修改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;  
}

enter image description here

3 个答案:

答案 0 :(得分:2)

实际问题是你的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);
}

答案 1 :(得分:0)

问题在于你的destroy方法。你释放临时引用的S->tos。然后使用temp->next

将temp设置为S->tos->next

答案 2 :(得分:0)

问题在于你的命运:

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->tos来自:

temp = S->tos;

但是之后你立即释放它:

free(S->tos);

然后当你调用temp->next; temp已经被释放时。

试试这个:

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;
}