【问题标题】:C: Memory leak implementing a simple linked listC:实现简单链表的内存泄漏
【发布时间】:2019-05-17 10:24:56
【问题描述】:

我创建了一个存储整数的链表。该程序似乎运行良好,但 Valgrind 通知我存在内存泄漏。我不确定这怎么可能。下面提供了代码以及输出和 Valgrinds 评估。谢谢。

ma​​in.c

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

int main( int argc, char* argv[ ] ){
    int num = 0;
    NODE head = NULL;

    num = 7;

    head = list_insert( head, num );
    bytes_of_list( head );

    head = list_insert( head, 9 );
    bytes_of_list( head );

    head = list_insert( head, 2 );
    bytes_of_list( head );

    head = list_insert( head, 8 );
    bytes_of_list( head );

    delete_node( head, 6 );
    delete_node( head, 9 );
    bytes_of_list( head );

    print_list( head );
    printf( "\n" );

    linked_list_destroy( &head );
    bytes_of_list( head );

    return 0;
}

linked_list.c

#include <stdlib.h>
#include <stdio.h>
#include "linked_list.h"
#include "status.h"

struct node;
typedef struct node Node;
struct node{
    int data;
    Node* next;
};
typedef struct node Node;

/************************************************************** list insert */
NODE list_insert( NODE head, int data ){
    Node* pNode = NULL;

    printf( "\nInsert %d into list.\n", data );

    pNode = ( Node* )malloc( sizeof( Node ));
    if( !pNode ) exit( 1 );
    pNode->data = data;
    pNode->next = head;
    return pNode;
}
/******************************************************  linked_list_destroy */
void linked_list_destroy( NODE* head ){
    Node* phead = ( Node* )*head;
    Node* prevNode = NULL;

    printf( "\nDestroy List:\n");

    if( !phead ) return;
    while( phead != NULL ){
        prevNode = phead;
        phead = phead->next;
        printf( "Deleting %d\n", prevNode->data );
        prevNode->data = 0;
        prevNode->next = NULL;
        free( prevNode );
    }
    *head = NULL;
}
/***************************************************************  print_list */
void print_list( NODE head ){
    Node* pHead = ( Node* )head;

    printf( "\nPrint list:\n");

    while( pHead != NULL ){
        printf( "%d ", pHead->data );
        pHead = pHead->next;
    }
}
/***********************************************************  delete nodes */
void delete_node( NODE head, int data ){
    Node* phead = ( Node* )head;
    Node* prev = NULL;

    printf( "\nDelete %d from list:\n", data );

    if( !head ) return;
    while(( phead != NULL ) && ( phead->data != data )){
        prev = phead;
        phead = phead->next;
    }
    if( !phead ) printf( "Sorry, %d is not in the list.\n", data);
    else{
        prev->next = phead->next;
        free( phead );
    }
    return;
}
/********************************************************* bytes of list */
int bytes_of_list( NODE head ){
    Node* phead = ( Node* )head;
    int bytes_total = 0;
    while( phead != NULL ){
        bytes_total += sizeof( *phead );
        phead = phead->next;
    }
    printf( "The current size of the list is %d bytes.\n", bytes_total );
    return bytes_total;
}

linked_list.h

#ifndef LINKED_LIST_H_INCLUDED
#define LINKED_LIST_H_INCLUDED
#include "status.h"

typedef void* NODE;
NODE list_insert( NODE head, int data );
void print_list( NODE head );
void linked_list_destroy( NODE* head );
void delete_node( NODE head, int data );
Status in_list( NODE head, int data );
int bytes_of_list( NODE head );

#endif

status.h

#ifndef STATUS_H_INCLUDED
#define STATUS_H_INCLUDED
enum status {FALSE, TRUE};
typedef enum status Status;
#endif

此程序的输出如下:

将 7 插入列表中。

列表的当前大小为 16 字节。

将 9 插入列表中。

列表的当前大小为 32 字节。

将 2 插入列表中。

列表的当前大小为 48 字节。

将 8 插入列表。

列表的当前大小为 64 字节。

从列表中删除 6 个:

抱歉,6 不在列表中。

从列表中删除 9:

列表的当前大小为 48 字节。

打印列表:

8 2 7

销毁清单:

删除 8

删除 2

删除 7

列表的当前大小为 0 字节。

VALGRIND 输出:

==2758== 堆摘要:

==2758== 退出时使用:1198 个块中的 140089 个字节

==2758== 总堆使用量:1,968 次分配,770 次释放,283,758 字节分配

==2758==

==2758== 泄漏摘要:

==2758== 肯定丢失:1 个块中的 10 个字节

==2758== 间接丢失:0 个块中的 0 个字节

==2758== 可能丢失:0 个块中的 0 个字节

==2758== 仍然可以访问:1197 个块中的 140079 个字节

==2758== 抑制:0 个块中的 0 个字节

==2758== 使用 --leak-check=full 重新运行以查看泄漏内存的详细信息

==2758==

==2758== 对于检测到和抑制的错误计数,重新运行:-v

==2758== 错误摘要:来自 0 个上下文的 0 个错误(已抑制:来自 0 的 0 个)

【问题讨论】:

  • 我建议使用--leak-check=full 重新运行它,因为输出日志建议查看更多详细信息。
  • 当我在valgrind v3.13.0 中运行它时,我得到:All heap blocks were freed -- no leaks are possible。也许升级你的 Valgrind。
  • 我试过了: valgrind -v --leak-check=full --show-leak-kinds=all make run 似乎有一个重新发生的泄漏,从 1 字节开始损失记录 1/219 并且似乎滚雪球到更大的数量,在损失记录 219/219 中以 65,536 字节结尾......我
  • 我会尝试升级 Valgrind 看看会发生什么。感谢您的建议。
  • OT: about: int main( int argc, char* argv[ ] ){main()的参数不使用时,使用签名int main( void )

标签: c memory-leaks valgrind singly-linked-list


【解决方案1】:

这是发布代码的一个版本

  1. 全部卡在一个文件中
  2. 所有建议的修复:
  3. 干净编译
  4. 发生错误时通知用户

现在,建议的代码版本:

#ifndef STATUS_H_INCLUDED
#define STATUS_H_INCLUDED
enum status {FALSE, TRUE};
typedef enum status Status;
#endif



#ifndef LINKED_LIST_H_INCLUDED
#define LINKED_LIST_H_INCLUDED
//include "status.h"
#include <stdio.h>

struct node 
{ 
    int data; 
    struct node *next; 
}; 
typedef struct node Node;

Node* list_insert( Node *head, int data );
void print_list( Node *head );
void linked_list_destroy( Node** head );
void delete_node( Node** head, int data );
Status in_list( Node* head, int data );
void bytes_of_list( Node* head );

#endif


#include <stdio.h>
#include <stdlib.h>
//#include "linked_list.h"

int main( void )
{
    int num = 0;
    Node *head = NULL;

    num = 7;

    head = list_insert( head, num );
    bytes_of_list( head );

    head = list_insert( head, 9 );
    bytes_of_list( head );

    head = list_insert( head, 2 );
    bytes_of_list( head );

    head = list_insert( head, 8 );
    bytes_of_list( head );

    delete_node( &head, 6 );
    delete_node( &head, 9 );
    bytes_of_list( head );

    print_list( head );
    printf( "\n" );

    linked_list_destroy( &head );
    bytes_of_list( head );

    return 0;
}


//#include <stdlib.h>
//#include <stdio.h>
//#include "linked_list.h"
//#include "status.h"




/************************************************************** list insert */
Node *list_insert( Node *head, int data )
{
    printf( "\nInsert %d into list.\n", data );

    Node *pNode = malloc( sizeof( Node ));
    if( !pNode )
    {
        perror( "malloc failed" );
        exit( 1 );
    }

    pNode->data = data;
    pNode->next = head;
    return pNode;
}


/******************************************************  linked_list_destroy */
void linked_list_destroy( Node** head )
{
    Node* phead = *head;
    Node* prevNode = NULL;

    printf( "\nDestroy List:\n");


    while( phead )
    {
        prevNode = phead;
        phead = phead->next;
        printf( "Deleting %d\n", prevNode->data );
        prevNode->data = 0;
        prevNode->next = NULL;
        free( prevNode );
    }
    *head = NULL;
}


/***************************************************************  print_list */
void print_list( Node *head )
{
    Node* pHead = head;

    printf( "\nPrint list:\n");

    while( pHead )
    {
        printf( "%d ", pHead->data );
        pHead = pHead->next;
    }
}


/***********************************************************  delete nodes */
void delete_node( Node **head, int data )
{
    Node* phead = *head;
    Node* prev  = NULL;

    printf( "\nDelete %d from list:\n", data );

    //if( !head ) return;

    while(( phead ) && ( phead->data != data ))
    {
        prev = phead;
        phead = phead->next;
    }

    if( !phead ) 
    {
        printf( "Sorry, %d is not in the list.\n", data);
    }

    else
    {
        prev->next = phead->next;
        free( phead );
    }
    return;
}


/********************************************************* bytes of list */
void bytes_of_list( Node* head )
{
    Node* phead = head;
    size_t bytes_total = 0;

    while( phead )
    {
        bytes_total += sizeof( *phead );
        phead = phead->next;
    }

    printf( "The current size of the list is %lu bytes.\n", bytes_total );
    //return bytes_total;
}

【讨论】:

  • 哇,干得好!我仍然不确定为什么会出现内存泄漏。明天我将不得不更详细地检查您的修复。非常感谢!
  • 您遇到了内存泄漏,因为在删除整个列表的过程中分配了很多内存,这些指针从未传递给free()
猜你喜欢
  • 2021-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-16
  • 2012-12-13
  • 2012-03-15
  • 1970-01-01
相关资源
最近更新 更多