内存泄漏检测导致错误

时间:2014-02-07 03:41:43

标签: c memory-leaks

基本上我有内存泄漏。所以我想解决它们!在某些函数中添加了free()。运行valgrind并获得成功的消息所有泄漏记忆固定或像这样!之后我遇到了一堆错误:(我认为我已经把free()放了。很容易混淆,因为有节点作为指针,节点作为结构(在file.h中查看)。任何帮助表示感谢谢谢。抱歉,这个问题很简单。我是初学者.....

file.h中的代码

struct node {
    int value;
    struct node * next;
};
typedef struct node List;

int is_empty(List *);
List *add_node(List *, int);
List *remove_node(List *, int);
List *create_node(int);
char *tostring(List *);

file.c中的代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "list.h"

#define STRSIZE 128 /*assume string representation fits*/

/* Return true if the list h is empty
 * and false otherwise.
 */
int is_empty(List *h) {
    return h == NULL;
}

/* Create a list node with value v and return a pointer to it 
 */
List *create_node(int v) {
    List *node = malloc(sizeof(List));
  free(node);
    node->value = v;
    node->next = NULL;
    return node;
}

/* Insert a new node with the value v at the 
 * front of the list. Return the new head of 
 * the list.
 */
List *add_node(List *h, int v) {
    List *node = create_node(v);
    node->next = h;
    return node;
}

/* Remove the first node in the list h that
 * has the value v.  Return the head of the
 * list.
 */
List *remove_node(List *h, int v) {
    List *curr = h;

    /* Handle the cases when list is empty or the value
     * is found at the front of the list */
    if (h == NULL) {
        return h;
    } else if (h->value == v) {
        h = h->next;
 return h;
    }

    /* Look for the value in the list (keeping the pointer to
     * the previous element so that we can remove the right 
     * element) */
    while (curr->next != NULL && curr->next->value != v) {
        curr = curr->next;
    }

    if (curr->next == NULL) { /* v is not in list so do nothing */
        return h;
    } else { /* curr->next->value == v */
        curr->next = curr->next->next;
        return h;
    }
}

/* Return a string representation of the list pointed to by h.
 */
char *tostring(List *h) {
    char *str= malloc(STRSIZE);
    char num[4]; /* assume integer has max. four digits*/
    free(str);
    str[0] = '\0';
    while (h != NULL) {
        sprintf(num, "%d", h->value);
        strncat(str, num, STRSIZE - strlen(str) - 1);
        h = h->next;
    }
    return str;
}

5 个答案:

答案 0 :(得分:1)

可能你想要

temp = curr->next;
curr->next = curr->next->next;
free (temp);

在代码的当前状态中,remove_node漏洞(如果删除所有节点,实际泄漏整个列表)。

另外,为了阻止tostring函数中的内存泄漏,此函数的调用者有责任释放tostring返回的字符串。

答案 1 :(得分:1)

在你的create_node()中,为什么你有free()?你应该删除那个free()。​​

在你的remove_node()中,你需要始终返回头部。我认为以下递归方法应该有效。递归函数将找到要删除的节点并返回下一个节点。如果没有删除,它将返回相同的节点。保持递归,直到找到具有该值的节点或列表的末尾。要检查的主要是,

时是否有效
  1. 删除头节点
  2. 空列表
  3. 删除最后一个节点
  4. 删除中间节点
  5. 以下代码未经过测试: - )。

    你提到你还有内存泄漏。正如Karthik所提到的,你的toString()函数会分配内存,并由调用者来释放它。因此,每次调用toString()函数时都要确保调用free()。否则你会泄漏记忆。

    List *remove_node(List *h, int v) {
        List *retval = remove_recurse(h,v);
    
        // if retval is different from head, means head is removed. return new head.
        // Otherwise return old head.
        return (retval!=h) ? retval : h;
    }
    
    List *remove_recurse(List *node, int v) {
        if(node==NULL) return NULL;
    
        List *retval = node; // default return current node
    
        if(node!=NULL && node->value==v) { // need to remove node
            retval = node->next; // return the next node
            free(node); // delete node
        }
        else {
            List *temp = remove_recurse(node->next,v);
            // if next node was deleted, point to new node
            if(node->next!=temp) node->next=temp;
        }
    
        return retval;
    }
    

答案 2 :(得分:1)

有了这个

List *node = malloc(sizeof(List));
free(node);

你分配一个节点(List)然后让节点指向它,然后你释放什么节点指向,所以在空闲之后它指向内存中的某个未分配的空间然后你开始分配给那个内存:

node->value = v;
node->next = NULL;

导致未定义的行为,它肯定是错误的,但编译器不会检测到。

删除free(node)

List *create_node(int v) 
{
  List *node = malloc(sizeof(List));
  node->value = v;
  node->next = NULL;
  return node;
}

如果你保持结构名称和typedef相同,那就更具可读性了。

typedef struct node {...} node;

而不是创建新的别名,而是使用更好的变量名称,例如

node* listStartOfNodes = NULL; // always initialize

答案 3 :(得分:1)

1,这个功能错了。

List *create_node(int v) {
    List *node = malloc(sizeof(List));
    free(node);
    node->value = v;
    node->next = NULL;
    return node;
}

为什么你free(node)?请删除此free(node);。 和此功能相同的错误,请删除free(str);

char *tostring(List *h) {
    char *str= malloc(STRSIZE);
    char num[4]; /* assume integer has max. four digits*/
    free(str);
    str[0] = '\0';
    while (h != NULL) {
        sprintf(num, "%d", h->value);
        strncat(str, num, STRSIZE - strlen(str) - 1);
       h = h->next;
    }
    return str;
}

2,你应该修改这个功能:

    List *remove_node(List *h, int v) {
    List *curr = h;
    List* freeNode = NULL;
    /* Handle the cases when list is empty or the value
    * is found at the front of the list */
    if (h == NULL) {
        return h;
    } else if (h->value == v) {
        freeNode = h;
        h = h->next;
        free(freeNode);
        return h;
    }

    /* Look for the value in the list (keeping the pointer to
    * the previous element so that we can remove the right 
    * element) */
    while (curr->next != NULL && curr->next->value != v) {
        curr = curr->next;
    }

    if (curr->next == NULL) { /* v is not in list so do nothing */
        return h;
    } else { /* curr->next->value == v */
        freeNode = curr->next;
        curr->next = curr->next->next;
        free(freeNode);
        return h;
    }
}

答案 4 :(得分:0)

在函数remove_node

List *remove_node(List *h, int v) 
{
List *curr = h,*prev;

/* Handle the cases when list is empty or the value
 * is found at the front of the list */
if (h == NULL) {
    return h;
 } else if (h->value == v) {
    h = h->next;
    free(curr);
    return h;
 }

while (curr->next != NULL && curr->next->value != v) {
    curr = curr->next;
}

if (curr->next == NULL) { /* v is not in list so do nothing */
    return h;
} else { /* curr->next->value == v */
    prev = curr->next;
    curr->next = curr->next->next;
    free(prev); 
    return h;
}
}

当您在移除节点时不再需要该节点时,应该释放内存。

在函数tostring中,在不再使用或不需要str之后,不要释放刚刚分配的内存释放被调用函数中的内存。