2010-04-12 26 views
5

He escrito este qsort:punteros vacío en C++

void qsort(void *a[],int low,int high, int (*compare)(void*,void*)); 

Cuando llamo a esto en

char *strarr[5]; 

Dice conversión inválida de char ** ** para anular. ¿Por qué esto está mal?

Este es el código:

#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; 
} 
+0

¿por qué ha etiquetado esto como C? –

+1

Guau, al decir "¿Por qué está mal?" entonces podría enumerar * tantas cosas *. – Puppy

+0

@DeadMG es correcto. Aprenda sobre 'std :: vector',' std :: string' y 'std :: sort'. Si necesita ayuda para convertir su código a C++ real moderno, no dude en preguntar. –

Respuesta

12

una conversión implícita de cualquier tipo de puntero a void * se permite, porque void * es un define para ser un tipo de puntero que tiene un rango suficiente que puede representar cualquier valor que cualquier otro tipo de puntero lata. (Técnicamente, solo otros objetos tipos de puntero, que excluyen los punteros a las funciones).

Esto no quiere decir que void * tiene el mismo tamaño o representación como cualquier otro tipo de puntero, sin embargo: la conversión de un puntero de otro tipo de puntero a un void *no necesariamente salir de la representación subyacente sin cambios. Conversión de double * a void * es como convertir de double a int - tiene que suceder a la vista del compilador, no puede ocultar esa conversión detrás del compilador.

Así que esto implica que si bien void * es un puntero genérico, void ** es no un puntero puntero a genérico. Es un puntero a void * - un puntero void ** solo debe apuntar a objetos reales void * (mientras que void * mismo puede apuntar a cualquier cosa).

Es por esto que no hay conversiones implícitas entre type ** y void ** - es por la misma razón que no hay conversiones implícitas entre double * y int *.

Ahora, hay un caso especial: por razones históricas, char * garantiza tener los mismos requisitos de tamaño, representación y alineación que void *. Esto significa que las conversiones entre char ** (en particular) y void ** están realmente bien, como una excepción a la regla general. Por lo tanto, en su caso particular, su código es correcto si agrega un molde a void ** cuando pasa strarr a .

Sin embargo, su qsort1() solamente se define para trabajar correctamente en matrices de void * o char * (incluyendo unsigned char * etc.). No puede usarlo para ordenar una matriz de punteros double *, por ejemplo (aunque actualmente funcionaría en la mayoría de los entornos comunes).

10

Cualquier puntero se puede convertir implícitamente a un puntero nulo. Pero su primer parámetro no es un puntero void: es una matriz de punteros vacíos, y no hay una conversión implícita a eso. Probablemente desee declarar su función como:

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

pero es difícil de decir sin ver el código.