C Academy · Lesson

qsort with Comparators

Standard library callbacks.

Lesson 3 of 413 steps

qsort with Comparators is a free C Academy lesson on CoddyKit. This is lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the C Academy learning path, and your progress syncs across the web and the CoddyKit app. The C Academy course includes 4 lessons in total.

The Standard qsort

The standard library provides qsort in <stdlib.h>, a generic sort that works on any array type by using a comparator callback.

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

int cmp_int(const void *a, const void *b) {
    int x = *(const int *)a;
    int y = *(const int *)b;
    return (x > y) - (x < y);
}

int main(void) {
    int a[] = {3, 1, 2};
    qsort(a, 3, sizeof(int), cmp_int);
    printf("%d %d %d\n", a[0], a[1], a[2]);
    return 0;
}

The qsort Signature

qsort(base, count, size, compare) takes the array start, element count, element size, and a comparator.

It is generic because it works with raw bytes plus your comparator.

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

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

int main(void) {
    int a[] = {9, 4, 7, 1};
    qsort(a, 4, sizeof(int), cmp);
    for (int i = 0; i < 4; i++) printf("%d ", a[i]);
    printf("\n");
    return 0;
}

The Comparator Contract

The comparator returns a negative value if the first element should come before the second, zero if equal, and positive if after.

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

int cmp(const void *a, const void *b) {
    int x = *(const int*)a, y = *(const int*)b;
    if (x < y) return -1;
    if (x > y) return 1;
    return 0;
}

int main(void) {
    int a[] = {5, 2, 8, 2};
    qsort(a, 4, sizeof(int), cmp);
    for (int i = 0; i < 4; i++) printf("%d ", a[i]);
    printf("\n");
    return 0;
}

Casting void Pointers

The comparator receives const void * for each element. Cast them to the correct type and dereference to read the values.

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

int cmp(const void *a, const void *b) {
    double x = *(const double*)a;
    double y = *(const double*)b;
    return (x > y) - (x < y);
}

int main(void) {
    double d[] = {2.5, 1.1, 3.3};
    qsort(d, 3, sizeof(double), cmp);
    printf("%.1f %.1f %.1f\n", d[0], d[1], d[2]);
    return 0;
}

Descending Order

Reverse the comparison to sort from largest to smallest.

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

int desc(const void *a, const void *b) {
    int x = *(const int*)a, y = *(const int*)b;
    return (y > x) - (y < x);
}

int main(void) {
    int a[] = {1, 5, 3, 2};
    qsort(a, 4, sizeof(int), desc);
    for (int i = 0; i < 4; i++) printf("%d ", a[i]);
    printf("\n");
    return 0;
}

Avoid Subtraction Overflow

Returning x - y can overflow for large integers. The safe idiom (x > y) - (x < y) avoids that.

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

int safe_cmp(const void *a, const void *b) {
    int x = *(const int*)a, y = *(const int*)b;
    return (x > y) - (x < y);
}

int main(void) {
    int a[] = {100, -100, 0};
    qsort(a, 3, sizeof(int), safe_cmp);
    for (int i = 0; i < 3; i++) printf("%d ", a[i]);
    printf("\n");
    return 0;
}

Sorting Strings

For an array of char *, each element is itself a pointer, so cast to const char * const * and compare with strcmp.

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

int cmp_str(const void *a, const void *b) {
    const char *sa = *(const char * const *)a;
    const char *sb = *(const char * const *)b;
    return strcmp(sa, sb);
}

int main(void) {
    const char *w[] = {"pear", "apple", "fig"};
    qsort(w, 3, sizeof(char*), cmp_str);
    for (int i = 0; i < 3; i++) printf("%s ", w[i]);
    printf("\n");
    return 0;
}

Sorting Structs

qsort handles arrays of structures too. Compare a chosen field inside the comparator.

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

typedef struct { char name; int age; } Person;

int by_age(const void *a, const void *b) {
    int x = ((const Person*)a)->age;
    int y = ((const Person*)b)->age;
    return (x > y) - (x < y);
}

int main(void) {
    Person p[] = {{'C',30},{'A',20},{'B',25}};
    qsort(p, 3, sizeof(Person), by_age);
    for (int i = 0; i < 3; i++) printf("%c:%d ", p[i].name, p[i].age);
    printf("\n");
    return 0;
}

bsearch Uses the Same Idea

bsearch performs a binary search on a sorted array using a comparator with the same contract as qsort.

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

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

int main(void) {
    int a[] = {1, 3, 5, 7, 9};
    int key = 7;
    int *found = bsearch(&key, a, 5, sizeof(int), cmp);
    printf("found: %d\n", found ? *found : -1);
    return 0;
}

Multiple Sort Keys

A comparator can compare a primary field, then a secondary field when the first ties.

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

typedef struct { int grade; int id; } Rec;

int cmp(const void *a, const void *b) {
    const Rec *x = a, *y = b;
    if (x->grade != y->grade) return x->grade - y->grade;
    return x->id - y->id;
}

int main(void) {
    Rec r[] = {{90,2},{90,1},{80,3}};
    qsort(r, 3, sizeof(Rec), cmp);
    for (int i = 0; i < 3; i++) printf("%d/%d ", r[i].grade, r[i].id);
    printf("\n");
    return 0;
}

Why Generic Sort Matters

Because qsort separates the algorithm from the comparison, one well-tested function sorts any data type you can compare.

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

int cmp(const void *a, const void *b) {
    char x = *(const char*)a, y = *(const char*)b;
    return (x > y) - (x < y);
}

int main(void) {
    char s[] = "dcba";
    qsort(s, 4, sizeof(char), cmp);
    printf("%s\n", s);
    return 0;
}

Quick Check

Test your understanding of qsort comparators.

Recap

You learned to use qsort with comparators:

  • qsort(base, count, size, compare) sorts any array generically.
  • The comparator takes two const void * and returns negative, zero, or positive.
  • Use (x > y) - (x < y) to avoid overflow.
  • The same comparator contract powers bsearch, struct sorts, and multi-key sorts.
Free to start

Learn C with an AI tutor — free

Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.

Courses
39
Lessons
144

Frequently Asked Questions

Is the “qsort with Comparators” lesson free?

Yes — the full text of “qsort with Comparators” is free to read here on the web. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the C Academy course, upgrade to CoddyKit PRO. The C Academy course includes 4 lessons in total.

What will I learn in “qsort with Comparators”?

Standard library callbacks. You practise C Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start C Academy?

No prior experience is required. C Academy on CoddyKit is structured for beginners through advanced learners, so you can start here or from the beginning and move at your own pace. This is lesson 3 of 4.

How long does the “qsort with Comparators” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this C Academy lesson?

Yes. Every C Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Declaring Function Pointers
  2. Passing Functions
  3. qsort with Comparators
  4. Function Pointer Tables
← Back to C Academy