Search code examples
cpointersstrcmpqsort

in c, if i have char *const* pointer, how do i access each and every element?


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?


Solution

  • 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.