C Doubly Circular Linked List Deletion - c

I'm having a problem deleting from a circular doubly linked list. I have tried various different methods mentioned here, but they all cause some sort of error. Here, I'm getting an error saying "double free detected in tcache 2"
void delete_list(Node *node)
{
Node *pt;
while(node != NULL){
pt = node;
node = node->next;
free(pt);
}
}

I'm having a problem deleting from a circular doubly linked list
A circular doubly linked list does not have a node with the data member next that is equal to NULL. The tail node in its data member next has the address of the head node.
So if your list is not empty then this function
void delete_list(Node *node)
{
Node *pt;
while(node != NULL){
pt = node;
node = node->next;
free(pt);
}
}
invokes undefined behavior after it moves from the tail node to the head node that it tries to free twice.
The function can look for example the following way (without testing)
void delete_list( Node **head )
{
if ( *head )
{
Node *current = ( *head )->next;
while ( current != *head )
{
Mode *tmp = current;
current = current->next;
free( tmp );
}
free( *head );
*head = NULL;
}
}
If in main you have a declaration like
Node *head = NULL;
//...
then the function can be called like
delete_list( &head );
Pay attention to that the function does not deal with the pointer to the tail node if it is declared separately apart from the pointer to the head node.
In this case you need to introduce one more structure as for example
struct CircularList
{
Node *head;
Node *tail;
};
that indeed defines a list. And call the (modified) function for an object of this type.

free'ing a node in a doubly linked list does NOT remove that node from the list.
The code must correct the 'next' field of the prior node in the list and correct the 'prev' field of next node in the list so those fields skip the node to be deleted, Then the node to be deleted can be passed to free()

void delete_list(Node **head){
Node *current, *garbage;
if (*head==NULL) return; else current=(*head)->next;
while(current != *head){
garbage=current;
current = current->next;
free(garbage);
}
free(current);
*head=NULL;
}

Related

Explanation for base case return value in recursive linked list reverse algorithm

I am learning how to reverse a linked list recursively. I am confused with the last 4 lines.
node *reverse_linked_list_rec(node *head){
if (head->next==NULL){
return head;
}
node *smallans= reverse_linked_list_rec(head->next);
node *tail = head->next;
tail->next = head;
head->next = NULL;
return smallans;
}
Let's say I am reversing
1 2 3 NULL
by recursion, it reaches at 3 NULL and then by base case returns
2 3 NULL
here head=2, smallans=2 (not sure).
Why we are returning smallAns here and how it is changing?
smallans is a confusing variable name because it's actually the old tail being passed back through the list to become the new head which is ultimately returned to the caller.
Its next pointer changes when these lines execute in the parent function call:
// when head->next->next == NULL ...
node *tail = head->next; // ... `tail` points to the old tail (new head) ...
tail->next = head; // ... and this sets the new tail's next pointer to
// the old second-to-last node (new second node).
tail is a misleading name here--I associate a "tail" with a single node that terminates the entire list, not a previous node. new_prev or old_next seem more appropriate here depending on whether you want to name things relative to the node roles in the new list or the original list.
As a minor point, I recommend using if (!head || !head->next) to avoid a potential null pointer dereference.
I'd write the function as follows:
node *reverse_linked_list_rec(node *head) {
if (!head || !head->next) {
return head;
}
node *old_tail = reverse_linked_list_rec(head->next);
node *old_next = head->next;
old_next->next = head;
head->next = NULL;
return old_tail;
}
Aside from intellectual curiosity, recursion is a poor choice for linked list operations since it adds function call overhead, you can blow the stack and the logic isn't any easier to follow than iterative, in most cases.
Case in point, here's a complete example with an iterative version:
#include <stdio.h>
#include <stdlib.h>
struct node {
int id;
struct node *next;
};
struct node *make_node(int id) {
struct node *n = malloc(sizeof(*n));
if (!n) exit(1);
n->id = id;
n->next = NULL;
return n;
}
struct node *reverse_linked_list(struct node *head) {
struct node *prev = NULL;
for (struct node *curr = head; curr;) {
struct node *old_next = curr->next;
curr->next = prev;
prev = curr;
curr = old_next;
}
return prev;
}
void print_linked_list(struct node *head) {
for (; head; head = head->next) {
printf("%d->", head->id);
}
puts("");
}
void free_linked_list(struct node *head) {
while (head) {
struct node *tmp = head;
head = head->next;
free(tmp);
}
}
int main() {
struct node *head = make_node(1);
head->next = make_node(2);
head->next->next = make_node(3);
print_linked_list(head); // => 1->2->3->
head = reverse_linked_list(head);
print_linked_list(head); // => 3->2->1->
free_linked_list(head);
return 0;
}
As another minor point, since the linked list is being mutated I'd probably go for a header like void reverse_linked_list(struct node **head);. Otherwise, it seems too easy to call the non-void function, ignore the return value and wind up with a memory leak or crash when head in the caller scope (which has become a tail pointing to null) is dereferenced.

A question about deleting a node in a linked list

Before calling the free(); function if I don't assign NULL value to the link part of the node that I want to delete, what will be the problem ? I reviewed some codes of deleting nodes in other websites, but I found no assignment of NULL value to the link part. They just called the free(); function. Please reply to remove my confusion. Thank you.
struct node
{
int data;
struct node * next;
}
struct node * head = NULL; //This is the head node.
/* Here some other functions to create the list */
/* And head node is not going to be NULL here, after creating the list */
void deleteFirstNode()
{
struct node * temp = head;
head = temp->next;
temp->next = NULL; //my question is in this line, is this line necessary?
free(temp);
}
No, the line
temp->next = NULL;
is not necessary. Any data in the node pointed to by temp will become invalid as soon as free is called, so changing any values inside that node immediately before they become invalid will have no effect.
This function can invoke undefined behavior when will be called for an empty list due to these statements
struct node * temp = head;
head = temp->next;
because in this case head is equal to NULL.
The function frees the memory occupied by an object of the type struct node. So there is no sense to change the deleted object. This statement
temp->next = NULL; //my question is in this line, is this line necessary?
is redundant.
It is the same as before deleting the node to write
temp->data = INT_MAX;
This does not influence on the list.
The function can look like
void deleteFirstNode()
{
if ( head != NULL )
{
struct node *temp = head;
head = head->next;
free( temp );
}
}
Also it is a bad idea to define function that depend on global variables. In this case you will be unable for example to create more than one list in the program. It is better when the pointer to the head node is passed to the function deleteFirstNode by reference.
In this case the function can look like
void deleteFirstNode( struct node **head )
{
if ( head != NULL )
{
struct node *temp = *head;
*head = ( *head )->next;
free( temp );
}
}
And the function can be called like
deleteFirstNode( &head );

Delete last node of single linked list using tail pointer

I'm creating a singly linked list in C which has head and tail pointers where the head pointer points to starting node of SLL and tail pointer points to the last node of SLL. I don't want to traverse till the end of the list using the head pointer to delete the node. Is there a way so that I can use the tail pointer to delete the last element of SLL?
Following is node addition function. head and tail are initiated NULL.
void add_node_last(Node** head, Node** tail, int data) {
Node* new_node = (Node *) malloc(sizeof(Node));
new_node -> data = data;
new_node -> ptr = NULL;
if(*head == NULL && *tail == NULL) {
*head = new_node;
*tail = new_node;
return;
}
(*tail) -> ptr = new_node;
*tail = new_node;
}
To delete the first node, the following function is used:
void del_first(Node **head) {
if(*head == NULL) {
return;
}
*head = (*head) -> ptr;
free(*head);
}
You can free the node's memory, but only once. After the first removal, your tail pointer, and the ptr of the second to last node, will be invalid pointers. In order to make sure both pointers are always correct you either need to traverse the entire list or make it a doubly linked list.
That's a long way of saying no (thanks to #stark).
in order for this to work without making it a doubly linked list, you could have the tail's *next pointer point to the head of the list, then traverse through it till you reach the node before the tail. once there you can NULL its *next pointer which would essentially detach the original tail from the list. you would then set the tail to the current node, then finally free the original tail.
void del_last(Node **head, Node **tail) {
struct node *new_head = *head;
struct node *current = *tail;
current->next = head;
while(current-> != *tail) //getting the node right before the original tail
{
current = current->next
}
current->next = NULL; //detaches original tail form list
free(**tail); //gets rid of original tail
**tail = current; // sets current node to tail pointer
}

A method to delete the elements in a linkedlist using C

So I'm asked to make a method that empty out the entire linked list.
This is what I have now, and I have no idea why it doesn't want to work:
void deleteList(){
}
Your function needs to be passed the head of the list, i.e. struct node *head that it can operate on. Then you can use that instead of current to keep track of the current head.
void deleteList(struct node *head){
struct node* next;
while (head!= NULL) {
next = head->next;
free(head);
head = next;
}
}
Edit:
Since the list head is a global variable, then you would do this:
struct node *head; // Initialized elsewhere
void deleteList(){
struct node* current = head;
struct node* next;
while (current != NULL) {
next = current->next;
free(current);
current = next;
}
}
Your function never assigns "current" to any node to begin with. Because of this your while loop never runs because "current" effectively always equals NULL (hopefully, actually it is undefined and could cause very strange behavior). The loop is always skipped. Try passing the first node of the list into your function as a parameter:
void deleteList(struct node * start) {
//"start" points to the first node in the list, point "current" at it
struct node * current = start;
struct node * next;
while (current != NULL) {
next = current->next;
//what's this pop doing? It seems unnecessary to the logic here
pop(next);
//free "current" and then point "current" at "next"
free(current);
current = next;
}
}
This would also allow you to release an arbitrary segment of the end of the list by providing "start" the node you want to begin releasing at. It need not be the very first node.

How to pop from linked list?

I've implemented a Linked-List with a Pop function in C:
Node * pop (Node * head) {
Node * temp = head;
printf("Temp is: %s\n", temp->val);
if (head->next != NULL) {
*head = *head->next;
}
printf("Temp is: %s\n", temp->val);
return temp;
}
And the output when I pop would be something like:
Temp is: node1 value
Temp is: node2 value
That is to say that temp is becoming temp->next when I assign *head = *head->next.
So how can I get the value of the current head and return it while also moving the head of the Linked-list to head->next?
Doing head = head->next does NOT remove the reference to the first node. (i.e. When I print the list, the first node is still there).
First, note that your code (and some of the previous solutions) will never pop the last element off the list. You want
if (*head != NULL) ...
Next, passing a pointer to a pointer will work. But it's actually better to make a list header like this:
typedef struct node_s {
struct node_s *next;
... data declaration here
} Node;
typedef struct list_s {
struct node_s *head;
} List;
void init_list(List *list) {
list->head = NULL;
}
Now declare a list like this:
List list[1];
init_list(list);
Declaring an array of one element makes every reference to list a pointer automatically, which eliminates lots of &'s in your code. Then it's nice and clean to implement push and pop:
void push(List *list, Node *node) {
node->next = list->head;
list->head = node;
}
Node *pop(List *list) {
Node *head = list->head;
if (head) {
list->head = head->next;
head->next = NULL;
}
return head;
}
Why is this better? Say you decide later to keep a count of items in the list. With the separate header node this is very easy:
typedef struct list_s {
struct node_s *head;
int length;
} List;
void init_list(List *list) {
list->head = NULL;
length = 0;
}
void push(List *list, Node *node) {
node->next = list->head;
list->head = node;
++list->length;
}
Node *pop(List *list) {
Node *head = list->head;
if (head) {
list->head = head->next;
head->next = NULL;
--list->length;
}
return head;
}
Note no calling code needs to change. With the pointer to pointer approach you are at a dead end. There are many other use cases where having a separate list header makes your code more flexible for future changes.
Your need to pass the address of head for your function to modify it. Then your function needs to dereference this address. Further, the last pop() needs to change *AddressOfHead as well
Node *pop(Node **AddressOfHead) {
Node *temp = *AddressOfHead;
if (temp) {
*AddressOfHead = temp->next;
}
return temp;
}
...
// Usage example
Node *TopOfList = pop(&Head);
Others have told you how to fix it, let me answer why temp changed..
Node * pop (Node * head) {
You are passing head as a pointer to a Node.
Thus when you do
*head = *head->next;
I think it is parsed as
*head = *(head->next);
And thus COPIES the object that is in next into the object at head, which is ofcourse the same object at temp.
Pointers are passed by value. That is, when you pass a pointer to the stack, a change in the called function to what the pointer points to is not reflected in the calling function.
In order for the value of the node pointer to be changed in the calling function, you need to pass the stack as a pointer to a pointer:
Node* pop (Node** head) {
Node* temp = *head;
if (temp) {
*head = temp->next; // to update stack in calling function
temp->next = NULL; // to detach temp from the rest of the list
}
return temp;
}
You do not need to check if ((*head)->next) or in this case if (temp->next) before updating the value of *head, because if you are at the last node of the stack and the next node is NULL, you want the list to be NULL anyway.
Karthik T's answer has the right explanation for why the value of temp was changing in your original code.
void pop(struct node** tol) {
struct node* t = *tol;
while (t->link->link != NULL){
t = t->link;
}
t->link = NULL;
}

Resources