Quick Sorting Structures

Difficulty: ★ ★ ★ ★

I’ve covered the miraculous qsort() function elsewhere in this blog. It’s nifty, allowing you to sort all kinds of data with your only job being to code a compare() function. Most coders these days just copy-paste this function and call it good. But for sorting an array of structures, more brain muscle is required.

As a review, the qsort() function has four arguments:

void qsort(void *base, size_t nel, size_t width, int (*compar)(const void *, const void *));

The *base is the start of the array or data to sort; nel is the number of elements; width is the size of each element (most likely the datatype), and *compar() is a function that compares the data, spawning the sort.

The compar() function has a very specific format. Here’s what most programmers purloin from StackOverflow:

int compare(const void *a, const void *b)
{
    return( *(int *)a - *(int *)b);
}

Effectively, the return statement determines the difference between two elements in the array, generating a value negative, zero, or positive. The qsort() function uses this result to sort the list. Changing the expression’s variable order reverses the sort.

And that’s about as much thought as anyone puts into the task — unless faced with something like the sample code shown below.

2022_12_01-Lesson.c

#include <stdio.h>
#include <stdlib.h>

struct film {
    char title[32];
    int year;
};

int compare(const void *a, const void *b)
{
}

int main()
{
    const int size = 9;
    struct film bond[size] = {
        { "Casino Royale", 2006 },
        { "Dr. No", 1962 },
        { "GoldenEye", 1995 },
        { "Goldfinger", 1964 },
        { "Moonraker", 1979 },
        { "Octopussy", 1983 },
        { "Skyfall", 2012 },
        { "Spectre", 2015 },
        { "Thunderball", 1965 }
    };
    int x;

    /* sort the list by year */
    qsort(bond,size,sizeof(struct film),compare);

    /* output results */
    for( x=0; x<size; x++ )
        printf("%d, %s\n",
                bond[x].year,
                bond[x].title
              );

    return(0);
}

An array of James Bond films is presented as bond[]. Each structure contains a movie name and the year it was released.

The qsort() function is called at Line 30, which sorts the list by year. A for loop outputs the results, which looks like this:

1962, Dr. No
1964, Goldfinger
1965, Thunderball
1979, Moonraker
1983, Octopussy
1995, GoldenEye
2006, Casino Royale
2012, Skyfall
2015, Spectre

Your task is to code the compare() function. You must deal with the year member in the film structure, comparing each value and processing the results to create a proper sort.

Yes, this task is a bastard. When faced with this challenge myself a few months back, I gave up and did something other than a quick sort. But the problem persisted because I knew a solution was possible! You can discover it as well, providing you properly deal with the const void pointers and somehow mangle them properly to obtain the year member from each structure passed to the compare() function.

Have fun! Click here to view my solution, but try this exercise on your own before you peek to see what I did.

4 thoughts on “Quick Sorting Structures

  1. You just need to cast a and b to film instead of int, and then use -> to get the year:

    ((film*)a)->year

    Sorting strings is easier because you can use strcmp (string.h) which returns 0 as required by qsort.

    There are actually two Casino Royale films, the other made in 1967. I haven’t seen it but I assume Bond is briefed by M, given some hi-tech gadgetry and a shiny new Aston Martin by Q, and then jets off to some exotic location to deal with an evil criminal mastermind.

    Anyway, if they were both in the array it would be nice to sort by name and year . . .

Leave a Reply