2015-05-25 48 views
2

我遇到了内存泄漏的问题,我在C中构建BST并需要释放BST。我BST_element:尽管释放内存泄漏struct

typedef struct _BST_Node { 
char* name; 
char* public_key_file; 
struct _BST_Node *left, *right; 
} BST_Node; 

我的配置功能:

BST_Node* new_BSTNode(char* name, char* public_key_file) { 

BST_Node* node = malloc(sizeof(BST_Node)); 
node->name = malloc((strlen(name) + 1) * sizeof(char)); 
node->public_key_file = malloc((strlen(public_key_file) + 1) * sizeof(char)); 
node->left = calloc(1,sizeof(BST_Node)); 
node->right = calloc(1,sizeof(BST_Node)); 

//check if allocation was correct 
if (!node || !node->name || !node->public_key_file || !node->left || !node->right) { 
    printf(ALLOCATION_ERROR_MSG); 
    exit(ALLOCATION_ERROR); 
} 

//copy strings into struct 
strcpy(node->name,name); 
strcpy(node->public_key_file,public_key_file); 

return node; 

} 

并负责释放分配的内存功能:

无效free_BST(BST_Node **节点){

//free the children: 
if(!((*node)->right->name==NULL)) 
    free_BST(&((*node)->right)); 
else free((*node)->right); 

if(!((*node)->left->name==NULL)) 
    free_BST(&((*node)->left)); 
else free((*node)->left); 

//free strings 
free((*node)->public_key_file); 
free((*node)->name); 

free(*node); 
} 

我认为节点**没有必要,但是这是一个考试问题,所以我不允许更改声明。

我的测试用例:

{ 
BST_Node* foo1 = new_BSTNode("hi","my"); 
BST_Node* foo2 = new_BSTNode("name","is"); 
foo1->left = foo2; 
free_BST(&foo1); 
} 

内存泄漏是foo1根据VS.然而在我的析构函数中,我明确地释放了这个结构?我该如何解决这个问题?

+1

您如何知道存在内存泄漏? –

+3

我不认为你应该在'BST_new()'中将'left'和'right'初始化为'NULL'以外的任何东西。这是非常令人困惑的,除非你知道该节点是必需的,否则通常你不会分配节点,在某些'insert()'操作中。 – unwind

+2

我认为@unwind就是钱。 'BST_new'为'left'节点分配内存。但是对于'foo1'来说,由于用'foo2'覆盖了''left'节点,所以内存丢失(因此永远不会释放)。 – kaylum

回答

5

创建新节点时,不应将leftright指针设置为除NULL之外的任何其他指针。

你不知道哪些节点将被需要,所以它总是分配的形式很糟糕,并且让事情变得混乱。

改为在树上插入时分配所需的子节点。

0

自由操作有几个问题。

举一个例子,假设'当前'节点位于右端节点链的最末端。

接着的条件将是:

currentNode->name != NULL 
currentNode->public_key_file != NULL 
currentNode->right = NULL 
currentNode->left != NULL 

在free_BST()函数的第一行问:

is the currentNode->right->name != NULL 
然而

,因为currentNode->右边是NULL,这将是访问某些内存地址非常低。一个与节点链无关的地址!

由于地址处于非常低的内存中,读取该地址很可能会触发seg故障事件。

对于代码这个特殊的问题,建议您只盯着

if(NULL != currentNode->right) 
then 
    free name, 
    free public_key_file,   
    free currentNode 

有通过节点

换句话说当遍历留下了类似的问题,不要在其他任何访问数据字段因为'其他'节点可能不存在