this is for the qsort comparison function,
int cmp(const void *p, const void *q) {
char *const* pp = p;
char *const* qq = q;
...
}
i want to compare the elements of the two strings. i tried (*pp)[i] since *pp is p, but it doesnt seem to work. also, what is the advantage of catching p and q this way instead of just creating two const char *?
last but no least, i have another comparison function that is supposed to skip leading white spaces
int wcmp(const void *p, const void *q) {
const char *pp = p;
const char *qq = q;
size_t i = 0;
size_t j = 0;
while(isspace(*(pp+i))) {
i++;
}
while(isspace(*(qq)+j)) {
j++;
}
return strcmp(pp+i, qq+j);
}
but when i test it with
d afdsa
hello
heal
the output is
heal
d afdsa
hello
what is going on with "d afdsa" in the middle?
qsort
works for elements of any size. The only way it can work is by passing pointers to the first bytes of the elements, and these are of type const void *
.
So if you have an array of int
s, the comparison function gets 2 pointers to void
, that actually points to 2 int
s in the array, and you compare the pointed-to objects:
int cmp(const void *p, const void *q) {
int *pp = p;
int *qq = q;
return *pp - *qq; // for example, ignoring all possible UB and such.
}
Likewise, if you have an array of pointers to char, i.e. char *array[]
, then each element is a pointer to char, and the comparison function gets passed in 2 arguments: pointers to const void that point to these elements. When you cast them back you get:
char *const *pp = p;
I.e. a pointer to a constant pointer to char. The actual objects that you must compare are pointed-to by these pointers.
And this is why your wcmp
doesn't work:
int wcmp(const void *p, const void *q) {
const char *pp = p;
const char *qq = q;
...
}
This would be appropriate if each element in the array to be sorted was a char
. But the elements were pointers to char, so it means that the arguments to wcmp
(each of which points to an element in the array) must be converted to pointers to pointers to char:
int wcmp(const void *p, const void *q) {
char *const *ptmp = p;
char *const *qtmp = q;
Then you must dereference them to get the actual pointer to char
char *pp = *ptmp; // dereference them
char *qq = *qtmp;
Or, you can shorten those 2 to:
char *pp = *(char *const *)p;
char *qq = *(char *const *)q;
As for the rest of the wcmp
, that's not really C - a true C programmer loves changing pointers:
while(isspace(*pp)) {
pp ++;
}
while(isspace(*qq)) {
qq ++;
}
return strcmp(pp, qq);
}
that is, for as long as pp
points to a space character, increment pp
so that it points to the next character; and do the same for qq
too, and then compare the strings whose first characters are pointed to by pp
and qq
.