1
votes

So I have a C function that goes like this:

int cmp (const void *a, const void* b)
 return rot13cmp( (const char*)a, (const char*)b );
}

and rot13cmp is another function that takes two parameters of type const char *.

I pass this function into the compare parameter for the C qsort function but it doesn't seem to work.

However, if I instead cast the const void * variables by doing

return rot13cmp ( *(const char **)a, *(const char **)b ); 

the function then starts to work. I looked this up at SO but every source said that the first method of casting should work so I wanted to know why only the second one worked for me?

Edit: Here's the relevant code I have,

int cmp (const void *a, const void *b) {
 return rot13cmp( (const char *)a, (const char *)b );
}

int rot13cmp (const char *a, const char *b) {
 while (*a == *b && *a != '\n') {
  a++;
  b++;
 }

 if (*a == *b) { return 0; }
 else if (*a == '\n') { return 1; }
 else if (*b == '\n') { return 1; }
 else { return rot13(*a) - rot13(*b);
}

and rot13 returns an int for the ASCII code of a letter rotated by 13 letters in the alphabet.

I called qsort by doing

qsort(words, word_count, sizeof(char*), cmp);

where words is an array of char** and word_count is an int. cmp is also just

1
I feel like an SSCCE would really help here.Baum mit Augen
There must be a different reason for this to happen.Iharob Al Asimi
So how did you call qsort()?timrau
We can't know anything about that if you don't show us what type your a and b have originally. From what you describe I'd guess they are pointers to pointers, but without information this is pure guessing.Jens Gustedt
Sorry about that, I added the relevant code above.Chang Liu

1 Answers

4
votes

qsort() calls the comparison function with pointers to the array elements that should be compared.

If your array contains const char*, that means the comparison function is called with pointers to those pointers, and you have to cast and dereference accordingly.

With (const char*)a you are interpreting the parameter as if it would be a pointer to const char. But it isn't. In reality it's a pointer to the const char* in the input array.

That's why (const char**)a is the correct cast, it interprets the parameter as a pointer to a const char*. To do string comparison you want that pointed-to const char*, which you access by dereferencing the casted value with *.

You can think of it as first correcting the type (by casting), and then accessing the pointed-to value (by dereferencing).

The difference between the two attempts is that the second case does an additional dereference. This is important since qsort() doesn't pass the const char* directly, but rather passes a pointer to it. So we have to look at the pointed-to value to find what we are looking for. By casting directly to const char* we just claim that the variable would contain such a pointer, which won't end well because that's not the case.