Comment sortinger un tableau de pointeurs sur char en C?

Supposons que j’ai un tableau de pointeurs sur char en C:

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

Et je souhaite sortinger ce tableau en utilisant qsort:

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

Je suis incapable de trouver la fonction de comparaison. Pour une raison quelconque, cela ne fonctionne pas:

 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_); } 

J’ai fait beaucoup de recherches et j’ai trouvé que je devais utiliser ** intérieur 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_); } 

Et ça marche.

Quelqu’un peut-il expliquer l’utilisation de *(const char **)name1 dans cette fonction? Je ne comprends pas du tout. Pourquoi le double pointeur? Pourquoi ma fonction d’origine n’a-t-elle pas fonctionné?

Merci, Boda Cydo.

Si cela vous aide à garder les choses claires dans votre tête, le type vers lequel vous devez atsortingbuer les pointeurs dans votre comparateur est le même que le type d’origine du pointeur de données que vous transmettez à qsort (que la base qsort appelle). Mais pour que qsort soit générique, il gère simplement tout comme void* , indépendamment de ce qu’il est “vraiment”.

Donc, si vous sortingez un tableau d’ints, vous passerez dans un int* (converti en void* ). qsort vous donnera deux pointeurs void* au comparateur, que vous convertissez en int* , et déréférencés pour obtenir les valeurs int que vous comparez réellement.

Maintenant, remplacez int par char* :

si vous sortingez un tableau de char* , vous passerez un char** (converti en void* ). qsort vous donnera deux pointeurs void* au comparateur, que vous convertissez en caractère char** , et déréférencés pour obtenir les valeurs de caractère char* vous comparez réellement.

Dans votre exemple, parce que vous utilisez un tableau, le caractère char** que vous transmettez est le résultat du tableau de caractère char* “en décomposition” vers un pointeur sur son premier élément. Comme le premier élément est un caractère char* , son pointeur est un caractère char** .

Imaginez que vos données étaient double data[5] .

Votre méthode de comparaison recevrait des pointeurs (double *, passés comme void *) aux éléments (double).
Maintenant, remplacez double par char * à nouveau.

qsort est assez général pour sortinger les tableaux constitués par autre chose que des pointeurs. C’est pourquoi le paramètre de taille est là. Il ne peut pas transmettre directement les éléments du tableau à la fonction de comparaison, car il ne sait pas au moment de la compilation quelle est leur taille. Par conséquent, il passe des pointeurs. Dans votre cas, vous obtenez des pointeurs sur char * , char ** .

La fonction de comparaison prend des pointeurs sur le type d’object contenu dans le tableau que vous souhaitez sortinger. Puisque le tableau contient char * , votre fonction de comparaison prend des pointeurs sur char * , c’est-à-dire char ** .

de l’ 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. 

Il semble donc que la fonction de comparaison renvoie des pointeurs vers les éléments du tableau. Maintenant, un pointeur sur un caractère char * est un caractère char ** (c’est-à-dire un pointeur sur un pointeur sur un caractère).

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

est une instruction demandant au compilateur un tableau de la taille 5 de pointeurs de caractères. Vous avez initialisé ces pointeurs sur les littéraux de chaîne, mais pour le compilateur, il s’agit toujours d’un tableau de cinq pointeurs.

Lorsque vous transmettez ce tableau à qsort , le tableau de pointeurs se décompose en un pointeur pointant sur le premier élément, conformément aux règles de transmission des parameters du tableau C.

Par conséquent, vous devez traiter un niveau d’indirection avant de pouvoir accéder aux tableaux de caractères contenant les constantes.

@bodacydo est un programme qui explique peut-être ce que d’autres programmeurs essaient de transmettre, mais ce serait dans le contexte de “nombres entiers”

 #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 ); }