We can sort an array like the one above using either of these functions:
#include <stdlib.h>
void qsort(void *base,
size_t nmemb,
size_t size,
int (*cmp)(const void *elem1,
const void *elem2));
#define __STDC_WANT_ 1 #includeLIB_ EXT1__ <stdlib.h>errno_t qsort_s(void *base, rsize_t nmemb, rsize_t size, int (*cmp)(const void *elem1, const void *elem2, void *ctxt), void *ctxt);
Both take the start of an array base, the number of elements in the array
nmemb, the size of each element in
the array size, and a pointer to a
comparison function cmp. Like our
compare_persons function, the
comparison function is expected to take two pointers
elem1 and elem2, and yield positive, negative or zero
according to their relative ordering. Because of the
differing parameter types, we cannot pass a pointer to
compare_persons directly to these
functions without rewriting it. An alternative is to
write a wrapper with the correct types:
static int cmpper_for_qsort(const void *elem1, const void *elem2) { return compare_persons(elem1, elem2); } qsort(database, ENTRY_COUNT, sizeof database[0], &cmpper_for_qsort);
The wrapper for qsort_s
is similar:
static int cmpper_for_qsort_s(const void *elem1, const void *elem2, void *ctxt) { return compare_persons(elem1, elem2); } qsort_s(database, ENTRY_COUNT, sizeof database[0], &cmpper_for_qsort_s, NULL);
The comparison function will only be invoked with
elem1 and elem2 pointing to elements of the specified
array. The final argument to qsort_s is
passed unmodified as the third argument ctxt in every call to the comparison function,
allowing user-defined context to be passed through
without using static storage. In summary, we inject the
behaviour defined by our comparison function into the
sorting algorithm that qsort and
qsort_s
implement. Despite the name, there is no reason to
believe that the algorithm is Quick
Sort; the function may use any algorithm, and may
even choose different algorithms based on, for example,
the size of the array, the size of elements, etc.
qsort_s
returns non-zero if nmemb or
size exceed RSIZE_.
The sorting functions re-arrange elements by copying them byte-by-byte, which is possible because the size of each element is provided. To reduce copying, it might be appropriate to have a separate array of pointers to the structures, and sort the pointers:
const struct person *ptrs[ENTRY_COUNT] = { &database[0], &database[1], &database[2], ... }; static int cmpper_for_qsort(const void *elem1, const void *elem2) { const struct person *const *pp1 = elem1; const struct person *const *pp2 = elem2; return compare_persons(*pp1, *pp2); } qsort(ptrs, ENTRY_COUNT, sizeof ptrs[0], &cmpper_for_qsort);
This technique is also appropriate if you want to build multiple indices to the same array, or an index to something that isn't an array.