I'm taking a specialization on Coursera and in a lesson it explains the qsort() function that sorts a given array:
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
where we should provide qsort() with four parameters - the array to sort, number of elements in the array, size of each element of the array, and a pointer to a function (compar) which takes two const void *s and returns an int. The lesson says that we need to write the compar
function to be compatible with the qsort
function, so if we would like to compare two strings the function should look like:
int compareStrings(const void * s1vp, const void * s2vp) {
// first const: s1vp actually points at (const char *)
// second const: cannot change *s1vp (is a const void *)
const char * const * s1ptr = s1vp;
const char * const * s2ptr = s2vp;
return strcmp(*s1ptr, *s2ptr);
}
void sortStringArray(const char ** array, size_t nelements) {
qsort(array, nelements, sizeof(const char *), compareStrings);
}
It says: Note that the pointers passed in are pointers to the elements in the array (that is, they point at the boxes in the array), even though those elements are themselves pointers (since they are strings). When we convert them from void *s, we must take care to convert them to the correct type—here, const char * const *—and use them appropriately, or our function will be broken in some way. For example, consider the following broken code:
// BROKEN DO NOT DO THIS!
int compareStrings(const void * s1vp, const void * s2vp) {
const char * s1 = s1vp;
const char * s2 = s2vp;
return strcmp(s1, s2);
}
The thing that I can't really get is why didn't we consider s1vp and s2vp as pointers to pointers? I mean, since the arguments passed to the function compareStrings
are addresses of pointers pointing to strings (address of pointer), shouldn't we have declared s1vp and s2vp as int compareStrings(const void ** s1vp, const void ** s2vp)
since they are receiving addresses of pointers?
In other words, I'm passing, for example, the address of the first element of the array of strings, which is actually a pointer, to s1vp. So now s1vp is receiving address of pointer not a variable, so We should declare it as pointer to pointer, right? It gives me warning when I try to do so...
A void *
can point to any datatype. The fact that the datatype in question is also a pointer doesn't change things.
Also, you can't change the signature of the comparison function, otherwise it would be incompatible with what qsort
is expecting and can lead to undefined behavior.