views:

383

answers:

2
+3  Q: 

Void pointers in C

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;
}
+9  A: 

Any pointer can be implicitly converted to a void pointer. But your first parameter isn't a void pointer - it's an array of void pointers, and there is no implicit conversion to that. You probably want to declare your function as:

void qsort(void *,int low,int high, int (*compare)(void*,void*));

but it's difficult to say without seeing the code.

anon
+2  A: 

An implicit conversion from any pointer type to void * is allowed, because void * 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 a void * does not necessarily leave the underlying representation unchanged. Converting from double * to void * is just like converting from double to int - 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 to void * - a void ** pointer should only ever point to real void * objects (whereas void * itself can point to anything).

This is why there's no implicit conversions between type ** and void ** - it's for the same reason that there's no implicit conversions between double * and int *.

Now, there is one special case: for historical reasons, char * is guaranteed to have the same size, representation and alignment requirements as void *. This means that conversions between char ** (in particular) and void ** are actually OK, as an exception to the general rule. So in your particular case, your code is correct if you add a cast to void ** when you pass strarr to qsort1().

However, your qsort1() is only defined to correctly work on arrays of void * or char * (including unsigned char * etc.). You can't use it to sort an array of double * pointers, for example (although it would actually work on most common environments today).

caf