Search code examples
csortingdynamic-memory-allocationc-stringsqsort

qsort turns all values of array to null


I have a program which reads in the lines of a text file and stores them in linesArr, I have also defined a function compFunc which takes two strings as inputs, makes copies of them and converts the copies to lowercase before returning the value of strcmp(copy1, copy2). I am trying to use this function to sort linesArr into alphabetical order with qsort(linesArr, size, 255, compFunc. But the values in the array turn from {"Bob", "James", "Alice"} to {(null), (null), (null)}.

This is how linesArr is initialised.

char **linesArr = (char**)malloc(size*sizeof(char));
for (int i = 0; i < size; i++) {
    linesArr[i] = (char*)malloc(255*sizeof(char));
}

And it it filled with values from the text using the file pointer fp

for (int i = 0; i < size; i++) {    
    fgets(line, 255, fp);
    strcpy(linesArr[i], line);
}

Why is qsort deleting the values in the array?


Solution

  • For starters this memory allocation

    char **linesArr = (char**)malloc(size*sizeof(char));
                                                 ^^^^^
    

    is incorrect, You need to write

    char **linesArr = (char**)malloc(size*sizeof(char *));
                                                 ^^^^^^
    

    Secondly the call of qsort must look like

    qsort(linesArr, size, sizeof( char * ), compFunc);
    

    because the array pointed to by the pointer linesArr is an array of pointers.

    Here is a demonstrative program.

    #include <stdio.h>
    #include <stdlib.h>
    #include <ctype.h>
    #include <string.h>
    
    int compFunc( const void *a, const void *b )
    {
        const char *s1 = *( const char ** )a;
        const char *s2 = *( const char ** )b;
        
        while ( *s1 && tolower( ( unsigned char )*s1 ) == tolower( ( unsigned char )*s2 ) )
        {
            ++s1;
            ++s2;
        }
        
        return tolower( ( unsigned char )*s1 ) - tolower( ( unsigned char )*s2 );
    }
    
    int main(void) 
    {
        enum { size = 3, len = 255 };
        
        char **linesArr = malloc( size * sizeof( char * ) );
        
        for ( size_t i = 0; i < size; i++ )
        {
            linesArr[i] = malloc( len * sizeof( char ) );
        }
        
        char line[len];
        
        for ( size_t i = 0; i < size; i++ )
        {
            fgets( line, sizeof( line ), stdin );
            line[ strcspn( line, "\n" ) ] = '\0';
            strcpy( linesArr[i], line );
        }
        
        qsort( linesArr, size, sizeof( *linesArr ), compFunc );
        
        for ( size_t i = 0; i < size; i++ )
        {
            puts( linesArr[i] );
        }
        
        for ( size_t i = 0; i < size; i++ )
        {
            free( linesArr[i] );
        }
        free( linesArr );
        
        return 0;
    }
    

    The program output might look like

    Bob
    James
    Alice
    Alice
    Bob
    James