Supponiamo di voler ordinare un array di int
s utilizzando qsort
.
int numbers[] = {10, 50, 35, 62, 22};
In primo luogo, si crea una funzione che può confrontare due int
s.
int intCompare(void* p1, void* p2)
{
int n1 = *(int*)p1;
int n2 = *(int*)p2;
return (n1 < n2);
}
Quindi, è possibile utilizzare:
qsort(numbers, 5, sizeof(int), intCompare);
Quando numbers
viene passato al qsort
, è decaduto a un int*
e passato come void*
. Quando abbiamo bisogno di estrarre il numero da un void*
in intCompare
, dobbiamo lanciarlo su int*
prima di dereferenziare il puntatore e confrontare i valori.
Prendendo l'analogia con le stringhe, diciamo che si desidera ordinare:
char* strings[] = { "abc", "xyz", "def" };
La chiamata a qsort
saranno:
qsort(strings, 3, sizeof(char*), scmp);
Quando strings
è passato a qsort
, si è decaduto a un char**
e passati come void*
. I tipi sottostanti dei puntatori passati a scmp
da qsort
saranno di tipo char**
, non char*
. Quindi, è corretto usare:
int scmp(const void *p1, const void * p2)
{
char *v1, *v2;
v1 = *(char **) p1;
v2 = *(char **) p2;
return strcmp(v1,v2);
}
La prima versione funziona a causa di una coincidenza fortunata in alcuni casi. Ecco un esempio di programma che mostra un paio di casi in cui non funziona mentre la seconda versione dovrebbe sempre funzionare.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// First version of scmp
int scmp1(const void *p1, const void * p2)
{
char *v1, *v2;
v1 = (char *) p1;
v2 = (char *) p2;
return strcmp(v1,v2);
}
// Second version of scmp
int scmp2(const void *p1, const void * p2)
{
char *v1, *v2;
v1 = *(char **) p1;
v2 = *(char **) p2;
return strcmp(v1,v2);
}
void test1()
{
char* strings[] = { "abc", "xyz", "def" };
qsort(strings, 3, sizeof(char*), scmp1);
for(int i = 0; i < 3; ++i)
{
printf("%s\n", strings[i]);
}
printf("\n");
}
void test2()
{
char* strings[] = { "abc", "xyz", "def" };
qsort(strings, 3, sizeof(char*), scmp2);
for(int i = 0; i < 3; ++i)
{
printf("%s\n", strings[i]);
}
printf("\n");
}
void test3()
{
char** strings = malloc(3*sizeof(char*));
strings[0] = "abc";
strings[1] = "xyz";
strings[2] = "def";
qsort(strings, 3, sizeof(char*), scmp1);
for(int i = 0; i < 3; ++i)
{
printf("%s\n", strings[i]);
}
free(strings);
printf("\n");
}
void test4()
{
char** strings = malloc(3*sizeof(char*));
strings[0] = "abc";
strings[1] = "xyz";
strings[2] = "def";
qsort(strings, 3, sizeof(char*), scmp2);
for(int i = 0; i < 3; ++i)
{
printf("%s\n", strings[i]);
}
free(strings);
printf("\n");
}
int main()
{
// Does not work.
test1();
// Should work always.
test2();
// Does not work.
test3();
// Should work always.
test4();
}
uscita (usando GCC 4.8.4):
abc
xyz
def
abc
def
xyz
abc
xyz
def
abc
def
xyz
La seconda versione sembra corretto a me.Difficile dire come funziona la prima versione senza vedere il resto del codice. –
come si chiama la funzione? Se chiami la funzione come 'scmp (" ciao "," ciao ");' solo la prima versione funzionerà: http://ideone.com/P96Wmj – mch
Potrebbe sembrare che funzioni in alcuni casi ma non lavoro per tutti i casi. Se per esempio p1 punta alla stringa "abcdefgh" e p2 ad un'altra stringa "abcdefgh". Ora le stringhe sono uguali e sono entrambe interpretate come lo stesso indirizzo (chiamiamolo p). Quindi strcmp confronterà la stringa in p con la stringa in p, e poiché entrambi i parametri puntano allo stesso indirizzo, i contenuti sono per definizione uguali. –