-5

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?

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • Is the type of `pp` literally `char * const *`, or are those asterisks meant for emphasis? –  Jul 25 '17 at 23:45
  • `char *const*` is a different animal than a `const char*`. The first is a pointer to a pointer, the second is a pointer to a `char`. So the first order of business is for you to understand what you really have in those void pointers. – Michael Burr Jul 25 '17 at 23:47
  • 1
    `*(qq)+j` --> `*(qq+j)` ? – BLUEPIXY Jul 25 '17 at 23:50

1 Answers1

4

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 ints, the comparison function gets 2 pointers to void, that actually points to 2 ints 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.