Sorting and Searching
Sorting data and finding things in it are among the most common jobs a program does. C's standard library provides a general-purpose sort, qsort, and binary search, bsearch, that work on arrays of any type — once you know how to write the comparison function.
Sorting numbers with qsort
qsort(base, count, size, compare) sorts an array in place. You supply a function that receives pointers to two elements and returns a negative number, zero or a positive number:
#include <stdio.h> #include <stdlib.h> int compare_doubles(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 times[] = { 12.4, 9.81, 11.02, 9.58, 10.0 }; size_t n = sizeof times / sizeof times[0]; qsort(times, n, sizeof times[0], compare_doubles); for (size_t i = 0; i < n; i++) printf("%.2f ", times[i]); printf("\n"); return 0; }
9.58 9.81 10.00 11.02 12.40
Sorting structs
The comparison can look at any member, and break ties with a second one:
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { char name[16]; int points; } Team; int by_points_then_name(const void *a, const void *b) { const Team *x = a, *y = b; if (x->points != y->points) return y->points - x->points; // more points first return strcmp(x->name, y->name); // then alphabetical } int main(void) { Team table[] = { { "Rovers", 54 }, { "Athletic", 61 }, { "City", 54 }, { "United", 47 } }; size_t n = sizeof table / sizeof table[0]; qsort(table, n, sizeof table[0], by_points_then_name); for (size_t i = 0; i < n; i++) { printf("%zu. %-10s %d\n", i + 1, table[i].name, table[i].points); } return 0; }
1. Athletic 61 2. City 54 3. Rovers 54 4. United 47
const Team *x = a; converts the const void * back to the real type — no cast is needed in C.
Sorting strings
For an array of char *, each element is a pointer, so the comparison receives pointers to pointers:
#include <stdio.h> #include <stdlib.h> #include <string.h> int compare_strings(const void *a, const void *b) { const char *const *x = a; const char *const *y = b; return strcmp(*x, *y); } int main(void) { const char *fruits[] = { "pear", "apple", "fig", "banana", "cherry" }; size_t n = sizeof fruits / sizeof fruits[0]; qsort(fruits, n, sizeof fruits[0], compare_strings); for (size_t i = 0; i < n; i++) printf("%s ", fruits[i]); printf("\n"); return 0; }
apple banana cherry fig pear
Passing strcmp directly would be a bug: it would receive pointers to the pointers, not the strings.
Binary search with bsearch
On a sorted array, bsearch finds an element in about log2(n) steps. It returns a pointer to the match, or NULL, and uses the same kind of comparison function:
#include <stdio.h> #include <stdlib.h> int compare_ints(const void *a, const void *b) { int x = *(const int *) a, y = *(const int *) b; return (x > y) - (x < y); } int main(void) { int ids[] = { 1043, 1187, 1201, 1356, 1499, 1602, 1777 }; size_t n = sizeof ids / sizeof ids[0]; int wanted[] = { 1356, 1400 }; for (int i = 0; i < 2; i++) { int *found = bsearch(&wanted[i], ids, n, sizeof ids[0], compare_ints); if (found) printf("%d found at index %td\n", wanted[i], found - ids); else printf("%d not found\n", wanted[i]); } return 0; }
1356 found at index 3 1400 not found
Writing a sort yourself
Insertion sort is simple and fast for small or nearly sorted arrays — which is why real sort implementations often switch to it for short ranges:
#include <stdio.h> void insertion_sort(int *a, size_t n) { for (size_t i = 1; i < n; i++) { int key = a[i]; size_t j = i; while (j > 0 && a[j - 1] > key) { a[j] = a[j - 1]; // shift larger elements right j--; } a[j] = key; } } int main(void) { int cards[] = { 7, 2, 9, 4, 1, 8 }; insertion_sort(cards, 6); for (int i = 0; i < 6; i++) printf("%d ", cards[i]); printf("\n"); return 0; }
1 2 4 7 8 9
Insertion sort takes time proportional to n² in the worst case; qsort implementations use O(n log n) algorithms. For large data, use the library.
Comparison function rules
- Return negative, zero or positive — only the sign matters.
- Be consistent: if a < b and b < c, then a < c must hold, or the sort may misbehave.
- Avoid
return x - y;for values that might overflow (large or mixed-sign integers). qsortisn't stable: equal elements may end up in any order. Add a tie-breaker if order matters.
Try it yourself
Sort words by length (shortest first), with alphabetical order for words of equal length.
fig kiwi plum apple banana cherry