I'm trying to free a tree that is not binary. It includes dozens of leaves and paths. Basicly it's a tree that starts with a root of a chess board position, and includes a lot of other positions. The structs are the following:
typedef char chessPos[2];
typedef struct _treeNodeListCell treeNodeListCell;
typedef struct _treeNode
{
chessPos position;
treeNodeListCell* next_possible_positions;
} treeNode;
typedef struct _treeNodeListCell
{
treeNode* node;
struct _treeNodeListCell* next;
} treeNodeListCell;
typedef struct _pathTree
{
treeNode* root;
} pathTree;
Basicly I want to free a whole path tree. For example, the path tree looks the following:
So the root of path tree is the root with "C3" written in it. (Ignore the parts with the blue "X" on them, it just means that these tree nodes aren't in the tree in my program)
This is the way I was trying to free the tree:
void freePathTree(pathTree* ptr)
{
freeTreeNode(ptr->root);
free(ptr);
}
void freeTreeNodeListCell(treeNodeListCell* tmp)
{
if (tmp->next != NULL)
{
freeTreeNodeListCell(tmp->next);
}
freeTreeNode(tmp->node);
free(tmp);
}
void freeTreeNode(treeNode* tmp)
{
if (tmp->next_possible_positions == NULL)
free(tmp);
else
{
freeTreeNodeListCell(tmp->next_possible_positions);
}
}
But as always, when trying to free memory, I receive dozens of warnings.
How can I free this huge tree without getting any errors? What is wrong with my program?
Big thanks in advance!
The existing freeTreeNode
function has a memory leak:
void freeTreeNode(treeNode* tmp)
{
if (tmp->next_possible_positions == NULL)
free(tmp);
else
{
freeTreeNodeListCell(tmp->next_possible_positions);
// Memory leak here. `tmp` has not been freed.
}
}
Rather than repeating the call free(tmp)
, the function can be restructured as follows to be more like freeTreeNodeListCell
:
void freeTreeNode(treeNode* tmp)
{
if (tmp->next_possible_positions != NULL)
{
freeTreeNodeListCell(tmp->next_possible_positions);
}
free(tmp);
}
The freeTreeNode
and freeTreeNodeListCell
functions are mutually recursive. freeTreeNode
could be changed to an iterative function that subsumes freeTreeNodeListCell
by "flattening" the tree into a list of treeNode
s and a list of treeNodeListCell
s as it goes:
void freeTreeNode(treeNode* node)
{
treeNodeListCell *cell = NULL;
treeNodeListCell **endCell = NULL;
while (node || cell)
{
if (!cell)
{
endCell = &cell;
}
if (node)
{
*endCell = node->next_possible_positions;
while (*endCell)
{
endCell = &(*endCell)->next;
}
free(node);
node = NULL;
}
while (!node && cell)
{
treeNodeListCell *tmp = cell;
node = cell->node;
cell = cell->next;
free(tmp);
}
}
}
As a more profound change, the data structure could be simplified by merging treeNodeListCell
into treeNode
so that there are fewer types to worry about and to reduce the number of memory allocations required to hold the tree:
typedef struct _treeNode
{
chessPos position;
struct _treeNode *next_possible_positions;
struct _treeNode *node;
} treeNode;
That turns it into a sort of binary tree turned on its side, where next_possible_positions
points across to the siblings, and node
points down to the children.
That would make the freeTreeNode
function simpler. Recursive version:
void freeTreeNode(treeNode *node)
{
if (node)
{
freeTreeNode(node->next_possible_positions);
freeTreeNode(node->node);
free(node);
}
}
Iterative version:
void freeTreeNode(treeNode *node)
{
treeNode **end = &node;
treeNode *tmp;
while (*end)
{
end = &(*end)->next_possible_positions;
}
while (node)
{
*end = node->node;
while (*end)
{
end = &(*end)->next_possible_positions;
}
tmp = node;
node = node->next_possible_positions;
free(tmp);
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.