It would help if you showed the definition of wordlist, but most likely it's defined as a char **. The compare() function receives a pointer to each element of your list. If each element of your list is of type char *, then compare() is going to receive two pointers to char *, or two char ** in other words.
The conversion to char ** (note that an actual cast would be superfluous, in this particular case, if you weren't going from a const void pointer, to a non-const char **) itself is necessary because qsort() has to work on any kind of type, so the arguments get converted to void * before they are passed. You can't deference a void * so you have to convert them back to their original types before doing anything with them.
For instance:
#include <stdio.h> int compare_int(void * a, void * b) { int * pa = a; int * pb = b; if ( *pa < *pb ) { return -1; } else if ( *pa > *pb ) { return 1; } else { return 0; } } int compare_double(void * a, void * b) { double * pa = a; double * pb = b; if ( *pa < *pb ) { return -1; } else if ( *pa > *pb ) { return 1; } else { return 0; } } int compare_any(void * a, void * b, int (*cfunc)(void *, void *)) { return cfunc(a, b); } int main(void) { int a = 1, b = 2; if ( compare_any(&a, &b, compare_int) ) { puts("a and b are not equal"); } else { puts("a and b are equal"); } double c = 3.0, d = 3.0; if ( compare_any(&c, &d, compare_double) ) { puts("c and d are not equal"); } else { puts("c and d are equal"); } return 0; }
Outputs:
paul@local:~/src/c/scratch$ ./comp a and b are not equal c and d are equal paul@local:~/src/c/scratch$
The compare_any() function will compare any type which is supported, in this case, int and double, because we can pass a function pointer to it. However, the signature of the passed function must be the same, so we can't declare compare_int() to take two int * arguments, and compare_double() to take two double *. We have to declare them both as taking two void * arguments, and when we do this, we have to convert those void * arguments to something useful within those functions before we can work with them.
What's happening in your case is exactly the same, but the data themselves are pointers, so we're passing pointers to pointers, and so we need to convert void * to, in your case, char **.
EDIT: To explain some confusion in the comments to the original question about how qsort() works, here's the qsort() signature:
void qsort(void *base, size_t nmemb, size_t size, int(*compar)(const void*, const void*))
base is a pointer to the first element of an array, nmemb is the number of members of that array, and size is the size of each element.
When qsort() calls compar on, say, the first and second elements of your array, it'll send the address of the first element (i.e. base itself) and the address of the element (i.e. base + size).
If base was originally declared as an array of int, then the compare function must interpret those pointers it receives as pointers to int, as int *. If base was originally declared as an array of strings, as a char **, then the compare function must interpret those pointers as pointers to char *, i.e. as char **.
In all cases, the compare function gets pointers to elements. If you have an int array, then you must interpret those pointers as int * in your compare function. If you have a char * array, then you must interpret them as char **, and so on.
In this case, you obviously could call strcmp() if you just passed plain char * arguments to the compare function. But, because qsort() is generic it can only pass pointers to the compare function, it can't actually pass the value of your elements - it's the use of void * which allows it to be generic, because any type of object pointer can be converted to void *, but there is no equivalent datatype to which any non-pointer value can be converted. For that reason, it has to work the same way with regular types like int and double, with pointers, and with structs, and the only way to get it to work correctly with all possible types is to have it deal with pointers to elements, not with the elements themselves, even when the elements are themselves also pointers. For this reason, it might seem like you're getting an unnecessary level of indirection, here, but it actually is necessary in order for qsort() to be able to function in the generic way that it does.
You can see this more clearly if I modify the code above so that compare_any() is more similar to qsort(), and takes not two pointers, but a single pointer to a two-element array of various types (slightly contrived example, but we're keeping it simple):
#include <stdio.h> #include <string.h> int compare_int(void * a, void * b) { int * pa = a; int * pb = b; if ( *pa < *pb ) { return -1; } else if ( *pa > *pb ) { return 1; } else { return 0; } } int compare_double(void * a, void * b) { double * pa = a; double * pb = b; if ( *pa < *pb ) { return -1; } else if ( *pa > *pb ) { return 1; } else { return 0; } } int compare_string(void * a, void * b) { char ** pa = a; char ** pb = b; return strcmp(*pa, *pb); } int compare_any(void * arr, size_t size, int (*cfunc)(void *, void *)) { char * first = arr; char * second = first + size; return cfunc(first, second); } int main(void) { int n[2] = {1, 2}; if ( compare_any(n, sizeof(*n), compare_int) ) { puts("a and b are not equal"); } else { puts("a and b are equal"); } double d[2] = {3.0, 3.0}; if ( compare_any(d, sizeof(*d), compare_double) ) { puts("c and d are not equal"); } else { puts("c and d are equal"); } char * s[] = {"abcd", "bcde"}; if ( compare_any(s, sizeof(*s), compare_string) ) { puts("'abcd' and 'bcde' are not equal"); } else { puts("'abcd' and 'bcde' are equal"); } return 0; }
Outputs:
paul@local:~/src/c/scratch$ ./comp a and b are not equal c and d are equal 'abcd' and 'bcde' are not equal paul@local:~/src/c/scratch$
As you can see, there's no way compare_any() could accept both an array of int, and an array of char *, without the compare_string() function getting a pointer it needs to treat as a char **, because of the pointer arithmetic it performs on the array elements. Without that additional level of indirection, neither compare_int() nor compare_double() could function.
sort_order == -1andstrcmpreturnsINT_MIN.strcmpreturnINT_MIN(which is also a macro for what value?)?