4

When I'm learning to use qsort to sort an array of string, there is a question puzzled me. For example, to sort the following s

 char *s[] = {
                   "Amit",
                   "Garima",
                   "Gaurav",
                   "Vaibhav"
                };

To use the qsort, you must provide a comparison function like the following function cstring_cmp I guess in the qsort function, the type of parameter to be passed to the function cstring_cmp is char**. How to convert a char** to a void*? Why can we convert a char** to a void*?

    int cstring_cmp(const void *a, const void *b)
    {
        const char **ia = (const char **)a;
        const char **ib = (const char **)b;
        return -strcasecmp(*ia, *ib);
        /* return the negative of the normal comparison */
    }
1
  • qsort() in this example will pass the address of each char * being examined. they are pointers to pointers. And this is exactly how it should be (again for this example). Greg you do NOT have it wrong (unless we both do, but judging by the OPs code, we don't). Commented Nov 5, 2012 at 3:38

3 Answers 3

2

Your question seems a bit vague but I'll give it a go anyway. To answer how, you can convert any pointer type to any other pointer type in C by simply casting. To answer why, well that's how C is defined.

The qsort() function requires a function with the given prototype (with const void *) parameters. This is because qsort() is unaware of the actual data type you are sorting, and must use a consistent function prototype for the comparison callback. Your comparison callback is responsible for converting the const void * parameters to pointers to the actual types in your array, in your case const char **.

Sign up to request clarification or add additional context in comments.

3 Comments

+1: I leave to write out a sample, come back and the entire comment stream is gone except for my original comment to you. did I miss something ? =P
@WhozCraig: yes, I suppose you did. :) The original commenter who suggested that a const char * was sufficient in the comparison function retracted his comments after I provided a counterexample. This is SO working as it should - incorrect information gets removed!
I somewhat figured. The sample I provided below is precisely what we (you and I) were referring to. I've done this very thing a zillion times with pointer arrays, so i was pretty sure we weren't hallucinating.
2

The example you provide is being setup to ask qsort() to sort an array of char pointers (char *). This comparator you're providing is given each 'pair' of items the algorithm needs, by address. two char pointers. the address qsort() uses is based on the root address you give it, adding size-bytes per "item". Since each "item" is a char*, the size of each item is, in fact, the size of a pointer.

I've modified the comparator to demonstrate what is being compared, and what the addresses are that are being passed in. you will see they are all increments off the base address of the array containing all the char *s.

char *mystrings[] =
{
    "This",
    "is",
    "a",
    "test",
    "of",
    "pointers",
    "to",
    "strings"
};

int cstring_cmp(const void *a, const void *b)
{
    const char **ia = (const char **)a;
    const char **ib = (const char **)b;
    printf("%p:%s - %p:%s\n", a, *ia, b, *ib);
    return -strcasecmp(*ia, *ib);
}

int main(int argc, char *argv[])
{
    printf("Base address of our pointer array: %p\n\n", mystrings);
    qsort(mystrings, sizeof(mystrings)/sizeof(mystrings[0]), sizeof(char*), cstring_cmp);
    for (size_t i=0; i<sizeof(mystrings)/sizeof(mystrings[0]);i++)
        printf("%s\n", mystrings[i]);
    return 0;

}

produces the following output:

Base address of our pointer array: 0x100006240

0x100006240:This - 0x100006260:of
0x100006260:of - 0x100006278:strings
0x100006240:This - 0x100006278:strings
0x100006248:is - 0x100006240:strings
0x100006278:This - 0x100006240:strings
0x100006250:a - 0x100006240:strings
0x100006270:to - 0x100006240:strings
0x100006258:test - 0x100006240:strings
0x100006260:of - 0x100006240:strings
0x100006268:pointers - 0x100006240:strings
0x100006260:of - 0x100006240:strings
0x100006240:test - 0x100006248:This
0x100006248:test - 0x100006250:to
0x100006240:This - 0x100006248:to
0x100006260:of - 0x100006268:pointers
0x100006268:of - 0x100006270:a
0x100006270:a - 0x100006278:is
0x100006268:of - 0x100006270:is
to
This
test
strings
pointers
of
is
a

Comments

0

A even less visualized one:

int cstring_cmp(const void *a, const void *b){
    return -strcasecmp((char *)(*((char **)a)), (char *)(*((char **)b)));
}

But you can see , a and b are char **, and they are dereferenced and become char * and passed to strcasecmp.


#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int cstring_cmp(const void *a, const void *b){
    return -strcasecmp((char *)(*((char **)a)), (char *)(*((char **)b)));
}

int main(){
    char *s[] = {  "Amit",
                   "Garima",
                   "Vaibhav",
                   "Gaurav"};
    qsort(s, 4, sizeof(char *), cstring_cmp);
    printf("%s\n%s\n%s\n%s\n", s[0], s[1], s[2], s[3]);
    return 0;
}

Output:

Vaibhav
Gaurav
Garima
Amit

It is legal to cast any pointer to char * or void * because void * means a pointer to a memory (RAM or virtual) byte.

2 Comments

Wrong. For sorting an array of int, what is passed to the comparator function is an int * (cast as const void *). For sorting an array of char *, what is passed to the function is char ** (cast as const void *).
No, this code is not valid! You are not comparing the strings, but you are comparing addresses by feeding them to the strcasecmp() function, which makes no sense. Check this by printing the value of ia as a string in your comparison function. Or see what happens when you swap two of the strings in the initial array.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.