Skip to Content
Course content
Click on the "Edit" button in the top corner of the screen to edit your slide content.

A few years ago, I worked with a junior developer who spent an entire weekend implementing a custom QuickSort from scratch. He was building a small game engine and needed to sort a list of enemy NPCs by their distance to the player to handle rendering priority. He had a subtle bug in his partition logic that only triggered when exactly three enemies were at the same distance, causing a segmentation fault that drove him crazy. When I finally looked at his code, I asked why he was reinventing the wheel. He didn't realize that the C standard library already provides a highly optimized, battle-tested sorting function. He had spent forty-eight hours debugging something that could have been solved with a single function call to qsort.

The Generic Nature of qsort

The power of qsort, found in <stdlib.h>, is that it is generic. It doesn't know if you're sorting integers, floating-point numbers, or a complex custom struct. Because it doesn't know the data type, it can't possibly know how to determine if one element is "less than" another. This is where you come in. You provide qsort with a comparison function—a pointer to a function you've written that tells qsort how to compare two elements of your specific type.

The function signature for qsort looks like this: void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));. The first three arguments are straightforward: the pointer to the start of the array, the number of elements, and the size of each element in bytes. The fourth argument is the tricky part. It's a function pointer to your comparison logic.

Writing the Comparison Logic

Your comparison function must take two const void * arguments and return an integer. This is the "contract" with qsort: if the return value is negative, the first element comes before the second; if positive, the second comes first; if zero, their relative order doesn't matter. Since the arguments are void *, you have to cast them back to your actual data type before you can dereference them.

Here is how I usually handle a simple array of integers:

int compare_ints(const void *a, const void *b) {
    int arg1 = *(const int *)a;
    int arg2 = *(const int *)b;
 
    if (arg1 < arg2) return -1;
    if (arg1 > arg2) return 1;
    return 0;
}

You might be tempted to just return arg1 - arg2. While that works for small positive integers, it's a dangerous habit. If you're dealing with very large positive and negative numbers, the subtraction can overflow, leading to an incorrect sort or a crash. Explicit comparisons are safer and clearer.

Sorting Complex Structs

The real utility of qsort appears when you're dealing with structures. Let's say you have a Player struct and you want to sort a leaderboard by score in descending order. You don't need to move the actual structs around manually; you just tell qsort how to look inside the struct to find the score.

typedef struct {
    char name[32];
    int score;
} Player;

int compare_players(const void *a, const void *b) {
    const Player *playerA = (const Player *)a;
    const Player *playerB = (const Player *)b;

    // For descending order, we flip the logic: 
    // return -1 if B is smaller than A
    if (playerA->score > playerB->score) return -1;
    if (playerA->score < playerB->score) return 1;
    return 0;
}

// Usage:
// qsort(leaderboard, num_players, sizeof(Player), compare_players);

I've seen developers struggle here because they forget that qsort passes pointers to the elements, not the elements themselves. Always remember: cast the void * to your type pointer, then dereference it to get to your data.




📋 Practical Task

Implement a Product Price Sorter

You are building a simple inventory system. You have a Product struct containing a name (string) and a price (double). Your task is to implement a comparison function and use qsort to sort an array of products from cheapest to most expensive.

Requirements:

  • Define a Product struct with char name[50] and double price.
  • Write a comparison function compare_products that handles double values correctly (remember that you cannot simply subtract doubles and return an int without risking precision loss or incorrect results).
  • Create an array of at least 5 products with unsorted prices.
  • Call qsort and print the resulting sorted list to the console.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.