Thread: qsort not working on array of structs

  1. #1
    Registered User
    Join Date
    Oct 2020
    Posts
    69

    qsort not working on array of structs

    I'm trying to sort data from a .csv file based on the year (3rd field), using qsort and bubble sort to test the speed of both:


    Look What The Cat Dragged In,Poison,2001,Look What The Cat Dragged In by Poison,1,0,1,0
    Nothin' But A Good Time,Poison,1988,Nothin' But A Good Time by Poison,1,1,21,21
    Something To Believe In,Poison,1990,Something To Believe In by Poison,1,1,1,1
    Talk Dirty To Me,Poison,1978,Talk Dirty To Me by Poison,1,1,1,1
    A Salty Dog,Procol Harum,1969,A Salty Dog by Procol Harum,1,1,1,1
    A Whiter Shade of Pale,Procol Harum,1967,A Whiter Shade of Pale by Procol Harum,1,1,3,3
    Blurry,Puddle of Mudd,2001,Blurry by Puddle of Mudd,1,1,1,1
    Amie,Pure Prairie League,,Amie by Pure Prairie League,1,0,4,0
    Another One Bites the Dust,Queen,1980,Another One Bites the Dust by Queen,1,1,102,102
    Bicycle Race,Queen,1978,Bicycle Race by Queen,1,1,3,3
    Kiss You All Over,Kiss,1978,Kiss You All Over by Kiss,1,1,5,5




    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <ctype.h>
    
    
    #define MAX 300
    
    
    typedef struct {
        char *song, *artist;
        int year;
    } music;
    
    
    
    
    int sort_Song(const void *a, const void *b)
    {
        music *p = (music *)a;
        music *q = (music *)b;
        return strcmp(p->song, q->song);
    }
    
    
    int sort_Artist(const void *a, const void *b)
    {
        music *p = (music *)a;
        music *q = (music *)b;
        return strcmp(p->artist, q->artist);
    }
    
    
    int sort_year(const void *a, const void *b)
    {
        music *p = (music *)a;
        music *q = (music *)b;
        return ((int)(p->year) - (int)(q->year));
    }
    
    
    void display(music *array, int n)
    {
        int i;
        for(i = 0;i <= n; i++)
        {
            printf("Song: %s | Artist: %s | Year: %d\n", array->song, array->artist, array->year);
        }
    }
    
    
    int countLines(FILE *fp)
    {
        char c;
        int count = 0;
        for (c = getc(fp); c != EOF; c = getc(fp))
        {
            if (c == '\n') // Increment count if this character is newline
            {
                count = count + 1;
            }
        }
        return count;
    }
    
    
    /*void bubbleSort_year(int array[], int n)
    {
        int i,j;
        int aux;
        for (i = 0; i < (n-1); i++)
        {
            for(j = 0; j < (n-i-1); j++)
            {
                if(array[j]) > array[j+1])
                {
                    aux = array[j];
                    array[j] = array[j+1];
                    array[j+1] = aux;
                }
            }
        }
    }
    */
    
    
    
    
    int main(int argc, char **argv)
    {
        FILE *fin = fopen(argv[1], "r");
        if (!fin)
        {
            fprintf(stderr, "Error opening the file.\n");
            exit(1);
        }
        if(argc != 2)
        {
            fprintf(stderr, "Invalid usage.\nCorrect usage: ./a.out file.csv");
            exit(-1);
        }
        music *array = (music *)malloc(sizeof(music));
        char buf[MAX];
        while(fgets(buf, MAX, fin))
        {
            buf[strcspn(buf, "\n")] = '\0';  // strip the trailing newline
            char *fields[8];
            char *word = strtok(buf, ",");
            int i = 0;
            while (word)
            {
                fields[i++] = word;
                word = strtok(NULL,",");
            }
            char *p;
            array->song = strdup(fields[0]);
            array->artist = strdup(fields[1]);
            array->year = strtol(fields[2], &p, 10);
            printf("Song: %s | Artist: %s | Year: %d\n", array->song, array->artist, array->year);
        }
        qsort(array, countLines(fin), sizeof(music), sort_Artist);
        //printf("Song: %s | Artist: %s | Year: %lu\n", array->song, array->artist, array->year);
        display(array, countLines(fin)-1);
        free(array->artist);
        free(array->song);
        free(array);
        fclose(fin);
        return 0;
    }
    Right now, the data displayed is unsorted and I'm not sure what is wrong with my qsort function? Any ideas? Thank you!

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    It doesn't look like you have a dynamic array: you allocated space for just one music object.

    I'd get rid of the countLines function: you can count while reading, and you should only do so once.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Dec 2017
    Posts
    1,626
    A lot of problems. To name a few:
    1. You are only allocating space for a single song.
    2. One of the songs is missing the year.
    3. You need to check that argc is 2 BEFORE you access argv[1].
    4. In countLines, c should be an int since that's what getc (usually called fgetc) returns.
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <ctype.h>
     
    #define MAXLINESIZE 300
     
    typedef struct {
        char *song, *artist;
        int year;
    } Music;
     
    char *strdup(const char *s)
    {
        char *r = malloc(strlen(s) + 1);
        if (!r) { perror("strdup"); exit(EXIT_FAILURE); }
        return strcpy(r, s);
    }
     
    int sortBySong(const void *a, const void *b)
    {
        Music *p = (Music*)a, *q = (Music*)b;
        return strcmp(p->song, q->song);
    }
     
    int sortByArtist(const void *a, const void *b)
    {
        Music *p = (Music*)a, *q = (Music*)b;
        return strcmp(p->artist, q->artist);
    }
     
    int sortByYear(const void *a, const void *b)
    {
        Music *p = (Music*)a, *q = (Music*)b;
        return (int)p->year - (int)q->year;
    }
     
    void display(Music *music, int n)
    {
        for (int i = 0; i < n; ++i)
            printf("Song: %s | Artist: %s | Year: %d\n",
                music[i].song, music[i].artist, music[i].year);
    }
     
    int countLines(FILE *fp)
    {
        int count = 0;
        for (int c; (c = fgetc(fp)) != EOF; )
            if (c == '\n')
                ++count;
        return count;
    }
     
    int main(int argc, char **argv)
    {
        if (argc != 2)
        {
            fprintf(stderr, "Usage: %s file.csv", argv[0]);
            exit(EXIT_FAILURE);
        }
     
        FILE *fin = fopen(argv[1], "r");
        if (!fin)
        {
            perror("Error opening input file");
            exit(EXIT_FAILURE);
        }
     
        int nsongs = countLines(fin);
        rewind(fin);
     
        Music *music = malloc(nsongs * sizeof *music);
     
        char buf[MAXLINESIZE];
        for (int i = 0; fgets(buf, sizeof buf, fin) != NULL; ++i)
        {
            buf[strcspn(buf, "\n")] = '\0';  // strip the trailing newline
            char *fields[8];
            char *word = strtok(buf, ",");
            for (int j = 0; word; ++j)
            {
                fields[j] = word;
                word = strtok(NULL, ",");
            }
            music[i].song   = strdup(fields[0]);
            music[i].artist = strdup(fields[1]);
            music[i].year   = strtol(fields[2], NULL, 10);
        }
     
        display(music, nsongs);
        putchar('\n');
     
        qsort(music, nsongs, sizeof *music, sortByYear);
     
        display(music, nsongs);
     
        for (int i = 0; i < nsongs; ++i)
        {
            free(music[i].artist);
            free(music[i].song);
        }
        free(music);
     
        fclose(fin);
     
        return 0;
    }
    A little inaccuracy saves tons of explanation. - H.H. Munro

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. qsort dynamic array of structs
    By akpr2000 in forum C Programming
    Replies: 1
    Last Post: 09-13-2020, 10:42 AM
  2. How to Qsort an array of structs by one of its members?
    By Vespasian in forum C++ Programming
    Replies: 3
    Last Post: 03-31-2013, 01:36 PM
  3. qsort not sorting structs
    By ArcadeEdge in forum C Programming
    Replies: 6
    Last Post: 04-11-2012, 05:44 AM
  4. Replies: 3
    Last Post: 03-31-2009, 12:34 PM
  5. Sorting an Array of Structs not working
    By ashcan1979 in forum C++ Programming
    Replies: 9
    Last Post: 09-28-2006, 03:07 PM

Tags for this Thread