How to free recursive struct (trie) - c

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.

Related

Run time Error- c project

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, &current);
}
}
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

C Value of initialised variable changes by itself after comparison

I am implementing a simple tree structure in C. The program showed some strange behaviour, and I was able to narrow it down to a place, where value stored in a memory location and accessed by using pointers unexpectedly changes. It is replicable, but only happens after a few runs (depending deterministically on the input) of a recursive function. It is in somewhere in the header of 'while' statement. I have checked that just before 'while' all pointers point to memory cells that have expected, well-defined etc. content. What bugs me most, is that even if I assign copy of the value to another variable that variable changes too. I have no idea how it is possible, though I suspect there's something obvious I'm missing. Below are relevant code fragments.
typedef struct _Node {
int root;
struct _Node *children;
struct _Node *next;
struct _Node *previous;
} Node;
int delete_subtree_aux(Node *n) {
Node *children = get_children(n);
int i = children->root;
int j = i;
// At this point i and j both equal e.g. -4
while (!(children->next->root == children->root)) {
i = children->root;
// At this point i equals -3
assert(i == j);
// And j equals -3 too!
delete_subtree_aux(get_first(children));
}
free_node(children);
}
All help is greatly appreciated!
Edit:
After setting additional breakpoint at free_node(children); I have noticed that something is off with the order of instructions executed. At one time program goes straight from free_node(children); to the inside of the loop bypassing while condition checking. 'n', 'i', 'j' and 'children' change together and correspond to different function inputs. Setting data breakpoints revealed that different 'j's are at two different memory addresses.
It seems to me, like for some reason that a few instances of this function are somehow executed in paralell, but that's not my intention. My follow-up question is, can freeing memory in such conditions cause errors? If yes, what should I do to fix it?
Edit 2:
Source for other functions called in the code above:
int free_node(Node *n) {
free(n);
}
Node *get_children(Node *n) {
return n->children;
}
Node *get_first(Node *list) {
return list->next;
}
The problem was that when get_first(children) == get_last(children) the while loop should have its last iteration. However, delete_subtree_aux fails to update where children->next points to. When children of the node at this address are free'd, the while loop instead of stopping, tries to do one more iteration (since children->next points to some Node-like garbage in memory that is different to children). This time however, it tries to access free'd children, and that of course causes error.
The mysterious changing of 'i', 'j', 'children', and 'n' between before while and inside were a result of viewing different levels of recursive function on the stack, as pointed out by #Holsety in the comments.

i can't free binary tree correctly, how could i debug it?

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.

deletion of a node in binary tree passing node by reference only

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);
}
}

Destroying a Linked list in C

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);
}

Resources