Home > Back-end >  Why deleting a node in linked list fails when explicitly using a variable to save the head of the li
Why deleting a node in linked list fails when explicitly using a variable to save the head of the li

Time:01-27

I'm using this function to create a list by pushing a new node to the front.

void push(struct Node **head, int newValue)
{    
    if (*head == NULL)
    {
        puts("List is empty. The first node will be created now... ");
    }
    struct Node *new_node = malloc(sizeof(struct Node));
    new_node->data = newValue;
    new_node->next = (*head);
    (*head) = new_node;
}

I'm populating the list by doing this:

  push(&head, 10);
  push(&head, 20);
  push(&head, 30);
  push(&head, 40);

This gives me the following list: 40->30->20->10

Now, I want to delete the element at the head of the list. Here's my delete function:

void delete (struct Node **head, int key)
{
    // struct Node *currentNode = (*head);
    
    if ((*head)->data == key)
    {
        struct Node *tmp = (*head);
        (*head) = (*head)->next;
        free(tmp);
    }
}

Then:

delete(&head, 40);
printList(head);

and I get the expected output (i.e. 30->20->10).

However, if I un-comment the struct Node *currentNode = (*head); line and use the currentNode pointer instead of (*head) like so:

void delete (struct Node **head, int key)
{
    struct Node *currentNode = (*head);

    //if the key is at HEAD (the first node)
    if (currentNode->data == key)
    {
        struct Node *tmp = currentNode;
        currentNode = currentNode->next;
        free(tmp);
    }
}

, and I call delete(&head, 40) and printList(&head) again, Iget some values that I believe are garbage (i.e. 0->1).

My printList is this:

void printList(struct Node *list)
{
    int index = 0;
    
    while (list != NULL)
    {
        index  ;
        list = list->next;
    }
}

and Node is this:

struct Node
{
    int data;
    struct Node *next;
};

What's going on?

CodePudding user response:

In the case where you're using currentNode, it contains a copy of what is in *head. However, you only modify the copy, not *head, so the head of the list doesn't actually change. So after the function returns, head now points to memory that has been freed, so reading that pointer triggers undefined behavior.

The reason for passing a pointer-to-pointer is to allow a pointer in the calling function to be modified by the called function.

CodePudding user response:

In fact what you have in the modified function is similar to the following

int x = 10;
int y = x;
y = 0;

After this code snippet the variable x stays unchanged because it is the variable y that initially was initialized by the value of the variable x that was changed.

There is no need to introduce the local variable currentNode within the function.

I suspect that you want to change the function such a way that it would delete any node (not only the first one) that has a value equal to the value of the parameter key.

In this case the function can look the following way

int delete (struct Node **head, int key)
{
    while ( *head != NULL && ( *head )->data != key )
    {
        head = &( *head )->next;
    } 

    int success = *head != NULL;

    if ( success )
    {
        struct Node *tmp = *head;
        *head = ( *head )->next;
        free( tmp );
    }

    return success;
}
  •  Tags:  
  • Related