I have written a binary search tree, it works fine but I'm not sure whether my program frees all the memories.
here is my definition of the node of a tree
typedef struct node {
int val;
struct node *left, *right;
} nodeOfTree;
I write this function to output the result and free all the nodes, it seems that the answer is right but the memories are not freed.
void outputAndDestroyTree(nodeOfTree *root) {
if (!root) {return;}
outputAndDestroyTree(root->left);
printf("%d ", root->val);
outputAndDestroyTree(root->right);
free(root); // I free this pointer, but after doing that, I can still access this pointer in the main() function
}
Is that mean I can not free a piece of memories in the recursive function? Thank you ~~~~~
Update: Thank you all~
Your code seems okay, but freeing the allocated memory won't magically set it's reference pointer to NULL. Since you didn't set a new value to the pointer, the old address will remain there, untouched. Maybe you can even read from it without crashing, despite it being undefined behavior.
If you want it to be set to NULL after freeing the memory, then just do so. Call outputAndDestroyTree(root->left); then do root->left = NULL;.
Related
I have some issues, maybe coming from a misunderstanding of how the function "free" works.
Basically I have defined a structure like this
typedef char parola[11]
typedef struct _node node
struct _node
{
parola wrd;
node *padre;
node *Ts;
node *Td;
};
Later in the code I allocate memory for a node using malloc:
node *r
r = (node *) malloc(sizeof(node));
And i create binary search trees allocating memory for every single node in this way.
When I try to remove a node in a bst, I pass a pointer to that node *n. I think I nail the recursive procedure, but then when it comes to using free() on the pointer to the node, that doesn't seem to work. I am sure of it because if I try to print "parola" in the node, it does actually print the word that was contained there after deallocating the memory.
node *n
.../*in another function*/
free (n)
printf("%s\n",n->wrd)
/*This does print the word inside the node after the deallocation*/
What am I missing here? Do i need to use free() in a different way?
Thanks for your help.
In C, free doesn't wipe the data. It just says "I'm not using it any more; you can use it for something else." If nothing needs to use it in that time, it won't be overwritten.
However, you can't guarantee that it won't be overwritten. Using stuff after it's freed is an excellent way to have your program suddenly, unpredictably fail at the worst possible moment.
(Make sure you free the node(s) you're pointing to before you throw away (or free) their last pointer(s), and make sure you only free each thing once!)
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.
I have created a program based on a linked-list where every node is a struct that holds an 8-byte integer and a pointer to the next node. The queue follows FIFO. It seems to work fine but I suspect the program could suffer from some kind of memory-leak or memory fragmentation in the heap. I may be wrong - hopefully!!! When a node is deleted in FIFO-order I use the library function free where I put the pointer of that node. I also set the pointer to the first and last node to NULL when the linked-list is empty.
But there is a thing that I do not understand and could be sign of a memory-leak.
Let say I create 3 nodes that holds 3 integers. The memoryaddresses of these nodes is as follows:
205888
206032
206056
Now I decide to delete these nodes and free resources to these three nodes.
And when I startover to add nodes - the first node do not start at address 205888, it starts at address 206056.
Does this reveal a memory-leak in my program?
Here is the function the destroy the node. It takes as argument the address to nodes that is to be deleted
static int destroy_node(node *node_ref) {
int data = 0;
data = node_ref->data;
free(node_ref);
return data;
}
and the struct
typedef struct node {
int data;
struct node *next;
} node;
If you free an area of memory, you cannot be sure what will be allocated for you next. So this behaviour basically does not show a memory leak.
There may be a memory leak in your code but you can not detect it using address of the allocated node.
To detect memory leak in your code you need tools like Valgrind
It would depend on the algorithm in the heap. Strictly speaking, this is "indeterminant" and out of your control. It could be a sign, but it's not evidence.
Here's the task. It is given a linked list, free all the memory and set head to NULL.
This is my function:
void free_list(struct Node *node)
{
while (node)
{
free(node);
node=node->next;
}
}
It outputs no error, just wont do anything. And another thing, how to check if the memory was freed ?
Hints at what's going wrong rather than sample code since this is homework...
You can't reliably access node after freeing it. Store the value of node->next before freeing.
You're passing the Node pointer by value. If you want to NULL the caller's pointer, use a pointer to a pointer instead.
There is no portable way to check the memory was freed, but you could investigate tools like valgrind if you want to check that no memory has been leaked when your program exits.
Note that you can't check the contents of memory locations to reassure yourself that the memory has been freed. Calling free merely passes ownership of the memory back to the system; it may get reallocated (and its values updated) at any point in future.
You should get the next node before freeing the current one
If you want to assign to the head, you need to pass its address to the function.
void free_list(struct Node **head)
{
struct node *nnode, *cnode;
cnode = *head;
while (cnode)
{
nnode = cnode->next;
free(cnode);
cnode = nnode;
}
*head = NULL;
}
call it like this..,,
free_list(&head);
EDIT:
You are accessing the same node node=node->next; after freeing it, You must have to store next pointer before freeing the node.
If I have a snippit of my program like this:
struct Node *node;
while(...){
node = malloc(100);
//do stuff with node
}
This means that every time I loop through the while loop I newly allocate 100 bytes that is pointed to by the node pointer right?
If this is true, then how do I free up all the memory that I have made with all the loops if I only have a pointer left pointing to the last malloc that happened?
Thanks!
Please allocate exactly the size you need: malloc(sizeof *node); -- if you move to a 64-bit platform that doubles the size of all your members, your old 96-byte structure might take 192 bytes in the new environment.
If you don't have any pointers to any of the struct Nodes you have created, then I don't think you should be allocating them with malloc(3) in the first place. malloc(3) is best if your application requires the data to persist outside the calling scope of the current function. I expect that you could re-write your function like this:
struct Node node;
while(...){
//do stuff with node
}
or
while(...){
struct Node node;
//do stuff with node
}
depending if you want access to the last node (the first version) or not (the second version).
Of course, if you actually need those structures outside this piece of code, then you need to store references to them somewhere. Add them to a global list keeping track of struct Node objects, or add each one to the next pointer of the previous struct Node, or add each one to a corresponding struct User that refers to them, whatever is best for your application.
If you set node = NULL before the loop and then use free(node) before node = malloc(100) you should be OK. You will also need to do a free(node) after the loop exits. But then again, it all depends on what "//do stuff with node" actually does. As others have pointed out, malloc(100) is not a good idea. What I would use is malloc(sizeof(*node)). That way, if the type of node changes, you don't have to change the malloc line.
If you don't need the malloc'ed space at the end of one iteration anymore, you should free it right away.
To keep track of the allocated nodes you could save them in a dynamically growing list:
#include <stdlib.h>
int main() {
int i;
void *node;
int prt_len = 0;
void **ptrs = NULL;
for (i = 0; i < 10; i++) {
node = malloc(100);
ptrs = realloc(ptrs, sizeof(void*) * ++prt_len);
ptrs[prt_len-1] = node;
/* code */
}
for (i = 0; i < prt_len; i++) {
free(ptrs[i]);
}
free(ptrs);
return 0;
}
Note: You should probably re-think your algorithm if you need to employ such methods!
Otherwise see sarnold's answer.
then how do I free up all the memory that I have made with all the loops if I only have a pointer left pointing to the last malloc that happened?
You can't. You just created a giant memory leak.
You have to keep track of every chunk of memory you malloc() and free() it when you're done using it.
You can not. You need to store all the pointer to free the memory. if you are saving those pointer somewhere then only you can free the memory.