Will this C recursive struct deallocate properly? - c

Suppose I have a standard linked list struct as follows:
struct Linked {
int data;
Linked* next;
}
I make a bunch of them in a loop by callocing the next pointer enough memory to store another Linked and initializing it. As per the norm with linked lists, I only maintain a pointer to the first node as follows:
struct Linked *first = make_list();
Now, I want to deallocate the memory held by the entire list. Can I call
free(first);
and have it release all the memory (including the memory allocated to all the next pointers), or do I have to do the deallocation from the end backwards?

There has to be one call to free() for each call to calloc(). So, you need to use a loop to free every element of your list in turn. You can choose to do the freeing backwards or forwards, but you'll probably find that forwards is easier:
void freelist(struct Linked *head)
{
while (head != NULL) {
struct Linked *tmp = head;
head = head->next;
free(tmp);
}
}
Note (and this is important) that you must read the value of head->next before freeing the node.

Related

what does this free list recursive function of a linked list do?

i want to know why the free list is a recursive function and what is doing
typedef struct listint_s
{
char *a;
char *b;
struct listint_s *next;
} listint_t;
void free_list(listint_t *head)
{
if (head)
{
if (head->next)
free_list(head->next);
free(head->a);
free(head);
}
}
This is freeing all the nodes in the list, and also what they point to from their a members (but not the b members).
The recursive calls first step through the list nodes until it reaches a node whose head->next element is NULL.
Within each recursive call, head points to the current element. After the recursive call returns, it frees what head->a points to and then frees the current element with free(head);.
The test if (head->next) is redundant, since free_list() checks whether it's called on a null pointer with if (head).
Most people write this kind of loop iteratively rather than recursively, as you could get a stack overflow when trying to free a really long list.
while (head) {
free(head->a);
listint_s *temp = head;
head = head->next;
free(temp);
}
The recursion here is used to call free on every element of the list. The first call to free_list is to process the head node. The second call operates on head->next, and so on. Note the input node is only freed after calling free_list(head->next). If this was not the case, the linked list would not be able to free the elements following head.
The same thing could be accomplished using a while loop instead of the recursion:
{
listint_t *next;
while (head)
{
next = head->next;
free(head);
head = next;
}
return;
}
If you want to know what free() itself does, check out How malloc and free work. As to free_list():
It is a recursive function because the structure of a linked list (which listin_s is) is recursive. I.e. *next is itself a listint_s. Therefore, it lends itself to being operated on recursively. Just was we can define the struct as "a thing containing two char*, and a pointer to the rest of the list", we can define the operation of freeing as "free the rest of the list, then free this thing which has two char* and a pointer to the rest of the list". Annotated:
void free_list(listint_t *head)
{
if (head) // If this thing is not null
{
if (head->next) // If the rest of the list is not null (i.e. we have not reached the end of the list yet)
free_list(head->next); // Free the rest of the list
free(head->a); // Then, free the thing pointed to by *a (note for some reason we are not freeing b?)
free(head); // Then, free this thing
}
}

confused over the usage of free () in C

This is done by someone who is better in C programming than me.
confused over the usage of free () in C
below is the struct of linked list
typedef struct node {
int value;
struct node *next;
} ListNode;
typedef struct list {
ListNode *head;
} LinkedList;
after created a list with some nodes
his code does this when exit
void deleteList(LinkedList *ll) {
if (ll != NULL) {
ListNode *temp;
while (ll->head) {
temp = ll->head;
ll->head = temp->next;
free(temp);
}
free(ll);
}
}
The above is what I don't understand. Why he needs to create such complexity, why not just do free(ll).
Please help
thanks in advance.
Linked list is made up of individual objects that happen to point at each other. If you want to delete a list you have to delete all of its nodes. free() won't do that. It doesn't know that these objects make up a list. It doesn't even know that these objects contain pointers to anything. Therefore you need to iterate over the list and free each node by hand.
if you have a linked list, suposse that every "*" is a node.
0 1 2 3 4
head--> *--*--*--*--*
the first *, es the head, is you just do "free ll"
this will be on the memory
0 1 2 3 4
head-->nul *--*--*--*
the problem here, is, all the "memory" that you ask for those nodes will still be there, and now you can't know where is it (you have nothing poiting to that memory) for every malloc you need a free (not 100% true, but for simple things work).
What that algorithm do is:
get the reference to the next node (if you don't do this and you free the node, you won't be able to get the "next" node, becouse head will be pointing to nothing ).
free the head.
make head point to the reference that you get before.
You can do with the following struct alone
typedef struct node {
int value;
struct node *next;
} ListNode;
But every time you have to declare a global variable struct node *HEAD. In a bigger program it may confuse you. The author has done this so that you can create a linked list like a variable. Every time you have to create a new linked list all you have to do is declare
LinkedList *ll;
When there are two struct, one has to free the objects of both the struct.
That's because each pointer points to a memory location. You need to free all memory locations that were previously allocated. free(ll) would only remove the node pointed to by the ll pointer.

Using free on a C struct

I have a simple Linked List node as follows
typedef struct node {
void *data;
struct ListElement *next;
} node;
Also I have a node create and delete function as follows:
void createNode(void *data){
node *n = malloc(sizeof(node));
//assign data to data and initialize pointer to NULL
}
void deleteNode(List *list, Node *node){
//Take care of the next pointer
free(node);
}
When I free the node, do I have to delete the members of the struct (data and next pointer) as well? Since I am not using malloc specifically for the members, but only for the entire struct? If so then how do I do it? Will all the members of the node be placed on the heap, and the stack will not be used at all?
The ultimate rule: you free() exactly the same number of times you malloc() (or calloc(), or...)
So:
I. If the data points to something allocated by these functions, then yes, you need to do so.
II. node->next is to be freed of course (assuming you are freeing the entire list), so you need to free it anyway, but only after you have taken care of the next element.
An iterative solution:
void free_list(Node *list)
{
while (list != NULL) {
Node *p = list->next;
// maybe:
// free(list->data);
free(list);
list = p;
}
}
A recursive solution:
void free_list(Node *list)
{
if (list->next != NULL) {
free_list(list->next);
}
// free(list->data);
free(list);
}
Usually, you will need to also free the data member, and you have to do that before freeing node,
free(node->data);
free(node);
but you don't need to free node->next, since either you want to keep the remainder of the list, or you free the entire list, and then freeing the next is done in the next iteration of the loop.
You must not free node->data if that doesn't point to allocated (with malloc or the like) memory, but that is a rare situation.
data is not a variable, it's a member of struct node. If you dynamically allocate struct node with a call to malloc(), you get a chunk of memory large enough to hold all the members of the struct. This obviously includes the storage for the data pointer, but not for the contents the pointer points to. Consequently, the storage for struct members must not be freed separately, it is enough to free the struct.
However, since data is itself a pointer, there is no telling where the memory it points to and whether this memory needs to be freed until we see how it is initialized.

Delete Linked List Function

Here's my function to delete a linked list:
void deleteList( NODE* head )
{
NODE* temp1;
NODE* tempNext;
temp1 = head;
tempNext = NULL;
while( temp1 != NULL )
{
tempNext = temp1->next;
free(temp1);
temp1 = tempNext;
}
}
So temp1 first points where the head pointer is pointing. If it isn't NULL, tempNext will be set to point to the next element of the list. Then the first element (temp1) is free'd, and temp1 is reassigned to point to where tempNext is pointing and process repeats.
Is this the right approach to deleting an entire list?
I ask this because when I print the list after using this function, it still prints the list. And IIRC freeing something doesn't delete it but only marks it as available so I'm not sure how to tell if this is correct or not.
Your code looks correct.
You're also correct that freeing a list's elements doesn't immediately change the memory they pointed to. It just returns the memory to the heap manager which may reallocate it in future.
If you want to make sure that client code doesn't continue to use a freed list, you could change deleteList to also NULL their NODE pointer:
void deleteList( NODE** head )
{
NODE* temp1 = *head;
/* your code as before */
*head = NULL;
}
It still print the list, because you probably don't set the head pointer to NULL after calling this function.
I ask this because when I print the list after using this function, it still prints the list.
There is a difference between freeing a pointer and invalidating a pointer. If you free your whole linked list and the head, it means that you no longer "own" the memory at the locations that head and all the next pointers point to. Thus you can't garintee what values will be there, or that the memory is valid.
However, the odds are pretty good that if you don't touch anything after freeing your linked list, you'll still be able to traverse it and print the values.
struct node{
int i;
struct node * next;
};
...
struct node * head = NULL;
head = malloc(sizeof(struct node));
head->i = 5;
head->next = NULL;
free(head);
printf("%d\n", head->i); // The odds are pretty good you'll see "5" here
You should always free your pointer, then directly set it to NULL because in the above code, while the comment is true. It's also dangerous to make any assumptions about how head will react/contain after you've called free().
This is a pretty old question, but maybe it'll help someone performing a search on the topic.
This is what I recently wrote to completely delete a singly-linked list. I see a lot of people who have heartburn over recursive algorithms involving large lists, for fear of running out of stack space. So here is an iterative version.
Just pass in the "head" pointer and the function takes care of the rest...
struct Node {
int i;
struct Node *next;
};
void DeleteList(struct Node *Head) {
struct Node *p_ptr;
p_ptr = Head;
while (p_ptr->next != NULL) {
p_ptr = p_ptr->next;
Head->next = p_ptr->next;
free(p_ptr);
p_ptr = Head;
}
free(p_ptr);
}

Confusion in Free'ing a linked list structure in C

I am juggling with two ways of free()'ing malloc()'ed memory in a linked list structure. Suppose I create a singly linked list with the following C code;
#include<stdio.h>
#include<stdlib.h>
struct node_type{
int data;
struct node_type *next;
struct node_type *prev;
}
typedef struct node_type node;
typedef struct node_type *list;
void main(void){
list head,node1,tail;
head=(list)malloc(sizeof(node));
tail=(list)malloc(sizeof(node));
node1=(list)malloc(sizeof(node));
head->next=node1;tail->prev=node1;
node1->prev=head;node1->next=tail;node1->data=1;
/*Method-1 for memory de-allocation*/
free(head->next->next);
free(head->next);
free(head);
/*OR*/
/*Method-2 for memory de-allocation*/
free(tail);
free(node1);
free(head);
/*OR*/
/*Method-3 for memory de-allocation*/
free(node1);
free(tail);
free(head);
}
Now, I have the following questions:
Q1) Which of the three methods of memory de-allocation shown in code above are correct/incorrect.
Q2) Is is necessary to follow any order in the free()'ing memory as used in Methods 1 and 2 for memory de-allocation OR randomly free()'ing memory is also fine?
All the methods you showed are correct, you should follow a specific order only when the pointer to an allocated memory exists only in another allocated memory, and you will lose it if you free the container first.
For example, for the allocation:
int ** ipp;
ipp = malloc(sizeof(int*));
*ipp = malloc(sizeof(int));
The correct free order will be:
free(*ipp);
free(ipp);
and not:
free(ipp);
free(*ipp); // *ipp is already invalid
All of these methods work fine. You can free memory blocks allocated by malloc in whatever order you like.
Just imagine for a moment that the order in which you allocated memory had to be reversed when you freed it. If that was so you could never insert or delete items from the middle of a list. Your only available dynamically allocated data structure would be a push-down stack.
Here's a simple way to free a linked list, starting at the head. (Note, this assumes "next" will be NULL if you're at the end of the list.)
node * it = head;
while( NULL != it ) {
node * tmp = it;
it = it->next;
free(tmp);
}

Resources