I am trying to delete a binary tree, my program work as follows:
(1) It reads the number of nodes to be created in tree.
(2) It reads all those nodes.
(3) It print the tree formed by those nodes.
(4) It reads the node to be delete at terminal.
Until here everything works fine but when i try to delete the desired node then it gives segmentation fault error.
Note: I have to pass the root by reference only (thats why i have kept two pointers for root in delete_tree_node(int delete_val, node **root)).
My approach to do so is:
I call recursively the function delete_tree_node() by left and right child in order to traverse the tree until i get the value of node equal to the value the node which user wants to delete.And once if i get that place then i free() that node.
My code to achieve this is: (which gives segmentation problem):
delete_tree_node(int delete_val, node **root)//two "**" because i call by reference in function call
{
node*temp1;
temp1=(*root);
if(delete_val==(*root)->freq)
{
free((*root));
temp1=temp1->left;
(*root)=temp1;
}
if(delete_val<temp1->freq)
{
delete_tree_node(delete_val,&temp1->left);
}
if(delete_val>temp1->freq)
{
delete_tree_node(delete_val,&temp1->right);
}
}
It's function call is :
delete_tree_node(delete_val, & head);//I give reference
Could some one help me in knowing :
(1) Why it gives segmentation error.
(2) Is my logic is correct to delete the desired node ?, If not then could you please give me a piece of code to make as reference?
Why it gives segmentation fault?
Because you free the memory pointed by *root before you try to access the same memory in temp1->left.
Let's look at things closely :-
temp1 = (*root)
temp1 now holds the same memory address as (*root), i.e. both are some numbers that point to the same address. For the sake of clarity, let's assume that number to be '6'. So, both of them point to the memory address '6'. Note, they are not equal to the value at that address, but are just pointing to that.
Now, free((*root)); tells the system that you are freeing the memory location pointed to by (*root), which in this case is 6. Once you free the memory, you lose access permission to that memory and next time you request it (through temp1->left), you get the segmentation fault.
I hope that clarifies what is causing the segmentation fault.
A cursory glance tells me that you could fix this by freeing (*root) at the end. In fact, the recursive call would be clearer that way, since you can describe it through this pseudo-code :-
delete left subtree
delete right subtree
delete root
I will not delve into the correctness of the logic as it appears to be a homework problem, and it'd be advisable that you solve that part yourself.
temp1=(*root); // copying the memory address of node to temp1
free((*root)); // your freeing the memory here of the node
temp1=temp1->left; // the memory your accessing is already free'd hence segmentation fault occurs
try interchanging the two statements .
temp1=temp1->left;
free((*root));
regarding the reference for logic check here
You cannot free the node and then access it. Try to move the free after the temp1=temp1->left.
Also, you must return once you found the correct node or path (or use else if):
delete_tree_node(int delete_val, node **root)
{
node *temp1;
temp1 = *root;
if(delete_val == temp1->freq)
{
temp1 = temp1->left;
free(*root);
*root = temp1;
}
else if(delete_val < temp1->freq)
{
delete_tree_node(delete_val, &temp1->left);
}
else if(delete_val > temp1->freq)
{
delete_tree_node(delete_val, &temp1->right);
}
}
Related
I looked at this answer and I am sure I'm using it correctly but my while loop never ends.
My code recursivly removes the bottom level of the tree. At least I think it does. Here's the code:
void freeTree(node *tree){
printf("\n\n");
printf("Free Tree\n");//Start here #1
printf("%i\n", tree->number); //#2
if(!tree){//The tree is not null so continue
return;
}
while (tree)
{
if(tree->left){
printf("Going Left\n");// why does it go here at the end? #4
freeTree(tree->left);
} else if (tree->right)
{
printf("Going right\n");
freeTree(tree->right);
} else if (tree->right == NULL && tree->left == NULL)//Check if bottom of the tree
{
printf("Freed: %i\n", tree->number);// #3
tree = NULL;
free(tree);
}
}
}
My output in my terminal looks like this:
Free Tree
5
Freed: 5
Going Left
I don't understand how after freeing the node in my while loop it tries to free the node by Going Left in the console.
What am I missing or messing up here?
Let’s follow the steps of the while loop. First we check if the tree has a left node. Assuming it does we take pointer to the node and call the function on it. Then, assuming function finished successfully we skip other conditions and go through the loop again. This time the pointer to the left node is still there but the memory it points to is freed. That is our first bug – dangling pointer.
Second bug is the infinite loop. Because the condition never changes when in the loop (left node pointer stays set).
To mitigate both issues you should set the left node pointer to null right after calling the function on it.
Same would happen with the right node (assuming program does not get stuck on the left node.
And finally, if both nodes are null, the pointer to tree set to null leaving a memory leak. And then you call free on the null pointer (which is fine on it own).
Generally when working with tree-like structures one would either use recursion or a loop. Using both normally does not make much sense.
P.S.
An interesting fact. It is possible to fix this program by only removing code - the best kind of fix.
void freeTree(node *tree)
{
if(!tree) return;
freeTree(tree->left);
freeTree(tree->right);
free(tree);
}
I wrote this function in order to swap 2 nodes in a linked list, but the result is a Segmentation Fault. Can you check it? Thanks.
(I did typedef for struct student* as punt)
void swap_node(punt node1, punt node2)
{
node1->next=node2->next;
node2->next=node1;
node2->prev=node1->prev;
node1->prev=node2;
(node2->prev)->next=node2;
}
I guess this would be sufficient, basically the only difference from your code is the last statement (did not include null checks for simplicity):
void swap_node(punt node1, punt node2)
{
node1->next=node2->next;
node2->next=node1;
(node1->prev)->next=node2;
node2->prev=node1->prev;
node1->prev=node2;
(node1->next)->prev=node1;
}
When possible, two nodes are more easily swapped by only swapping their contents. The result is identical. This would pose a problem if somewhere else in your code you held a pointer to one of the nodes you swapped and are still expecting it to be the same node.
Anyway, back to your code. There are a few things that need refinement. Firstly, we need to check if node1 and node2 are not null and if they aren't we can proceed, otherwise exit the function as we can't swap this. The first 4 lines of your swapping code are alright, but here's two issues:
Node that was before node1 (prior to swapping) might be null, and thus accessing it's next pointer to point at node2 would result in undefined behaviour and likely crash. Check if it exists and then perform the assignment.
You forgot to check if there exists a node after node2 (prior to swapping) and if so, point it's prev pointer at node1
It usually helps to visualize the links in a doubly linked list, just draw it on a piece of paper. You'll notice 4 links per node:
node->next
node->next->prev
node->prev
node->prev->next
So to swap two unrelated nodes you need to swap the 4 links.
The following will not work:
node1->next=node2->next;
This overwrites the old value node1-> next. You need to use a temporary variable instead. Something like this:
#define SWAP_PTR(a,b) { void* tmp = b; b = a; a = tmp; }
void swap_node(punt node1, punt node2)
{
SWAP_PTR(node1->next, node2->next);
SWAP_PTR(node1->next->prev, node2->next->prev);
SWAP_PTR(node1->prev, node2->prev);
SWAP_PTR(node1->prev->next, node2->prev->next);
}
Note - in a threaded environment you'll need some form of locking.
i make a function to print an BTree in level order none recursive way.
and i have a problem to find my mistake.. the following problem showing up.
Run-Time Check Failure #2 - Stack around the variable 'pq' was corrupted.
if some one can tell where is the problem is, or how i can find it by my self next time...?
i add the full project if is needed.
enter link description here
void PrintTreeLevelOrder(bstree tree){ //The problem some where here.....
queue *pq = (queue*)malloc(sizeof(queue)); // is struct of : *front, *rear
node *current;// is struct of : root
create_queue(&pq);//create queue- items_num = 0,front = NULL,rear = NULL
if (tree.root == NULL) {
printf("Your Tree Is Empty:\n");
return;
}
current = tree.root;
enqueue(current, &pq);
printf("Your Tree Displayed As Queue:\n");
while ((size_of_queue(&pq) )!=0) {
current = pq->front;
printf("%d ", current->data);
if (current->left != NULL)
enqueue(current->left, &pq);
if (current->right)
enqueue(current->right, &pq);
dequeue(&pq, ¤t);
}
}
First of all, I want to say that your algorithm is correct, please read the below.
Your code has multiple mistakes that should take care of
You used the pq functions in a wrong way, you passed a pointer to a pointer instead of the original pointer, so you overwrote the code
Create_queue should allocate unless you call it init but that's not the main issue
You should check if create_queue succeeded
You are saving addresses in the queue which are queue* as int which is wrong and not portable for an architecture different than 32bit
you are assigning current which is a node (node tree struct) a queue_element element pointer struct, which is also not correct because they are different types and architectures
Please work on these points, if you want more details please contact me
I would be happy to help
FINAL EDIT
My function that frees the memory works properly, and as milevyo has suggested, the problem lies in node creation, which I had fixed. I now have a separate problem where the program segfaults when run normally, but it cannot be reproduced in gdb or valgrind. However, that is a separate question altogether.
I have since found out that this segfault happened because I did not check for the EOF character properly. As per Cliff B's answer in this question, the check for EOF happens only after the last character in the file. As a result, in my function that loads the dictionary file, I had assigned the last character of the file to some i (which in this case was -1 according to a printf call), and tried to create and access a child node if index -1. This caused a segmentation fault, and also caused problems with my unload function, which would not unload the very last node I created.
As to why the segmentation fault does not appear when I run the program in gdb or valgrind, I have no idea.
EDIT 3
While stepping through my load function where the node creation happens, I notice an unexpected behaviour. I believe the problem lies somewhere in these lines of code, which are embedded within a for loop. The casting to (node*) is just to be safe, though it does not affect the running of the code to my knowledge.
// if node doesnt exist, calloc one, go to node
if (current_node->children[i] == NULL)
{
current_node->children[i] = (node*) calloc(1, sizeof(node));
nodes++;
}
current_node = current_node->children[i];
While stepping through the load function, I see that my current_node->children[i] seem to be calloc'ed properly (all children set to NULL), but the moment I step into current_node->children[i] and examine its children (see image below), I see that the addresses get screwed up. Specifically, the i'th child in the children node gets set to 0x0 for some reason. While 0x0 is supposed to be equal to NULL (correct me if I'm wrong), my free_all function seems to want to go into the 0x0 pointer, which of course results in a segfault. Can anyone shed light on how this might happen?
Values of children[i]
EDIT 2: I'm using calloc to create my nodes
root = calloc(1, sizeof(node));
For my child nodes, they are created within a for loop where I iterate over characters of the dictionary file I'm reading in.
if (current_node->children[i] == NULL)
{
current_node->children[i] = calloc(1, sizeof(node));
nodes++;
}
c in this case represents the character of the word being read in. I get i using the following:
if (c == '\'')
i = 26;
else if (isalpha(c))
i = c - 97;
EDIT: I'm thinking that something in my node creation is faulty, as milevyo suggested. This is because if I print out the addresses, it goes from 0x603250 to 0x603340 to 0x603430 to 0x603520, then finally to (nil), before it segfaults. I have verified that the root node gets passed in correctly by printing out its value in gdb. I'll try to figure it out.
ORIGINAL QUESTION
I'm running into a segfault when trying to free a recursive struct, but cannot figure out why, and would like some help.
My struct is defined as follows:
typedef struct node
{
bool is_word;
struct node* children[27];
}
node;
This is meant to implement a trie structure in which to load a dictionary into, for purposes of a spellcheck. After the spellcheck is done, I need to free the memory that I've allocated to the trie.
This is my current function which should free the trie when passed the root node, but it segfaults when doing so, though not immediately:
void free_all(node* curs)
{
int i;
// recursive case (go to end of trie)
for (i = 0; i < 27; i++)
{
if (curs->children[i] != NULL)
{
free_all(curs->children[i]);
}
}
// base case
free(curs);
}
Where could I have gone wrong? If more information is needed, please let me know.
i think, root node is faulty ( maybe it is null). if not, look elsewhere. in node creation for example.
void free_all(node* curs)
{
int i;
if(!curs) return; // safe guard including root node.
// recursive case (go to end of trie)
for (i = 0; i < 27; i++)
free_all(curs->children[i]);
// base case
free(curs);
}
The free_all function is ok. You have to check you set to NULL all children not allocated. This includes nodes that are not leaves, but don't have all the 27 children.
If that is ok, or fixing it doesn't fix the segfault, you have to debug.
I got a binary tree playing the game to guess the user's guess.
All worked fine until I tried to free the binary tree.
I used the valgrind to check, they give me these:
==8205== Invalid read of size 8
==8205== at 0x400F0A: treePrint (in /home/mbax4nc2/COMP26120/ex6/pangolin)
==8205== by 0x400A14: main (in /home/mbax4nc2/COMP26120/ex6/pangolin)
==8205== Address 0x4c334a8 is 200 bytes inside a block of size 216 free'd
==8205== at 0x4A06430: free (vg_replace_malloc.c:446)
==8205== by 0x400DEE: freeTree (in /home/mbax4nc2/COMP26120/ex6/pangolin)
==8205== by 0x400A08: main (in /home/mbax4nc2/COMP26120/ex6/pangolin)
typedef struct node{
char name[100];
char question[100];
struct node *yes;
struct node *no;
}node;
void freeTree(node *root)
{ //Tree's root note is passed as argument
if (root == NULL)
{
return;
}
if (root->no != NULL)
{
freeTree(root->no);
root->no = NULL;
}
if (root->yes != NULL)
{
freeTree(root->yes);
root->yes = NULL;
}
free(root);
return;
}
I didn't paste all my program in here, because it was really a long version. What's wrong with my free() function? How could I debug it? I didn't know how to use the valgrind record to fix my program.
To debug dynamic memory management: Count all calls to malloc(), calloc(), realloc(NULL, ...) and strdup(), sum them up and then count all calls to free(), excluding calls to free(NULL). The former and the later count shall match, if the don't you found a bug.
Just as a note: If the two counts mentioned above match, this does not mean memory management is done correctly.
just simple as this:
void freeTree(node *root)
{
if (!root )
return;
freeTree(root->no);
freeTree(root->yes);
free(root);
return;
}
It looks to me like the error may have been caused not by the free function but somewhere else in the code. Your free function looks ok to me even though it could be simpler like in milevyo's answer. If I had to guess I would say that you are not correctly initializing the yes and no pointers to null. By default they will point to some invalid memory. You need to set them to null any time you add a new node. It would help if you posted the rest of the code.
Actually I just looked at the comments and you said you called print after calling free. This should work so long as you set the root node to null after calling freeTree (assuming your print function correctly handles empty null trees). I notice that this function will not change the root node even though it frees it. The free function does not change the value of a pointer and that pointer will still point to the same location. I always set pointers to null after freeing them just to be safe.