#include #include #include "std-macros.h" /** * * This program exercises the system qsort function. The focus is on the * comparator functions that qsort calls, as an illustration of using function * pointers in C. * */ /** * Compare two void* values as ints, by casting them and using normal numeric * comparison. */ int intcmp(const void* a1, const void* a2) { int v1 = *((int*) a1); int v2 = *((int*) a2); if (v1 < v2) return -1; if (v1 > v2) return 1; return 0; } /** * Like intcmp, but reverses the sense of the comparison. This allows the * sorting order to defined as descending, without changing the implementation * of the sort function. */ int intcmp_reverse(const void* a1, const void* a2) { int v1 = *((int*) a1); int v2 = *((int*) a2); if (v1 > v2) return -1; if (v1 < v2) return 1; return 0; } /** * Compare two void* values as numeric strings, by casting them to char*, then * converting them using atoi, then using normal numeric comparison. * * Note here the intermediate use of char** as a cast, then the deference down * to char*. I.e,. the following code is used to cast the incoming void* * argument a1 into the char* variable s1: * * char* s1 = *((char**) a1); * * The deal is that qsort works with pointers to the array values it's sorting, * not the values themselves. In this case, the array being sorted contains * char* values. This means that qsort is working with element pointers of * type char**, since it's pointing to each char* element of the arrays. * Hence, this function receives values of type char**, carried in the generic * pointers of type void*. */ int str_intcmp(const void* a1, const void* a2) { char* s1 = *((char**) a1); char* s2 = *((char**) a2); int v1 = atoi(s1); int v2 = atoi(s2); if (v1 < v2) return -1; if (v1 > v2) return 1; return 0; } /** * The main function defines unsorted int and string arrays. It then calls the * system qsort function to sort the int array in ascending and descending * orders, using the preceding two int comparison functions. It also calls * qsort to sort the string array in ascending order, using str_intcmp. */ int main() { int i; int int_data[6] = {1, 8, 3, 4, 2, 1}; char* str_data[6] = {"1", "8", "3", "4", "2", "1"}; size_t int_nelems = sizeof(int_data) / sizeof(int); size_t str_nelems = sizeof(str_data) / sizeof(int); /* * Print the int array before sorting. */ for (i = 0; i < int_nelems; i++) printf("%d ", int_data[i]); printf("\n"); /* * Sort the int array using intcmp comparator and print results. */ qsort((void*) int_data, int_nelems, sizeof(int), intcmp); for (i = 0; i < int_nelems; i++) printf("%d ", int_data[i]); printf("\n"); /* * Sort the int array using intcmp_reverse comparator and print results. */ qsort((void*) int_data, int_nelems, sizeof(int), intcmp_reverse); for (i = 0; i < int_nelems; i++) printf("%d ", int_data[i]); printf("\n"); /* * Print the string array before sorting. */ for (i = 0; i < str_nelems; i++) printf("%s ", str_data[i]); printf("\n"); /* * Sort the string array using str_intcmp comparator and print results. */ qsort((void*) str_data, str_nelems, sizeof(char*), str_intcmp); for (i = 0; i < str_nelems; i++) printf("%s ", str_data[i]); printf("\n"); /* * Sort the string array using strcmp as the comparator and print results. * Note the cast applied to strcmp as a function pointer. It's required in * order for the compiler not to issue a warning. It works because 'const * void *' is compatible as a parameter type with the 'const char *' type * that strcmp's parameters are declared with. "Compatible" means that a * void* formal parameter may be safely passed a pointer of any other * type. See Section A.6.8 on Page 199 of K&R. */ qsort((void*) str_data, str_nelems, sizeof(char*), (int (*) (const void*, const void*)) strcmp); for (i = 0; i < str_nelems; i++) printf("%s ", str_data[i]); printf("\n"); exit(0); }