Search code examples
cstructlinked-listdoubly-linked-listfunction-definition

Removing an element from a linked list


Assuming I have this list below :

List of CDData
    1: Test1
    2: Test2
    3: Test3
    4: Test4
    5: Test5
    6: Test6

Now I want to delete the third one from the list using the linked list : which means free(removeFromDList(3)); This is my function :

TCD *removeFromDList(int res)
{
    int count = 0;
    TCD *CDData = First;
    CDData->Prev = First;

    if (First == NULL)
    {
        printf("Error\n");
        return NULL;
    }

    while (CDData)
    {
        count++;
        if (count == res)
        {
            if (count == 1)
            {
                if (CDData == Last)
                    Last = NULL;
                First = First->Next;
                return CDData;
            }
            else
            {
                while (CDData != NULL)
                {
                    CDData->Prev = CDData->Next;
                    if (CDData == Last)
                        Last = CDData->Prev;

                    // printf("%s",CDData->Title) I tested here whether my function is going to 
                    //  delete the third one or not with the printf() and it's actually printing the third one 
                    // Which means it's correct 
                   
                    return CDData;
                }
            }
        }

        else
            CDData->Prev = CDData;
        CDData = CDData->Next;
    }
}

By the way , this is the definition of TCD

typedef struct F
{
 char *Title;
 struct F *Next;
 struct F *Prev;
}TCD;

Now after re-printing my list it seems that all of CDData(The whole Data structure ) have been freed. Any ideas why ?

I get this as an output

List of CDData

 
 
  
   

Solution

  • I think in this structure definition

    typedef struct F
    {
     char *Titel;
     struct F *Next;
     struct F *Prev;
    }TCD;
    

    you mean that the name of the first data member is Title instead of Titel.

    And you need to allocate dynamically memory for a string that will be pointed to by this data member.

    Your function can invoke undefined behavior at least because initially the global variable First (by the way it is a bad idea when functions depend on global variables) can be equal to NULL. So in this code snippet

    TCD *CDData = First;
    CDData->Prev = First;
    

    there is an attempt to use a null pointer (CDData->Prev) to access memory.

    This inner while loop

                while (CDData != NULL)
                {
                    CDData->Prev = CDData->Next;
                    if (CDData == Last)
                        Last = CDData->Prev;
    
                    // printf("%s",CDData->Title) I tested here whether my function is going to 
                    //  delete the third one or not with the printf() and it's actually printing the third one 
                    // Which means it's correct 
                   
                    return CDData;
                }
    

    does not make sense.

    Pay attention to that in C indices start from 0.

    Using your approach the function can be written the following way as it is shown in the demonstrative program below.

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    typedef struct F
    {
        char *Title;
        struct F *Next;
        struct F *Prev;
    } TCD;
    
    TCD *First, *Last;
    
    TCD * removeFromDList( size_t n )
    {
        TCD **Current = &First;
        
        while ( *Current && n--)
        {
            Current = &( *Current )->Next;
        }
        
        TCD *target = *Current;
        
        if ( *Current )
        {
            if ( ( *Current )->Next == NULL ) 
            {
                Last = ( *Current )->Prev;  
            }
            else
            {
                ( *Current )->Next->Prev = ( *Current )->Prev;
            }
            
            *Current = ( *Current )->Next;
        }
        
        return target;
    }
    
    int append( const char *s )
    {
        TCD *Current = malloc( sizeof( TCD ) );
        int success = Current != NULL;
        
        if ( success )
        {
            Current->Title = malloc( strlen( s ) + 1 );
            success = Current->Title != NULL;
            
            if ( success )
            {
                strcpy( Current->Title, s );
                Current->Prev = Last;
                Current->Next = NULL;
            }
            else
            {
                free( Current );
            }
        }
        
        if ( success )
        {
            if ( Last )
            {
                Last = Last->Next = Current;
            }
            else
            {
                First = Last = Current;
            }
        }
        
        return success;
    }
    
    FILE * display( FILE *fp )
    {
        for ( TCD *Current = First; Current; Current = Current->Next )
        {
            fprintf( fp, "%s -> ", Current->Title );
        }
        
        fputs( "NULL", fp );
        
        return fp;
    }
    
    int main(void) 
    {
        
        for ( char s[] = "A"; s[0] != 'E'; ++*s )
        {
            append( s );
        }
        
        
        fputc( '\n', display( stdout ) );
        
        TCD *p = removeFromDList( 3 );
        free( p->Title );
        free( p );
        fputc( '\n', display( stdout ) );
        
        p = removeFromDList( 1 );
        free( p->Title );
        free( p );
        fputc( '\n', display( stdout ) );
        
        p = removeFromDList( 0 );
        free( p->Title );
        free( p );
        fputc( '\n', display( stdout ) );
        
        p = removeFromDList( 0 );
        free( p->Title );
        free( p );
        fputc( '\n', display( stdout ) );
        
        printf( "First == NULL : %d, Last == NULL : %d\n", First == NULL, Last == NULL );
        return 0;
    }
    

    The program output is

    A -> B -> C -> D -> NULL
    A -> B -> C -> NULL
    A -> C -> NULL
    C -> NULL
    NULL
    First == NULL : 1, Last == NULL : 1