¿Cómo ordenar una matriz de punteros a char en C?

Supongamos que tengo una serie de punteros a char en C:

char *data[5] = { "boda", "cydo", "washington", "dc", "obama" }; 

Y deseo ordenar esta matriz usando qsort:

 qsort(data, 5, sizeof(char *), compare_function); 

No puedo encontrar la función de comparación. Por alguna razón, esto no funciona:

 int compare_function(const void *name1, const void *name2) { const char *name1_ = (const char *)name1; const char *name2_ = (const char *)name2; return strcmp(name1_, name2_); } 

Realicé muchas búsquedas y descubrí que tenía que usar ** dentro de qsort:

 int compare_function(const void *name1, const void *name2) { const char *name1_ = *(const char **)name1; const char *name2_ = *(const char **)name2; return strcmp(name1_, name2_); } 

Y esto funciona

¿Alguien puede explicar el uso de *(const char **)name1 en esta función? No lo entiendo en absoluto. ¿Por qué el doble puntero? ¿Por qué no funcionó mi función original?

Gracias, Boda Cydo.

Si ayuda a mantener las cosas claras en su cabeza, el tipo al que debe aplicar los punteros en su comparador es el mismo que el del puntero de datos original que qsort en qsort (que los docs de qsort llaman base ). Pero para que qsort sea ​​genérico, simplemente maneja todo como void* , independientemente de lo que sea “realmente”.

Entonces, si estás ordenando una matriz de enteros, entonces pasarás un int* (convertido a void* ). qsort le devolverá dos punteros void* al comparador, que convertirá a int* , y la desreferencia para obtener los valores int que realmente compara.

Ahora reemplace int con char* :

si está ordenando una matriz de caracteres char* , pasará un char** (convertido a void* ). qsort le devolverá dos punteros void* al comparador, que convertirá a char** , y una desreferencia para obtener los valores de char* que realmente compara.

En su ejemplo, debido a que está usando una matriz, el char** que pasa es el resultado de la matriz de “desintegración” de caracteres char* a un puntero a su primer elemento. Como el primer elemento es un char* , un puntero es un char** .

Imagine que sus datos eran datos double data[5] .

Su método de comparación recibiría punteros (double *, pasado como vacío *) a los elementos (doble).
Ahora reemplace doble con char * nuevamente.

qsort es lo suficientemente general como para ordenar matrices que constan de otras cosas que no sean punteros. Es por eso que el parámetro de tamaño está ahí. No puede pasar los elementos del conjunto a la función de comparación directamente, ya que no sabe en tiempo de comstackción qué tan grandes son. Por lo tanto, pasa punteros. En tu caso obtienes punteros a char * , char ** .

La función de comparación toma punteros al tipo de objeto que está en la matriz que desea ordenar. Como la matriz contiene char * , su función de comparación toma punteros a char * , aka char ** .

del man qsort :

 The contents of the array are sorted in ascending order according to a comparison function pointed to by compar, which is called with two arguments that **point** to the objects being compared. 

Entonces parece que la función de comparación obtiene punteros a los elementos de la matriz. Ahora un puntero a un char * es un char ** (es decir, un puntero a un puntero a un personaje).

char *data[5] = { "boda", "cydo", "washington", "dc", "obama" };

es una statement que le pide al comstackdor una matriz de 5 caracteres de punteros de caracteres. Ha inicializado esos punteros a literales de cadenas, pero para el comstackdor, sigue siendo una matriz de cinco punteros.

Cuando pasa esa matriz a qsort , la matriz de punteros se descompone en un puntero que apunta al primer elemento, de acuerdo con las reglas de paso de los parámetros de la matriz C.

Por lo tanto, debe procesar un nivel de direccionamiento indirecto antes de poder llegar a las matrices de caracteres reales que contienen las constantes.

@bodacydo aquí es un progtwig que puede explicar lo que otros progtwigdores están tratando de transmitir, pero esto sería en el contexto de “enteros”

 #include  int main() { int i , j; int *x[2] = {&i, &j}; i = 10; j = 20; printf("in main() address of i = %p, address of j = %p \r\n", &i, &j); fun(x); fun(x + 1); return 0; } void fun(int **ptr) { printf("value(it would be an address) of decayed element received = %p, double dereferenced value is %d \r\n",*ptr, **ptr); printf("the decayed value can also be printed as *(int **)ptr = %p \r\n", *(int **)ptr ); }