I am using the following free function for my tree:
void freeTree(struct node *tree) {
if (tree == NULL) return;
freeTree(tree->left);
freeTree(tree->right);
free(tree);
}
And I am creating a tree/operating on it like this:
struct node *root = NULL;
root = createTree(testNodes);
inOrderPrint(root);
freeTree(root);
Definition of node struct:
struct node {
int val;
int color;
struct node *parent;
struct node *left;
struct node *right;
};
I have noticed after running this enough (many hours), memory starts to build up (very little amount) in my IDE (I am using CLion). I am posting to ask if my freeTree function is implemented correctly to rule that out and to see if it could be something else causing this slow memory build up.
Supposing that your tree is in fact constructed in the manner implied by the names of the members of struct node, and that nodes' left and right pointers are set to NULL for nodes that do not have a left or right child, respectively, your freeTree() function will free all memory associated with the (sub) tree whose root node its argument points to. If you have a leak, it is elsewhere.
Related
I'm currently studying Computer Science and we started working with Pointers. I had the feeling that I started to understand pointers but I ran into a problem and can't figure out what went wrong.
We defined a Tree like this:
typedef struct node *tree;
struct node {int key; tree left, right;};
Now we should write a function that creates nodes with three parameters, the key of the node, the left node and the right node that should be "below" the node. I did it like this and it seemed to work:
tree createNode(int n, tree l, tree r){
tree node = (tree) malloc(sizeof(tree));
node->key = n;
node->left = l;
node->right = r;
return node;
}
Finally we should write a function that multiplies all leaves of the Tree and i thought the easiest way would be to start at the root and search for the leaves through a recursion and then multiply them. But when i call the function the program seem to crash in the middle of the function. My function looks like this:
int leafprod(tree t){
printf("%d\n", t->key);
if (t->left == NULL){
if (t->right == NULL){
printf("$1\n\n");
return t->key;
}
printf("$2\n\n");
return leafprod(t->right);
}
if (t->right == NULL){
printf("$3\n\n");
return leafprod(t->left);
}
printf("$4\n\n");
return leafprod(t->left) * leafprod(t->right);
}
and i call the function in the main function like this:
int main(){
tree a = createNode(1, NULL, NULL);
tree b = createNode(2, NULL, NULL);
tree c = createNode(3, a, NULL);
tree d = createNode(4, b, c);
int n = leafprod(d);
printf("end: %d", n);
free(a);
free(b);
free(c);
free(d);
return 0;
}
I used the print statements to follow the programm and try to locate the error, but in most cases it prints nothing. Then sometimes it prints:
4
$4
2
$2
And only two times the program went through the whole code. I believe maybe I am using the malloc function wrong but I cannot tell.
The problem is in this line:
tree node = (tree) malloc(sizeof(tree));
tree is typedef for a pointer to struct node.
Therefore sizeof(tree) is just the size of the pointer.
You should one of the following instead:
tree node = malloc(sizeof(*l));
Or:
tree node = malloc(sizeof(*r));
*l and *r are of type struct node (not a pointer) and this is the element you are trying to create.
Another option as #IanAbbott commented is:
tree node = malloc(sizeof(*node));
Note that node here is the name of the variable, not the type (which in C requires to be prefixes with struct, i.e. struct node).
The advantage of this approach is that the statement is not dependent on other variables.
Side notes:
You shouldn't cast the result of malloc. See here:Do I cast the result of malloc?.
It's not a good practice to hide pointer types with typedefs. You can consider to avoid it (you can use typedef struct node Node if you want to save the need to use the struct keyword everywhere).
Don't use the typedef for hiding pointer types.
With typedef struct node *tree; you have no idea what tree is in your code hence the confusion.
Typically here tree node = (tree) malloc(sizeof(tree)) you did it wrong, and the main reason was probably because you didn't know anymore what tree actually was.
...
struct node
{
int key;
struct node* left;
struct node *right;
};
struct node* createNode(int n, struct node*l, struct node*r) {
struct node* node = malloc(sizeof(*node)); // don't use the cast, it's useless
...
}
int leafprod(struct node* t) {
...
I want to build a graph that creates a new parent node by merging two child nodes. The code below is supposed to merge node a and b into a parent node c. Then, nodes a and c to create a parent node d:
a b
|---|
|
a c
|---|
|
d
When I try to free the graph starting at node d I get a segmentation fault and I don't know why. Somehow it works if I don't use the same node twice in the graph. However, I want to be able to use the same node more than once. Can someone please tell me what am I missing here?
#include <stdlib.h>
struct Node {
int data;
struct Node *child1;
struct Node *child2;
};
struct Node *NewNode(double data) {
struct Node *node = NULL;
node = malloc(sizeof(*node));
if (node == NULL) {
return node;
}
node->data = data;
node->child1 = NULL;
node->child2 = NULL;
return node;
}
struct Node* merge(struct Node *self, struct Node *other) {
struct Node *node = NewNode(-1);
node->child1 = self;
node->child2 = other;
return node;
}
void free_graph(struct Node **node) {
if (*node != NULL) {
free_graph(&(*node)->child1);
free_graph(&(*node)->child2);
free(*node);
*node = NULL;
}
}
int main(void){
struct Node *a = NewNode(1);
struct Node *b = NewNode(2);
struct Node *c = merge(a, b);
struct Node *d = merge(a, c);
free_graph(&d);
}
It does not work because your "tree" does not match your illustration, and is in fact technically not a tree. What you have looks like this:
You need to make a copy instead of reusing a node if you want a tree.
In order to free everything in a graph like this, I'd suggest having a separate linked list to keep track of everything you need to free.
If you don't want to do that, or cannot do that for some reason, it gets more complicated. Performing an operation an all nodes in a tree is trivial, but for a general directed graph it's slightly more complicated. I guess this answer could help, and if not, it at least gives you an idea about what to search for:
Finding list of all nodes in a directed graph
I assume you could do something like this pseudo:
getAllNodes(root, nodes)
if root // NULL check
if not node in nodes // If it's the first time we visit the node
// Add this node to the list of visited nodes
nodes = nodes + [root]
// And then call this function recursively on the children
getAllNodes(root->left, nodes)
getAlLNodes(root->right, nodes)
nodes = []
getAllNodes(root, nodes)
for node in nodes
free(node)
Trees have the nice feature that they never contain loops. But directed graphs do, so you have to have some check to see if a node is already visited. Note that in order for this to work, it has to be called from the root. Or to be more precise, every node needs to be reachable from the node. But that's not so different from a tree.
I guess you could somehow move the free inside to create a freeAllNodes() function, but this is more flexible. Maybe you want a list for other purposes. So my suggestion in that case is to just make freeAllNodes() call getAllNodes().
I could write an implementation for the above, but since C does not provide library functions for linked lists, that would mean including a lot of extra code.
You put a into the intended tree twice, so free_graph attempts to free it twice. Calling free twice on the same address from the same original allocation is improper.
If you want to have a true tree, do not put any node into it twice. If you want to have a data structure that can have the same node in it twice, either use separate copies of the node (e.g., two different allocations for struct Node with the same value for data) or make provisions in the data structure to avoid freeing it twice (for example, add a reference count to struct node to count how many times it is currently in the tree, and free the node only when its reference count reaches zero).
I just started programming and I have a beginner question:
So I have a trie tree and I want to use it to store a large numbers of words from multiple files.
In order to do that everytime after I insert all the words from one file into the tree, I need to free the memory of the tree so that I can reuse the tree for the next file.
Should I use free to just free the root? Or I need to traverse the tree and delete all the node one by one?
Here's the node, I am already able to insert all the words into the tree.
struct node{
struct node * parent;
int noempty;
int isword;
int super;
int occurrence;
int leaf;
struct node * child[26];
};
Here is my insert function:
struct node* insert(struct node *root,char *c){
int i=0;
struct node *temp=root;
int l=length(c);
while(i!=l){
int index=c[i]-'a';
if(temp->child[index]==NULL){
//New Node
struct node *n=(struct node *)malloc(sizeof(struct node));
n->parent=temp;
temp->child[index]=n;
temp->noempty=1;
}
//Node Exist
if(i!=l&&temp->leaf==1){temp->leaf=0;}
temp=temp->child[index];
i++;
}
if(temp->noempty==0){
temp->leaf=1;}
temp->isword=1;
return root;
};
You must traverse the tree and free every node. Each node you created for the Trie has been dynamically allocated. If you just delete the root, then only the memory for the root will be freed, while the memory for every other node is taking up space in the heap. This means you have a memory leak. If you create a Trie for each of your files, the memory that you have not freed could add up to be a substantial amount.
How can I free this tree effectively? That algorithm should work for any given node in such tree. So I'll have pointer to node, and that node will be "root" node. And I want to free everything below that node.
Every node in tree is this struct:
typedef struct tag
{
struct tag* parent;
struct tag* nextSibling;
struct tag* previousSibling;
struct tag* firstChild;
struct tag* lastChild;
char* name;
char* text;
}node;
I imagine this would work. But in reality, Dariusz is correct. You just use a valid tree traversal, and perform your operation on each node.
The question changed: And since you want this to operate on any node in the tree, just find the root first. It's much easier to write a tree traversal that progresses in one direction, than up and down the tree.
You've changed the question from deleting a tree, to deleting a subset of a tree. So, instead, let's do this. Remove the element from the tree first (remove_node). and then perform the same free that we would have done before.
void remove_node(node *self) {
if (self->previousSibling)
self->previousSibling->nextSibling = self->nextSibling;
if (self->nextSibling)
self->nextSibling->previousSibling = self->previousSibling;
if (self->parent && self->parent->firstChild == self)
self->parent->firstChild = self->nextSibling;
if (self->parent && self->parent->lastChild == self)
self->parent->lastChild = self->previousSibling;
}
void free_node(node *self) {
// Free one node. Perhaps this is:
free(self->name);
free(self->text);
free(self);
}
void iterate_nodes(node *root, void op(node *self) ) {
if (root == NULL)
return;
iterate_nodes(root->nextSibling, op);
iterate_nodes(root->firstChild, op);
op(root);
}
int main() {
node *node = NULL; // Some node in the tree...
remove_node(node);
iterate_nodes(node, free_node);
}
Use any of the standard tree-traversal mechanisms and delete all elements.
http://en.wikipedia.org/wiki/Tree_traversal
You can use a standard post-order tree traversal algorithms to free the whole tree. To make it work from any given node, just start by traversing all of the parent links to the root. For example:
void free_tree(node *n)
{
// Find the root node of the tree
while(n->parent)
n = n->parent;
free_tree_helper(n);
}
void free_tree_helper(node *n)
{
// Free all children of this node in post-order traversal
node *child = n->firstChild;
while(child)
{
// Save the next sibling pointer to avoid dangling pointers
node *next = child->nextSibling;
free_tree_helper(child);
child = next;
}
// All the children have been freed, now free the parent
free(n->name);
free(n->text);
free(n);
}
Alternatively, if you use a memory pool to allocate your tree nodes, all of your nodes come from the same pool, and the pool contains no other tree's nodes, you can instead just free the entire memory pool at once, saving you from having to traverse the entire tree. This will be much more efficient, since it avoids a lot of cache misses in a potentially large tree, and it also avoids certain memory fragmentation problems.
Okay so I have a Binary Search Tree built using only C structs and pointers because I'm insane and didn't want to use C++. Anyways, I've got some serious memory leaks since I'm assuming free(tree), tree being an instance of the struct below, doesn't free all the children of that tree.
Here is my node:
struct node{
struct node* parent;
struct node* left;
struct node* right;
int key; //the value of the node
};
and here is my bst:
struct bst{
struct node* root;
int elements; //number of nodes in the bst
};
So my question, is there any better way of doing this than recursively calling a delete function? for instance (writing this on the spot):
void delete_tree(struct node* n){
if(n == NULL) return;
struct node* left = n->left;
struct node* right = n->right;
free(n);
delete_tree(left);
delete_tree(right);
}
I see absolutely nothing wrong with a recursive delete. You could use an iterative approach, but it wouldn't have any discernible benefits and would be harder to write.
By the way, you can simplify the code a little and remove the two local variables as so:
void delete_tree(struct node* n){
if(n == NULL) return;
delete_tree(n->left);
delete_tree(n->right);
free(n);
}
You are making the recursive calls but never actually call free. You probably need to verify if a node is a leaf node (maybe asking if both children are null) and call free on that node.