Freeing tree that is NOT binary in C - c

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 treeNodes and a list of treeNodeListCells 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);
}
}

Related

Reassignment of void pointers in C

I am making Binary Tree is C. I know how to make Binary trees, that's not the issue over here.
I was using void pointers for root and all the elements that will be added to the tree.
When the binary tree is empty(root is pointing to NULL) I was simply making the root point towards the element that will be becoming the first element of the tree. But root wasn't getting the address of the element it should be pointing to. It was just a simple re-assignment.
As I mentioned above, I was trying simple re-assignment for void pointers to assign a new address for the root.
But when I was assigning the individual values of the element to the root, everything seemed worked perfectly fine.
Represent all the elements for the binary tree.
struct node {
void * key;
void * value;
struct node * left;
struct node * right;
};
First approach: simple re-assignment which fails
void map_tree_put(struct node * root, struct node * ele){
if(root==NULL) {
root = ele;
}
else {
/* some other code*/
}
}
Second approach: individual value assignment works fine
void map_tree_put(struct node * root, struct node * ele){
if(root==NULL) {
root->key = ele.key;
root->value = ele.value;
root->left = NULL;
root->right = NULL;
}
else {
/* some other code*/
}
}
Test code
int main() {
struct node * r = NULL;
int key = 10;
int value = 100;
struct node ele = {&key, &value, NULL, NULL};
map_tree_put(r, &ele);
printf("%d\n", *(int*)r->key); /* I get segmentation fault over here with the first approach but work fine with the second approach */
return 0;
}
Try
void map_tree_put(struct node ** root, struct node * ele){
if((*root)==NULL) {
(*root) = ele;
}
else {
/* some other code*/
}
}
and call from main should be
map_tree_put(&r, &ele);
This is about passing by value and reference.
That's because in this code:
void map_tree_put(struct node * root, struct node * ele){
if(root==NULL) {
root = ele;
}
else {
/* some other code*/
}
}
the function receives a copy of the pointers. To make the root pointer remember the re-assignment when the function returns, you need to do it like this:
void map_tree_put(struct node **root, struct node *ele){
if (root) {
if(*root==NULL) {
*root = ele;
}
else {
/* some other code*/
}
}
}

Delete left subtree node (binary search tree) in C

I am working on a C binary search tree library and I'm trying to write a function that will delete the left node of the tree subtree. Here's the struct of my tree:
struct Node {
int value;
struct Node *left;
struct Node *right;
};
typedef struct Node TNode;
typedef struct Node *binary_tree;
The tree is created like this:
binary_tree NewBinaryTree(int value_root) {
binary_tree newRoot = malloc(sizeof(TNode));
if (newRoot) {
newRoot->value = value_root;
newRoot->left = NULL;
newRoot->right = NULL;
}
return newRoot;
}
Adding element to it:
void Insert(binary_tree *tree, int val) {
if (*tree == NULL) {
*tree = (binary_tree)malloc(sizeof(TNode));
(*tree)->value = val;
(*tree)->left = NULL;
(*tree)->right = NULL;
} else {
if (val < (*tree)->value) {
Insert(&(*tree)->left, val);
} else {
Insert(&(*tree)->right, val);
}
}
}
The delleftsubtreenode I did:
void delleftsubtree(binary_tree *tree){
if( (*tree)->value!=NULL )
{
free(&(*tree)->left);
delleftsubtree( &(*tree)->left);
}
else
{
printf("end");
}
}
This method compile,however when I try to call it the program just crash.I dont understand why or how else to do that function.
thank you!
As Olaf said in his comment, you have several problems; calling "free()" with a pointer then attempting to dereference it, and use of double indirection.
binary_tree* tree; /* why use a pointer to a pointer? */
Unless you intend to change the value of the pointer, this is extra work you don't want to be doing. All those "(*tree)->member" expressions are not needed if you follow the usual conventions, and I'm not convinced that you understand what "&(*tree)->left" is doing.
I'm not saying that you should never use a pointer to a pointer, I've done it myself, however you should only do it when there is a reason to be changing the value of the referenced pointer, or with a volatile pointer that might be changed by some external actor; this is unlikely and fairly rare outside of garbage collected and compacted pools (strings in some BASIC interpreters, for example) and the like.
Keep in mind that the "left" subtree of a node in the tree is a binary tree itself; it has both left and right nodes. You need to write a function that deletes a subtree at and below a given node. Once that's understood, removal of the left subtree below a node is as simple as:
void delSubtree(NodeT* subRoot)
{
if (subRoot != NULL)
{
delSubtree(subRoot->left);
delSubtree(subRoot->right);
free(subRoot);
}
}
void delLeftSubtree(NodeT* root)
{
if (root != NULL)
{
delSubtree(root->left);
root->left = NULL;
}
}
If this is homework, you should be solving these problems yourself, and I'm doing you no favors in giving you code samples. Understanding how to use pointers and linked data structures (lists, trees, and other graphs) is essential to becoming an accomplished C programmer.

freeing an array of lists

I got a memory leak in my program, and I can't understand why. I got a 4 size array of linked lists, and valgrind says there is a memory leak.
Here is my struct:
struct node {
achievementMen100m player;
char* playerName;
Men100mAchievement playerAchiInRound;
char*currentRound;
struct node *head;
struct node *next;
} node, *Node;
Here is my allocation in the create function:
for(int i=0; i<4;i++){
OG->games->head->phases[i] = malloc(sizeof(struct node)); //VALGRIND SAYS MEMORY ALLOCATED HERE NOT FREED!//
OG->games->head->phases[i]->head=NULL;
OG->games->head->phases[i]->next=NULL;
OG->games->head->phases[i]->playerAchiInRound = 0;
}
Here is my free-list function:
void listDestroy(struct node * list) {
struct node * currentPlayer = list;
struct node * temp;
while (currentPlayer != NULL) {
temp = currentPlayer;
currentPlayer=currentPlayer->next;
free(temp->playerName);
free(temp);
}
list = NULL;
free(list);
}
And this is the free function of the ADT:
void olympicGamesDestroy(OlympicGames OG) {
if (OG == NULL) {
return;
}
if (OG->games == NULL) {
free(OG);
return;
}
if (OG->games->head == NULL) {
free(OG->games);
free(OG);
return;
}
for (int i=0; i<4;i++) {
listDestroy(OG->games->head->phases[i]->head);
}
free(OG->games->next);
free(OG->games->head);
free(OG->games);
free(OG);
}
update
here is my entire .h file
typedef struct men100 {
Men100mAchievement olympicMinimum;
Men100mAchievement olympicSkipPre;
char* roundNames[4];
struct node* phases[4];
} men100, *Men100;
typedef struct gameList {
int name;
men100* head;
struct gameList *next;
} gameList, *GameList;
typedef struct olympicGames {
GameList games;
int numOfGames;
} olympicGames, *OlympicGames;
Your void olympicGamesDestroy(OlympicGames OG) looks strange!
You are allocating at OG->games->head->phases[i].
So, where are you freeing them? You are only working on OG->games->head->phases[i]->head and not on OG->games->head->phases[i].
Show the actual OlympicGames data structure.
UPDATE:
I don't have much time to verify the whole code:
But you can try the following:
for(int i=0; i<4; i++)
{
listDestroy(OG->games->head->phases[i]->head);
free(OG->games->head->phases[i]); // you need this
}

insertion binary search tree in C

I've been stuck on the insertion part of the binary search tree. I get so confused with nested structs. The basic idea of this program is to create a bst that is able to hold names and double values which get stored by value (obviously).
Example: I want to store
Jane 3.14
John 3.233
Luke 6.4
Mike 1.4
so the bst would look like
3.14
/ \
1.4 3.233
\
6.4
however I'm having trouble with the insertHelper recursion portion of the code. The hash table is a bonus part of the code that I'll try implementing at a later time. Thank you for your help!
typedef struct name_val // holds name and value
{
char *name;
double value;
}NAME_VAL;
typedef struct node //binary search tree
{
NAME_VAL *nV;
struct node *left;
struct node *right;
}NODE;
struct tmap_struct //handle for bst and hashtable
{
int nL; //nodes on left
int nR; //nodes on right
NODE *root;
NODE **table;
};
int tmap_insert(TMAP_PTR hashTree, char * name, double val)
{
if(hashTree->root == NULL)
{
NODE *bst = (NODE *)malloc(sizeof(NODE));
NAME_VAL *root = (NAME_VAL *)malloc(sizeof(NAME_VAL));
bst->nV = root;
bst->nV->value = val;
strcpy(bst->nV->name, name);
hashTree->root = bst;
hashTree->nL = 0;
hashTree->nR = 0;
}
else
insertHelper(hashTree->root, val, name);
}
void insertHelper(TMAP_PTR hashTree, int val, char * name)
{
if(val < hashTree->root->nV->value)
{
if(hashTree->root->left == NULL)
{
hashTree->root->left = (NODE *)malloc(sizeof(NODE));
hashTree->root->left->nV = (NAME_VAL *) malloc(sizeof(NAME_VAL));
strcpy(hashTree->root->left->nV->name, name);
hashTree->root->nV->value = val;
(hashTree->nL)++;
}
else
insertHelper(hashTree->root->left, val, name);
}
else
{
if(hashTree->root->right == NULL)
{
hashTree->root->right = (NODE *)malloc(sizeof(NODE));
hashTree->root->right->nV = (NAME_VAL *)malloc(sizeof(NAME_VAL));
strcpy(hashTree->root->left->nV->name,name);
hashTree->root->nV->value = val;
(hashTree->nR)++;
}
else
insertHelper(hashTree->root->right, val, name);
}
}
I doubt this compiles. Is that the problem you're having?
From what I can see, you have declared insertHelper with the wrong type for its first parameter. It should take NODE* values, not TMAP_PTR values. That's because you always call it with nodes out of your tree.
So the first part of the function should look like this:
void insertHelper(NODE *node, int val, char * name)
{
if(val < node->nV->value)
{
if(node->left == NULL)
{
node->left = (NODE *)malloc(sizeof(NODE));
node->left->nV = (NAME_VAL *) malloc(sizeof(NAME_VAL));
strcpy(node->left->nV->name, name);
node->left->nV->value = val;
}
else
insertHelper(node->left, val, name);
}
//.....
Note that I removed the line:
(hashTree->nR)++;
It hardly even makes sense to track this information, unless maybe you do it at the node level.
But if you must, you could have insertHelper recursively return a positive or negative value to indicate what side it inserted on. But that doesn't makes sense. What is it on the right of? You may have inserted it on the right of a node that was in the left half of the tree.
If you store this information on each node, you can recursively update the node above as you return from insertHelper. Maybe that's what you were trying to do. Balanced tree implementations do something similar - AVL trees store the maximum depth of the tree at a node and use that to do branch rotations for rebalancing.
You'll have to adapt mine(It's almost standard C besides the unneeded template and class), but it's a similar algorithm: (I believe, I didn't look at any source for my own purposes.)
template<typename T>
class BST {
protected:
typedef struct node_t {
struct node_t * dir[2];
T data;
} node;
node * root;
void insert_node(node * active_node, T data){ //call with node *root;
int next = data < active_node->data ? 0 : 1;
if(active_node->dir[next] == NULL){
active_node->dir[next] = new node;
active_node->dir[next]->dir[0] = NULL;
active_node->dir[next]->dir[1] = NULL;
active_node->data = data;
} else
insert_node(active_node->dir[next], data);
}
public:
BST() : root(new node){root->dir[0] = NULL; root->dir[1] = NULL; root->data = 0;}
~BST(){}
}

Pop() method always giving the first element from stack without erasing it

My program is supposed to read a postfix expression and convert it to infix and prefix using a tree implementation.
the pop() method always give the first element without errasing it and i can't figure out why. Any help will be apreciate.
//tree structur
typedef struct asa {
enum { number_exp,sous_exp_op } type;
union {
int child;
struct {
struct asa* left;
struct asa* right;
char oper; } tree;
} op;
} asa;
//stack
typedef struct stack {
int size;
struct {
asa * element;
struct stack* link;
}e;
} stack;
struct stack *top;
(...)
asa * pop(){
asa* e ;
stack * temp;
if(top->size == 0 ){
printf("ERR0R : empty stack\n");
exit (EXIT_FAILURE);
}
else if (top->size >= 1){
temp = top->e.link;
e= top->e.element;
top = temp;
}
return e;
}
void push(asa* node ){
if(top->size == 0 ){
top->e.element = node;
top->e.link = NULL;
top->size++;
}
else if (top->size > 0){
pile * next = (pile*) malloc(sizeof(top));
next = top;
top->e.element = node;
top->e.link = next;
top->size++;
}
}
Logs snapshot:
Your immediate problems are that you are discarding next as soon as you allocate it when top->size > 0 and that you are allocating the size for a pointer rather than for the whole struct. To fix them, replace next = top with top = next at the end of the function and fix the sizeof invocation:
else if (top->size > 0){
pile * next = (pile*) malloc(sizeof(*top));
next->e.element = node;
next->e.link = top;
next->size = top->size + 1;
top = next;
}
Also, this implementation of stack feels needlessly complex and error-prone. If you need the stack size, you should maintain the size independently of the nodes of the linked list, not in every individual node. The standard linked list idiom is to represent the empty list (stack) as NULL, so neither push nor pop need any extra code to check for empty stack:
typedef struct stack {
asa *element;
struct stack *next;
} stack;
void push(stack **head, asa *elem)
{
stack *new_head = malloc(sizeof(stack));
new_head->next = head;
new_head->elem = elem;
*head = new_head;
}
asa *pop(stack **head)
{
stack *old_head = *head;
asa *top_elem = old_head->elem;
*head = old_head->next;
free(old_head);
return top_elem;
}

Resources