I have written this qsort:
void qsort(void *a[],int low,int high, int (*compare)(void*,void*));
When I call this on
char *strarr[5];
It says invalid conversion from char** to void**. Why this is wrong?
This is the code:
#include<cstdlib>
#include<cstdio>
#include<iostream>
using namespace std;
inline void strswap(void *a,void *b) {
char *t=*(char**)a;
*(char**)a=*(char**)b;
*(char**)b=t;
}
int strcompare(void *a, void *b) {
return strcmp(*(char**)a,*(char**)b);
}
void qsort1(void *a[],int low,int high, int (*compare)(void*,void*), void (*swap)(void*,void*)) {
if(low>=high)
return;
int q=low-1;
for(int i=low;i<=high-1;i++)
if((*compare)(&a[i],&a[high]) < 0)
swap(&a[i],&a[++q]);
swap(&a[high],&a[++q]);
qsort1(a,low,q-1,compare,swap);
qsort1(a,q+1,high,compare,swap);
}
int main() {
const int n=3;
//int a[n]={4,6,8,12,10,9,8,0,24,3};
char *strarr[5]={"abcd","zvb","cax"};
qsort1(strarr,0,n-1,strcompare,strswap);
for(int i=0;i<n;i++)
cout << strarr[i] << " ";
cout << endl;
return 0;
}
An implicit conversion from any pointer type to
void *is allowed, becausevoid *is a defined to be a pointer type that has a sufficient range that it can represent any value that any other pointer type can. (Technically, only other object pointer types, which excludes pointers to functions).This does not mean that
void *has the same size or representation as any other pointer type, though: Converting a pointer from another pointer type to avoid *does not necessarily leave the underlying representation unchanged. Converting fromdouble *tovoid *is just like converting fromdoubletoint– it has to happen in full view of the compiler, you can’t hide that conversion behind the compiler’s back.So this implies that while
void *is a generic pointer,void **is not a generic pointer-to-pointer. It’s a pointer tovoid *– avoid **pointer should only ever point to realvoid *objects (whereasvoid *itself can point to anything).This is why there’s no implicit conversions between
type **andvoid **– it’s for the same reason that there’s no implicit conversions betweendouble *andint *.Now, there is one special case: for historical reasons,
char *is guaranteed to have the same size, representation and alignment requirements asvoid *. This means that conversions betweenchar **(in particular) andvoid **are actually OK, as an exception to the general rule. So in your particular case, your code is correct if you add a cast tovoid **when you passstrarrtoqsort1().However, your
qsort1()is only defined to correctly work on arrays ofvoid *orchar *(includingunsigned char *etc.). You can’t use it to sort an array ofdouble *pointers, for example (although it would actually work on most common environments today).