Search code examples
clinked-listfreesingly-linked-listfunction-definition

Linked list failing delete


I have a linked list defined like this

typedef struct Elem Elem;

struct Elem {
    int val;
    Elem *next;
};

and i wrote two list delete function the first:

void free_list(Elem** head) {
        if (!*head)
            return;
        if (!(*head)->next) {
            free(*head);
            *head = 0;
            return;
        }
        free_head(&((*head)->next));
    
}

and the second

void free_list(Elem** head) {
    while (*head) {
        Elem *tmp = *head;
        head = &((*head)->next);
        free(tmp);
    }
}

So the problem is that the two function works on mac os without problems, while the second doesn't work on ubuntu, indeed when i execute it appear this error

free(): double free detected in tcache 2
Aborted (core dump)

So i suppose that the second is wrong, but i don't see the error


Solution

  • The both functions are incorrect.

    The first function

    void free_head(Elem** head) {
            if (!*head)
                return;
            if (!(*head)->next) {
                free(*head);
                *head = 0;
                return;
            }
            free_head(&((*head)->next));
        
    }
    

    deletes only the last node in the list because deleting a node occurs only in this if statement

            if (!(*head)->next) {
                free(*head);
                *head = 0;
                return;
            }
    

    The second function is wrong because it does not set to NULL the pointer to the head node and moreover it assigns the pointer head with the address of the data member ( *head )->next while the node containing this data member is being deleted. SO the function has undefined behavior.

    void free_head(Elem** head) {
        while (*head) {
            Elem *tmp = *head;
            head = &((*head)->next);
            free(tmp);
        }
    }
    

    The function can be defined the following way

    void free_head( Elem **head ) 
    {
        while ( *head ) 
        {
            Elem *tmp = *head;
            *head = (*head)->next;
            free( tmp );
        }
    }
    

    And the recursive function can look like

    void free_head( Elem **head ) 
    {
        if ( *head )
        {
            Elem *tmp = *head;
            *head = ( *head )->next;
            free( tmp );
            free_head( head );
        }
    }