A question about deleting a node in a linked list - c

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

Related

Purpose of Using a double pointer in Linked Lists

I have a few questions about this function which intends to delete all occurrence of a given integer in the list :
void deleteAllOcc (node**headRef,int d)
{
node*temp;
if (*headRef==NULL)
return;
while (*headRef)
{
if ((*headRef)->data==d)
{
temp=*headRef;
*headRef=(*headRef)->next;
free(temp);
}
else
{
headRef=&((*headRef)->next);
}
}
}
First why did we use **headRef instead of *head ?
Secondly, considering this :
if ((*headRef)->data==d)
{
temp=*headRef;
*headRef=(*headRef)->next;
free(temp);
}
Don't we need to update the links ?
And third, considering this :
else
{
headRef=&((*headRef)->next);
}
Why we didnt do *headRef=(*headRef)->next); here?
Thanks in advance
For starters the function can be written simpler
void deleteAllOcc( node **headRef, int d )
{
while ( *headRef != NULL )
{
if ( ( *headRef )->data == d )
{
node *temp = *headRef;
*headRef = ( *headRef )->next;
free( temp );
}
else
{
headRef = &( *headRef )->next;
}
}
}
That is the first check for the equality of the passed by reference the pointer to the head node is redundant.
First why did we use **headRef instead of *head?
It depends on how the function is defined. In the case of the function definition provided in your question the pointer to the head node is passed by reference that is through a pointer to the pointer head. In this case changing the pointed pointer head within the function you are changing the original function.
For example imagine that the list contains only one node and its data member data is equal to the specified value of the argument d.
in main
node *head = malloc( sizeof( mode ) );
head->data = 1;
head->next = NULL;
deleteAllOcc( &head, 1 );
//...
and within the function deleteAllOcc you have
if((*headRef)->data==d)
{
temp=*headRef;
*headRef=(*headRef)->next;
free(temp);
}
As *headRef yields the original pointer head in main then this statement
*headRef=(*headRef)->next;
changes the original pointer head in main bot a copy of the value of the pointer.
You could define the function in other way when the pointer to the head node is not passed by reference but passed by value. But in this case you need to return the possible new value for the pointer to the head node in main.
For example
node * deleteAllOcc( node *head, int d )
{
while ( head != NULL && head->data == d )
{
node *temp = head;
head = head->next;
free( temp );
}
if ( head != NULL )
{
for ( node *current = head; current->next != NULL; )
{
if ( current->next->data == d )
{
node *temp = current->next;
current->next = current->next->next;
free( temp );
}
else
{
current = current->next;
}
}
}
return head;
}
and in main the function should be called for example like
node *head = NULL;
//filling the list
head = deleteAllOcc( head, 1 );
As you can see the function definition when the pointer to the head node is passed by reference looks more simpler.
how are we updating the links between the nodes after deleting a node
You have a pointer to the data member next of the current node. The pointed node by the data member next of the current node contains the value equal to the value of the parameter d. So the next node must be deleted. It ,means that the data member next of the current node shall point to the node after the deleted node. That is you need to write
*headRef = ( *headRef )->next;
where headRef at the current moment points to the data member next of the current
node.
|node1| next | -> |node2| next | -> |node3| next |
| |
headRef node that must be deleted
So in the data member next pointed to by headRef you have to write the value of the data member next of the deleted node node2.
why we didnt do *headRef=(*headRef)->next); here?
In this code snippet
else
{
headRef=&((*headRef)->next);
}
you are reallocating the pointer headRef to point to the data member next of the next node. If you will write
*headRef = ( *headRef )->next;
then you will lose the node currently pointed to by the value stored in the expression *headRef that is in the currently pointed data member next will be changed rewriting the stored pointer.
First why did we use **headRef instead of *head?
When you send the adress of a linked list to a function, you create a pointer on the first element of this list. It allows you to iterate on the list etc. But if you want to manipulate the complete list (or edit it), you have to create a pointer on this list, (that means a double pointer on this list by sending the adress of the linked list
why we didnt do *headRef=(*headRef)->next); here?
Your method can work but I advise you to create a pointer to a temporary node *(node tmp) in order to assign the value to it and swap data with it. It's much more readable for everyone.

C Doubly Circular Linked List Deletion

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

Why to return pointer after inserting node in Link Lists

I don't understand why we have to return pointers to the head node after a node has been added to a linked list.
struct node *append(int v) {
struct node *ptr;
struct node *t;
ptr=head;
while (ptr->next != tail) ptr = ptr->next;
t=(struct node *) malloc(sizeof *t);
t->value=v;
t->next = tail;
ptr->next = t;
return ptr; // why return ptr?
}
It depends of the context of your problem. Usually in linked list problems you have to return the head of the list so you can have your data structure consistent, but I infer from your code that the head is a global variable.
Unless the code that are invoking this function needs to know the location of the new node created, you don't need to return the node since your head is a global variable (again, if my assumption is correct).
Besides this, I suggest to revise your function since I see some cases you are missing here (what if the list comes empty and you have to change the head for example?)
First of all the function is invalid. When the list is empty and the first element is added head can be equal to NULL. So using expression head->next that in the function code corresponds to ptr->next results in memory access violation.
Also in my opinion it is not a good idea to name NULL as tail. I would explicitly use NULL. Otherwise the code can confuse readers.
Neverteless the function can look the following way
struct node * append( int v )
{
struct node *t = ( struct node * )malloc( sizeof( *t ) );
t->value = v;
t->next = tail;
if ( head == tail )
{
head = t;
}
else
{
struct node *current = head;
while ( current->next != tail ) current = current->next;
current->next = t;
}
return t;
}
As for your question then I also do not understand why the function returns ptr instead of t. It should return t. In this case the function would be more correct and efficient because it would return head when the first element is appended to the empty list and when a next non-first value is appended to the list and the head would be some node (not necessary the head itself) the while loop had no iteration because the first expression ptr->next would be equal already to NULL.
The function should return the last appended node as in the implementation I have shown.
I am sure that it is simply an error in the design of the function.:)
This drawback will be more visible if do not use the global variable head within the function but declare it as a function parameter. For example
struct node * append( struct node *head, int v )
{
struct node *t = ( struct node * )malloc( sizeof( *t ) );
t->value = v;
t->next = tail;
if ( head == tail )
{
head = t;
}
else
{
struct node *current = head;
while ( current->next != tail ) current = current->next;
current->next = t;
}
return t;
}
In this case the function call in main could look for example the following way
struct node *head = NULL;
struct node *current;
int i;
head = append( head, 0 );
for ( i = 1, current = head; i < 10; i++ ) current = append( current, i );
In this case the call of append would be very efficient because within the function the while loop would not make even one iteration.
Linked lists are often implemented with a NULL head when the list is empty. In this case, you have to return the head of the list when the head is a local variable, or when it is a global and you want to have more than one list using the same function. When adding a node, the head may have changed, even if adding at tail, in the case the list was empty there is a new head.
But another way to do is to always have a node at the head, just here to indicate the head, and adding/reading/deleting nodes after this head in order to treat datas in the list. In this case, returning the head is useless, because the head never change.
You can detect the tail of the list when for a node n: n->next == NULL, using a head equal to NULL when the list is empty, as the following code do:
// add at the tail of the list:
struct node * add_to_list_tail(struct node * head,int v) {
struct node *t;
t=(struct node *) malloc(sizeof(struct node));
t->value = v;
t->next = NULL; // next is set to NULL because it is the new tail
if(head == NULL) {
// in the case the list is empty
head = t; // t become the new head, because the list was empty
} else {
// in the case the list isn't empty
struct node * n = head;
// the following loop will stop when n->next == NULL, and n will point to the tail
while(n->next != NULL) {
n = n->next;
}
n->next = t;
}
return head;
}
// add at the head of the list:
struct node * add_to_list(struct node * head,int v) {
struct node *t;
t=(struct node *) malloc(sizeof(struct node));
t->value = v;
t->next = head; // make t become the new head
return t; // return t because it is the new head
}
int main() {
struct node * head = NULL;
head = add_to_list(head,1);
head = add_to_list(head,2);
head = add_to_list_tail(head,3);
}
If you don't want to return the head, you can also pass a pointer to the head pointer, as parameter for the functions that manipulate the list. A short sample code:
void add_to_list(struct node ** head,int v) {
struct node *t;
t=(struct node *) malloc(sizeof(struct node));
t->value = v;
// make t become the new head:
t->next = *head;
*head = t;
}
int main() {
struct node * head = NULL;
// we pass &head, the adress of variable head, as parameter:
add_to_list(&head,1);
add_to_list(&head,2);
struct node * n = head;
while(n != NULL) {
printf("\nvalue: %d",n->value);
n = n->next;
}
}

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

Adding a node into a linked list, right after the head

I have a linked list, and I need to create a node right after the head..
it means I have something like this:
node *head = NULL;
and my linked list in the end should be like :
head -> node -> NULL...
but when I use a normal addNode function, it gives me a runtime error(not sure which, my debug has problems)...
this is what I wrote:
void addNode(node *head)
{
node *temp = head; // a temp to not move the head
node *newNode = (node*)malloc(sizeof(node)); // The new node
while (temp -> next != NULL)
{
temp = temp -> next // Getting to the last node
}
temp -> next= newNode; // Adding the new node into the linked list insted of the NULL
newNode -> next = NULL; // Adding the NULL after the new node
}
This code works great to me when I have a linked list with already 1 or more nodes ,but if the linked list only has a head, it does problems to me... how can I solve the problem?
(if you didnt understand my problem - With the addNode function I wrote here, i'm getting a runtime error for adding a new node into a head that points to NULL already)..
Thanks, Amit :)
Need to check if head is NULL on entry, otherwise a null pointer will be dereferenced:
node *temp = head; /* temp set to head, possibly null. */
while (temp->next != NULL) /* 'temp' dereferenced, undefined behaviour
if 'temp' is null. */
In order for the change to be seen by the caller, you will need to pass in a node** (as suggested by wildplasser), as C passes arguments by value. Change to (for example):
void addNode(node **head)
{
node *newNode = malloc(sizeof(node)); /* No need to cast. */
if (newNode)
{
newNode->next = NULL;
if (NULL == *head)
{
*head = newNode; /* Set the head, as there isn't one yet. */
}
else
{
node* temp = *head;
while (temp->next) temp = temp->next;
temp->next = newNode;
}
}
}
This would be called:
node* my_list = NULL;
addNode(&my_list);
You have to check if Head is null. Otherwise when you try to check
head->next != NULL
head is NULL so you are referring to random place in memory
You can't add node after head if head is NULL. You have to allocate memory for head and then set 'next' pointer. By the way why u want to set head->next while head is null?
EDIT
Mayby you should try add flag to nodes like bool active and set it false when you want to pass it.
I'll try to say it in another way. You can't set head->next because head is NULL. NULL means, that it's just a pointer, to nowhere. It's a variable where u can place some address, but nothing else. If u want to have there a structure, like node, you have to place there address of new object of type Node:
Node element = malloc(sizeof(Node));
head = element;
After that u will have in head address of Node object and u will be able to revoke to variables (like Node *next) inside this structure.
You could use a pointer to pointer:
void addNode(node **pp)
{
node *newNode = malloc(sizeof *newNode); // The new node
if (newNode) {
newNode->next = *pp; // steal the parent. (this will also work if *pp happens to be NULL)
*pp = newNode; // let *pp point to the new node
}
}
To be called like:
...
node *head = NULL;
addNode( &head);
...

Resources