1

I am trying to delete a node from a linked list but I am still new to the concept of double pointers so I tried using a global variable to hold the head pointer instead. However, I get the wrong results when I try to print my list after deleting the middle node.

I saw this question deleting a node in the middle of a linked list and I don't know how is my delete node function different from the answer.

Here is my code:

#include <stdio.h>
#include <stdlib.h>

typedef unsigned char u8;
typedef struct Node node;
void addfirstnode( u8 );
void addnode( u8 );
void print( void );
void deletenode( u8 key );
void deleteonlynode();
void deletefirstnode();

struct Node
{
    u8 x;
    node *next;
};
node *head;
u8 length = 0;


void main( void )
{
    u8 x;
    printf( "\nTo add node enter 0\nTo print linked list enter 1\nTo exit press 2\nTo delete node press 3\nYour Choice:" );
    scanf( "%d", &x );
    if ( x == 2 )
    {
        printf( "\nThank You\nGood Bye" );
    }
    while ( x != 2 )
    {
        switch ( x )
        {
            u8 n;
            u8 key;
            case 0:            //Add node
                printf( "\nPlease enter first value:" );
                scanf( "%d", &n );
                if ( length == 0 )
                {
                    addfirstnode( n );
                    //printf("%d",head->x);
                }
                else
                {
                    addnode( n );
                }
                printf( "\nNode added , Thank you\n" );
                break;

            case 1:            //Print
                print();
                break;

            case 3:            //DeleteNode
                printf( "\nPlease enter value to be deleted:" );
                scanf( "%d", &key );
                deletenode( key );
                //deletefirstnode();
                break;

            default:
                printf( "\nInvalid Choice please try again\n" );
        }
        printf( "\nTo add node enter 0\nTo print linked list enter 1\nTo exit press 2\nTo delete node press 3\nYour Choice:" );
        scanf( "%d", &x );
        if ( x == 2 )
        {
            printf( "\nThank You\nGood Bye" );
        }
    }
    //where do I use free();
}

void addfirstnode( u8 n )
{
    head = ( node * ) malloc( sizeof( node ) );
    head->next = NULL;
    head->x = n;
    length++;
}

void addnode( u8 n )
{
    node *last = head;
    while ( ( last->next ) != NULL )
    {
        last = last->next;
    }
    last->next = ( node * ) malloc( sizeof( node ) );
    ( last->next )->next = NULL;
    ( last->next )->x = n;
    length++;
}

void print( void )
{
    node *last = head;
    u8 count = 1;
    printf( "\n---------------------" );
    if ( last == NULL )
    {
        printf( "\nList is empty" );
    }
    while ( last != NULL )
    {
        printf( "\nNode Number %d = %d", count, last->x );
        last = last->next;
        count++;
    }
    printf( "\n---------------------" );
    printf( "\n" );
}

void deletenode( u8 key )
{
    node *last = head;
    //node*postlast = NULL;
    if ( ( last->x == key ) && ( last->next == NULL ) )
    {
        deleteonlynode();
    }
    else
    {
        while ( last != NULL )
        {
            if ( ( last->x ) == key )
            {
                printf( "value to be deleted is found" );
                node *temp = last->next;
                last->next = last->next->next;
                free( temp );
                length--;
            }
            last = last->next;
        }
    }
}

void deleteonlynode()
{
    printf( "\n Deleting the only node" );
    free( head );
    head = NULL;
    length--;
}

void deletefirstnode()
{
    printf( "\n Deleting the first node" );
    node *temp = head;
    head = head->next;
    free( temp );
    length--;
}
Kingsley
  • 14,398
  • 5
  • 31
  • 53
Nemo
  • 85
  • 2
  • 11
  • 1
    Why do almost all beginners cast malloc? Where do you learn it? – klutt Dec 10 '18 at 02:43
  • @Broman I initially thought that was the only way to do it but your question made me look things up and I found this [link](https://stackoverflow.com/questions/20094394/why-do-we-cast-return-value-of-malloc) – Nemo Dec 10 '18 at 02:51
  • But I'm curious. Where did you get that idea? It's not like it's something that you do without someone telling you. – klutt Dec 10 '18 at 02:54
  • @Broman I probably saw it in a code example on tutorialspoint and guessed that was the only way to do it. – Nemo Dec 10 '18 at 03:01
  • That explains it. Don't trust that site. – klutt Dec 10 '18 at 03:04

2 Answers2

1

The code is removing the wrong item from the linked list:

See:

        if ( ( last->x ) == key )
        {
            printf( "value to be deleted is found" );
            node *temp = last->next;     // last->next? No, just last.
            last->next = last->next->next;
            free( temp );
            length--;
        }

last is pointing at the element to be removed. But then the code assigns temp to point at last->next (NOT last), and then cuts that from the list.

So by looking at node->next rather than the current node, it's possible to trim it out since you're starting from the pointer before the one to remove. Basically your code was almost there already.

void deletenode( u8 key )
{
    node *ptr = head;

    if ( ( ptr->x == key ) )
    {
        // Delete the first/head element
        node *temp = ptr;
        head = head->next;
        free( temp );
        length--;
    }
    else
    {
        while ( ptr->next != NULL )
        {
            if ( ( ptr->next->x ) == key )
            {
                printf( "value to be deleted is found" );
                node *temp = ptr->next;
                ptr->next = ptr->next->next;
                free( temp );
                length--;
            }
            ptr = ptr->next;
        }
    }
}

Also I took the liberty of renaming last to ptr because it was confusing me.

EDIT: Updated to remove the head cleanly too.

Kingsley
  • 14,398
  • 5
  • 31
  • 53
  • Great Thanks a lot I get it now – Nemo Dec 10 '18 at 02:37
  • I updated the function to be able to delete the first node as well if the key was found there : `if ((last->x == key)) { deletefirstnode(); }` However when I use this condition `//if ((last->x == key) && (last == head))` the function doesn't work properly and here is the implementation: `void deletefirstnode() { printf("\n Deleting the first node"); node* temp = head; head = head->next; free(temp); length--; }` – Nemo Dec 10 '18 at 03:24
  • 1
    If you need to remove the head node, just keep a pointer to it, then `head = head->next;`. Don't try to make it complicated ;) `head->next` is either `NULL` or just another node-pointer. – Kingsley Dec 10 '18 at 03:53
  • 1
    BTW: did you notice the bug in your remove function? It's actually removing all non-head nodes that match. A `break` would fix it. – Kingsley Dec 10 '18 at 03:56
  • yes you are right I didn't notice that bug. I will add a break thanks a lot. – Nemo Dec 10 '18 at 15:28
1

Your code seems to be deleting last->next while last should be the node that matches the key. I guess the following code may be shorter and do the deletion

node* head;

/* returns the node* the previous_node->next should be after the deletion */
node* delete_node(node* current, u8 key) {
    if (current == NULL) return NULL;  // deletion comes to end
    if (head->x == key) {
        node* temp = current->next;
        free(current);
        return delete_node(temp, key);
    }
    current->next = delete_node(current->next, key);
    return current;
}


int main() {
    // build the linked list
    // ...
    head = delete_node(head, key);
    return 0;
}

However, this implement (which uses recursion instead of loop) may cause StackOverFlow if the list is too long. I had not tested if gcc would optimize the recursion out.

Ze Chen
  • 21
  • 5
  • I am still dealing with short lists so I don't think that will be a problem. Thanks a lot – Nemo Dec 10 '18 at 15:29