Reputation: 35
It looks there is no duplicate questions...so i want a function to free all nodes in a single linked list, and i want to do it recursively. I come up with a close one that i thought it would work, but it does not. It seems that after it removed one node, the upper stack function will not excuse, recursively. I am wondering how to modify the code to make it work.
#include <stdlib.h>
#include<stdio.h>
#include<stdlib.h>
struct Node
{
int data;
struct Node *next;
};
void ft_list_clear(struct Node *begin_list)
{
if ((begin_list->next))
ft_list_clear(begin_list->next);
if(!(begin_list->next))
{
free(begin_list);
begin_list = NULL;
}
}
int main()
{
struct Node* head = NULL;
struct Node* second = NULL;
struct Node* third = NULL;
// allocate 3 nodes in the heap
head = (struct Node*)malloc(sizeof(struct Node));
second = (struct Node*)malloc(sizeof(struct Node));
third = (struct Node*)malloc(sizeof(struct Node));
head->data = 1; //assign data in first node
head->next = second; // Link first node with second
second->data = 2; //assign data to second node
second->next = third;
third->data = 3; //assign data to third node
third->next = NULL;
ft_list_clear(head);
return 0;
}
Upvotes: 0
Views: 1955
Reputation: 4444
Recursively deleting a linked is a bad idea. Each recursive call requires a stack frame, and whether you free the list node memory as you descend or ascend the recursion, you need O(n) memory for what is a simple operation. Each stack call requires local variable storage, room for return pointer, previous stack frame pointer, and possibly other stuff (at least 12-24 bytes per node).
Better to iterate through the list. I have provided three variants of the free (iterative, and two recursive, one free's node on descent, one free's node on ascent).
#include <stdlib.h>
#include <stdio.h>
typedef struct Node
{
int data;
struct Node* next;
} node_t;
long list_clear_iter(node_t* p) {
if(!p) return 0;
long n = 0; //count;
for( ; p->next; ) {
node_t* fp = p; //free this
p = p->next;
free(fp);
++n;
}
return n;
}
//list clear, recursive, (pre)free
long ft_list_clear_pr(node_t* p) {
if(!p) return 0;
node_t* np = p->next;
free(p); //free on descend
long n = ft_list_clear_pr(np);
return(n+1);
}
//list clear recursive, free(post)
long ft_list_clear_rp(node_t* p) {
if(!p) return 0;
long n = ft_list_clear_rp(p->next);
free(p); //free on ascend
return(n+1);
}
Upvotes: 0
Reputation: 13580
The problem with this
void ft_list_clear(struct Node *begin_list)
{
if ((begin_list->next))
ft_list_clear(begin_list->next);
if(!(begin_list->next))
{
free(begin_list);
begin_list = NULL;
}
}
is:
begin_list
is equal to head
.head->next
is not NULL
, so ft_list_clear(second)
is executedsecond->next
is not NULL
, so ft_list_clear(third)
is executedthird->next
is NULL
, so free(third)
happens. The begin_list = NULL
line does nothing here, its pointless.The third iteration returns, back to the second. The next line to execute is
if(!(begin_list->next))
begin_list->next
is not NULL (it's been only free
d), hence the condition is evaluated to false
and the free
is not executed.
This is recursion that would work:
void ft_list_clear(struct Node *begin_list)
{
if(begin_list == NULL)
return;
ft_list_clear(begin_list->next);
free(begin_list);
}
Upvotes: 1
Reputation: 3287
I think it's because you're just freeing nodes, but you miss to nullify the next
members. Try this. I haven't run this so goodluck.
void ft_list_clear(struct Node *begin_list)
{
if ((begin_list->next))
{
ft_list_clear(begin_list->next);
begin_list->next = NULL; // <-- you should nullify the next of the current after you free the node which it points to.
}
if(!(begin_list->next)) // <-- even if the next node was deleted, this won't run if you didn't nullify begin_list->next
{
free(begin_list);
begin_list = NULL;
}
}
Upvotes: 1
Reputation: 174
`void ft_list_clear(struct Node *begin_list)
{
if ((begin_list->next))
ft_list_clear(begin_list->next);
free(begin_list);
begin_list = NULL;
printf("God bless America");
}`
Hopefully, if God blesses America thrice, your code is working, I've committed some changes in your code, and all I did was remove the second if statement because usually, we don't need that in recursion (I'm not saying we don't need more than one if statement). Test it yourself and you'll understand why it's so. Hope it helps.
Upvotes: 1
Reputation: 5706
You're pretty close
void ft_list_clear(struct Nude *list)
{
if (!list) { return; }
ft_list_clear(list->next);
list->next = null;
free(list);
}
Explaining the code
The first if
checks if the list is currently null
and exits the recursion if so.
If the list isn't null
recursively call the function.
This repeats until the end of the list null
.
Then since the next
has been cleared by the recursive call you can set it to null
in this call (not strictly necessary since this clears everything).
Finally actually free
this node prior to returning to the previous call (this node's parent).
You can also do the delete in the opposite order if you want
void ft_list_clear(string Node *list)
{
if (!list) { return; }
struct Node *next = list->next;
free(list);
ft_list_clear(next);
}
Same principles just deletes this node before going to the next. This means you don't need to fix the next
pointers but you will need to copy them first so you don't lose the reference.
Upvotes: 3