Search code examples
cqsort

Sorting an struct array in C with qsort function


First of all, I saw some examples like:

But they don't work for me.

My struct is

typedef struct Team {
    int total;
    char name[N][N];   // Nombre
    int points[N];     // Points
    int pg[N];         // Won Matches
    int pe[N];         // Tied Matches
    int pp[N];         // Lost Matches
    int gf[N];         // Goals For 
    int gc[N];         // Goals Against
} Teams;

int compareTeams(struct Team *e1, struct Team *e2){
    int comparer;
    int dg1 = e1->gf - e1->gc;
    int dg2 = e2->gf - e2->gc;

    //classified according to the points
    if (e1->points > e2->points) {
        comparer=-1;
    } else if (e1->points < e2->points) {
        comparer=1;
    } else {
        // with the same points, goal difference check
        if (dg1 > dg2) {
            comparer=-1;
        } else if (dg1 < dg2) {
            comparer=1;
        } else {
            // with the same goal difference , we check who scored more goals
            if(e1->gf > e2->gf) {
                comparer=-1;
            } else if (e1->gf < e2->gf) {
                comparer=1;
            } else
                comparer=0;
        }
    }
    return comparer;
}

In main function, I have this:

Teams teams[100];
qsort(teams, teams->total, sizeof(struct Team), &compareTeams);

But obviously, it doesn't work :(


Solution

  • You have a single struct:

    typedef struct Team {
        int total;
        char name[N][N];   // Nombre
        int points[N];     // Points
        int pg[N];         // Won Matches
        int pe[N];         // Tied Matches
        int pp[N];         // Lost Matches
        int gf[N];         // Goals For 
        int gc[N];         // Goals Against
    } Teams;
    

    This struct is misnamed; it is not a team, it is a league. All fields except total are themselves arrays. If you want to sort this struct, you would have to swap all arrays simultaneously, because they are essentially independent. qsort can't do that; you would have to write your own sorting algorithm.

    It makes managing the teams and also sorting easier when you restructure your data: A team should only contain the data for itself:

    typedef struct Team {
        char name[24];
        int points;               // Points
        int won, drawn, lost;     // Match records
        int scored, conceded;     // Goal records
    } Teams;
    

    Then you can create an array of teams:

    Team league[] = {
        {"FC Bayern Muenchen",   85,   27,  4,  2,   77, 16},
        {"Borussia Dortmubd",    77,   24,  5,  4,   80, 32},
        {"Bayer 04 Leverkusen",  57,   17,  6, 10,   53, 38},
        {"Borussia M'Gladbach",  52,   16,  4, 13,   65, 50},
        // ...
    };
    

    Then write a comparison function to obeys the definition used in qsort:

    int compareTeams(const void *p1, const void *p2)
    {
        const Team *e1 = p1;
        const Team *e2 = p2;
    
        int dg1 = e1->gf - e1->gc;
        int dg2 = e2->gf - e2->gc;
    
        if (e1->points > e2->points) return -1;
        if (e1->points < e2->points) return 1;
    
        if (dg1 > dg2) return -1;
        if (dg1 < dg2) return 1;
    
        if (e1->gf > e2->gf) return -1;
        if (e1->gf < e2->gf) return 1;
    
        return 0;
    }
    

    and use it:

    qsort(league,
        sizeof(league) / sizeof(*league),    // number of teams
        sizeof(*league),                     // size of one team
        compareTeams);
    

    The restructuring means that the data for each team is kept together in the same struct and instead of swapping many independent arrays in order to keep them in sync, you swap whole teams.