Freeing a pointer to structure containing an array - c

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!)

Related

Does the struct get freed this way in C?

I have the following struct which I use to implement a priority queue
struct q_element
{
//Declaration of struct members
int element;
int priority;
struct q_element *next_element;
};
and I use a pointer to a struct 'cur' to start from the first item in the queue
struct q_element* cur = start_element;
and keep moving until I find the one I want to delete from list.
while (cur->priority!=max_priority)
cur = cur->next_element;
Does the following line of code actually free the struct? Because 'cur' is a pointer to the struct I wasn't completely sure.
free(cur);
You need to pass a pointer to free, so free(cur) is the way to go, assuming that the struct itself has been allocated using malloc/calloc/realloc. Specifically, if you allocated your curr in the automatic memory (i.e. on the stack) you are not supposed to call free on it.
It looks like q_element is part of a linked list. Freeing the struct itself will not free other structs pointed to by it, so if you'd like to free the struct along with its tail, you need to write a loop.
Finally, when you free memory pointed to by some pointer in your program, it is a very good idea to assign NULL to the pointer that you freed to avoid accidental double-freeing and undefined behavior on accessing freed memory.

Memoryleak or not - linked list

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.

Returning a pointer or a reference in C

Having the following,
struct node{
int value;
struct node *next;
};
typedef struct node Node;
typedef struct node *pNode;
Node newNode(){
Node n;
n.value = 5;
return n;
}
pNode newpNode(){
pNode pn = (pNode) malloc(sizeof(Node));
pn->value = 6;
return pn;
}
I read somewhere that if memory deallocation is to be done by the caller function, I should use newpNode(), and otherwise use newNode(), but that does not help me understand quite enough.
Can you give me some concrete examples of when should I use newNode() and when newpNode()?
Edit: forgot pn inside newpNode()
In this simple example, there is no strong need to use one over the other.
When you call newNode(), memory is allocated when the function is called to store the size of a Node to be returned from the call (on the call stack). This memory can be assigned to a variable and you will keep it around (the memory on the call stack will be memcpy'd into your local variable):
Node n = newNode();
However, as a Node gets more complicated, you will run into problems. For example, if you have nested data structures, these won't get copied along and could be destroyed as newNode() cleans up.
Also, as the memory required for Node gets larger (i.e. more fields), it will take more and more memory on the stack to make these calls. This can limit things such as recursion, or just general efficiency.
To deal with these limitations, you allocate memory on the heap in newPNode(); This always returns a pointer, regardless of the size of Node. However, you have to make sure you explicitly clean up this memory later, or you will have a memory leak.

How to free a binary tree using C?

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;.

Basic Malloc/Free

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.

Resources