Suppose I have an array of pointers to char in C:
char *data[5] = { "boda", "cydo", "washington", "dc", "obama" };
And I wish to sort this array using qsort:
qsort(data, 5, sizeof(char *), compare_function);
I am unable to come up with the compare function. For some reason this doesn't work:
int compare_function(const void *name1, const void *name2)
{
const char *name1_ = (const char *)name1;
const char *name2_ = (const char *)name2;
return strcmp(name1_, name2_);
}
I did a lot of searching and found that I had to use **
inside of qsort:
int compare_function(const void *name1, const void *name2)
{
const char *name1_ = *(const char **)name1;
const char *name2_ = *(const char **)name2;
return strcmp(name1_, name2_);
}
And this works.
Can anyone explain the use of *(const char **)name1
in this function? I don't understand it at all. Why the double pointer? Why didn't my original function work?
Thanks, Boda Cydo.
Imagine your data was
double data[5]
.Your compare method would receive pointers (double*, passed as void*) to the elements (double).
Now replace double with char* again.
If it helps keep things straight in your head, the type that you should cast the pointers to in your comparator is the same as the original type of the data pointer you pass into
qsort
(that the qsort docs callbase
). But forqsort
to be generic, it just handles everything asvoid*
, regardless of what it "really" is.So, if you're sorting an array of ints, then you will pass in an
int*
(converted tovoid*
). qsort will give you back twovoid*
pointers to the comparator, which you convert toint*
, and dereference to get theint
values that you actually compare.Now replace
int
withchar*
:if you're sorting an array of
char*
, then you will pass in achar**
(converted tovoid*
). qsort will give you back twovoid*
pointers to the comparator, which you convert tochar**
, and dereference to get thechar*
values you actually compare.In your example, because you're using an array, the
char**
that you pass in is the result of the array ofchar*
"decaying" to a pointer to its first element. Since the first element is achar*
, a pointer to it is achar**
.qsort
is general enough to sort arrays consisting of other things than pointers. That's why the size parameter is there. It cannot pass the array elements to the comparison function directly, as it does not know at compile time how large they are. Therefore it passes pointers. In your case you get pointers tochar *
,char **
.The comparison function takes pointers to the type of object that's in the array you want to sort. Since the array contains
char *
, your comparison function takes pointers tochar *
, akachar **
.from
man qsort
:So it sounds like the comparison function gets pointers to the array elements. Now a pointer to a
char *
is achar **
(i.e. a pointer to a pointer to a character).char *data[5] = { "boda", "cydo", "washington", "dc", "obama" };
is a statement asking the compiler for an array of size 5 of character pointers. You have initialized those pointers to string literals, but to the compiler, it's still an array of five pointers.
When you pass that array into
qsort
, the array of pointers decays into a pointer pointing to the first element, in accordance with C array parameter passing rules.Therefore you must process one level of indirection before you can get to the actual character arrays containing the constants.