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);
}
Related
This is a push function to enter data into a binary tree. It is causing a segmentation fault on the third call. Check out the code for more.
void push(){
int data;
printf("enter the data you want to enter");
scanf("%d",&data);
struct bst* temp;
temp=(struct bst*)malloc(sizeof(struct bst*));
temp->data=data;
if(root==NULL){
temp->right=NULL;
temp->left=NULL;
root=temp;
}else{
struct bst* p;
p=root;
while(p->left!=NULL || p->right!=NULL){
if(data<<p->data){
p=p->left;
}else{
p=p->right;
}
}
if(data>>p->data){
temp->left=NULL;
temp->right=NULL;
p->right=temp;
}else{
temp->left=NULL;
temp->right=NULL;
p->left=temp;
}
}
}
When you are traversing the tree, you are using p->left!= NULL OR p->right!= NULL condition. In this case if your tree's left is not NULL in this case you are assigning NULL to p. Then you are comparing data with NULL variable data. This causes to segmentation fault. You need to add AND statement instead of OR to the while condition:
while(p->left!=NULL && p->right!=NULL){
Also in this line if(data>>p->data){ you are using right shift operator instead of greater operator. You should type it correctly.
There are numerous problems with the code presented, some of which have been presented in comments and in another answer. Among these are
You do not allocate enough space for each node (per #EddInglis). As a result, you write outside the bounds of the allocated object when you set one or more of its members, thus producing undefined behavior. This is likely the source of the segfaults. As an associated but secondary matter, in C, you do not need to explicitly convert values of type void * to other object pointer types for assignment, and as a matter of style and good programming practice, you should not do so.
Your conditional logic for traversing the tree is incorrect (per #hhusein). The condition p->left!=NULL || p->right!=NULL holds for all nodes that are not leaves, but you need also to accommodate the case of internal nodes that have only one child. This probably is not the cause of the segfault, though. It is just prone to losing data and leaking memory.
Your conditional logic for choosing which direction to move in the tree is incorrect:
if(data<<p->data){
...
if(data>>p->data){
The << and >> operators compute bitwise left and right shifts. You are looking for relational operators instead (< and >). This is not responsible for your segfault, but it will cause the resulting binary tree to fail to be a binary search tree. The nodes will be arranged incorrectly in most cases.
There are three typos in your code,
Your malloc is allocating size of pointer than a node. i.e malloc(sizeof(struct bst))
if(data<<p->data) is left shifting data than comparing. Replace to just comparison if(data < p->data)
if(data>>p->data) is right shift operator and you need if(data>p->data)
Apart from the typos, logic to find the right place holder for new created node has to be fixed.
temp->left= NULL;
temp->right= NULL;
while(p){
if(data < p->data){
if(!p->left) {
p->left = temp;
break;
}
p=p->left;
}else if(data > p->data) {
if(!p->right) {
p->right = temp;
break;
}
p=p->right;
}else{
//Skip insertion for same key
break;
}
}
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 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);
}
}
So here's my code for destroying a linked list.
void destroy(node *h){
if (h->next!=NULL){
destroy(h->next);
}
free(h);
h=NULL;
}
The problem is that printing still outputs a bunch of numbers:
11, 2, 15, 3, 9, //Before Destroy
28495936, 28495968, 28496064, 28496096, 0, //After Destroy
Unfortunately I cannot alter the void destroy(node *h) parameters due to assignment reasons.
I've tried using a while loop method but I still get the same result. I've also tried shifting to the left and deleting from the end but then I wouldn't be able to delete the last node.
thanks in advance.
--edit---
as requested, here is the print function
void print(node* N){
printf("%d, ", N->value);
if (N->next)
print_set(N->next);
if (N == NULL)
printf("Empty Set");
}
You must set h->next = NULL. Also, after the call to destroy, make sure you don't use the pointer anymore because it is freed. So, always after destroy(n), make sure that you have n = NULL.
A better way is probably to change the signature to void destroy(node **h), so the code becomes:
void destroy(node **h){
if ((*h)->next!=NULL){
destroy(&h->next);
}
free(*h);
*h=NULL;
}
Then you ensures that you are not using the pointer afterwards.
In your print function, you must add this check at the beginning:
if(N == NULL) return;
If the solution provided by Albert is not possible due to some rules, the only possibility you as the author of the source in question have is to remember the list's nodes had been deallocated and therefore contain invalid references to memory and that the code you write because of the latter may not dereference such pointers, that is they may not be passed to the printing functions as this would provoke undefined behaviour by accessing un/deallocated memory.
If writing such potential insecure code, it is in your responsibilty as the author to use it carefully and document it very well for your fellow programmers maintaining the code after you left the project.
The problem here is that h=null in your function does not do anything. You're modifying a local parameter so it won't have any effect outside the function.
Thus, the only thing you do is freeing the memory, but you keep the address the same. Your list still exists, pointing to random memory location (well not random : the same as before, but the values at this memory locations are random)
When you print your list after that (which is strange because you're supposed to have destroyed it... Why would you want to print it again ?), you print random values in memory.
This is a problem because your program could also crash (you're accessing memory which is not allocated).
The solution, unfortunately, requires to change the signature of your function :
void destroy(node **h){
if ((*h)->next!=NULL){
destroy((*h)->next);
}
free(*h);
*h=NULL;
}
If you can't, you have to set the pointer to NULL after destroying it, like this:
void destroy(node *h){
if (h->next!=NULL){
destroy(h->next);
h->next=NULL;
}
free(h);
}
and in the calling function:
destroy(myList);
myList=NULL;
The problem is probably in code you haven't posted!
I assume you keep a 'head' pointer to your list, and your code looks like this.
Node * myList;
.. do stuff..
destroy(myList);
print(myList);
The problem is that you don't set myList = NULL following the destroy.
destroy(myList);
myList = NULL;
print(myList);
Your h=NULL in destroy() doesn't do anything because it's modifying a local parameter.
I don't know what your structure looks like, but I'm guessing something like this:
struct {
int something;
int* value;
list* next;
}
The problem is that even though h is the NULL pointer, h->value and h->next are not. They are pointers in NULL+1 and NULL+2, which may point to random places in memory.
Try this code if u are working on singly linked list
void destroy(node *h){
node *n;
node *p; \\ variable to store previous term
n=h;
while(n->next!=NULL){
p = n;
}
p->next=NULL;
free(n);
}
I was reading about a few basic operations on linked list and I saw two types of loops being used predominantly
struct node {
int data;
struct node *next;
}*start=NULL,*tmp;
The first loop was of the form
for(tmp=start;tmp->next!=NULL;tmp=tmp->next);
Using the above loop, now the tmp pointer points towards the last node in the list
The second loop was of the form
tmp=start;
while(tmp!=NULL)
{
// do something
}
I think that both of them do the same work, but I'm not sure. Is there any difference?
I suppose your while loop is something like this.
temp=start;
while(temp!=NULL)
{
// do something
temp= temp->next;
}
In your code of for loop, When you are out of the for loop, temp is not pointing to NULL. temp is pointing to end of the linked list. But in case of while loop, your temp is pointing to NULL after you exit the while loop and you don't have tail(Unless you assign temp to any other temporary variable to change the logic of program) with you if you want to use it in the further steps. That is the only difference. Except that there isn't much difference.
You could have checked it by writing a small program and printing the results. I recommend you do it.
The loops aren't identical. In fact, your for loop has a problem. Consider what happens when start==NULL before you enter the for loop.
for(tmp=start;tmp->next!=NULL;tmp=tmp->next);
You assign start to tmp and then dereference tmp, a NULL pointer. I think you want the following instead.
for(tmp=start;tmp!=NULL;tmp=tmp->next);
That change makes the for and while loops the same.
Q: Effectively, "no". There isn't any substantive difference; they both do the same work.
You can always code a "for()" loop with an equivalent "while()".
I use while loop when I need to change the linked list. For e.g.
while (root->next)
{
if(0 == strcmp(root->data,root->next->data))
{
temp = root;
root = root->next;
free(temp)
}
else
{
root = root->next;
}
}
I use for loop when I need a read only access to linked list.