Załóżmy, że chcesz posortować tablicę z int
s przy użyciu qsort
.
int numbers[] = {10, 50, 35, 62, 22};
Po pierwsze, należy utworzyć funkcję, która może porównać dwie int
s.
int intCompare(void* p1, void* p2)
{
int n1 = *(int*)p1;
int n2 = *(int*)p2;
return (n1 < n2);
}
Następnie można użyć:
qsort(numbers, 5, sizeof(int), intCompare);
Kiedy numbers
jest przekazywana do qsort
, jest zepsute do int*
i przekazywane jako void*
. Kiedy musimy wyodrębnić numer z void*
w intCompare
, musimy przesłać go do int*
, zanim usuniemy wskaźnik i porównamy wartości.
Biorąc analogię do strun, powiedzmy chcesz uporządkować:
char* strings[] = { "abc", "xyz", "def" };
Wezwanie do qsort
będą:
qsort(strings, 3, sizeof(char*), scmp);
Kiedy strings
jest przekazywana do qsort
, jest zepsute do char**
i przekazano jako void*
. Podstawowe typy wskaźników przekazywanych do scmp
przez qsort
będą typu char**
, a nie char*
. W związku z tym jest poprawne użycie:
int scmp(const void *p1, const void * p2)
{
char *v1, *v2;
v1 = *(char **) p1;
v2 = *(char **) p2;
return strcmp(v1,v2);
}
Pierwsza wersja działa w wyniku szczęścia przez przypadek w niektórych przypadkach. Oto przykładowy program, który pokazuje kilka przypadków, w których nie działa, podczas gdy druga wersja powinna zawsze działać.
#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();
}
Output (używając gcc 4.8.4):
abc
xyz
def
abc
def
xyz
abc
xyz
def
abc
def
xyz
Druga wersja wydaje mi się poprawne.Trudno powiedzieć, jak działa pierwsza wersja, nie widząc reszty kodu. –
jak nazwać funkcję? Jeśli wywołasz funkcję podobną do 'scmp (" cześć "," cześć ");' działa tylko pierwsza wersja: http://ideone.com/P96Wmj – mch
Może się wydawać, że działa w niektórych przypadkach, ale nie będzie działa we wszystkich przypadkach. Jeśli na przykład p1 wskazuje na napis "abcdefgh" i p2 na inny ciąg "abcdefgh". Teraz łańcuchy są równe, więc oba są interpretowane jako ten sam adres (nazwijmy to p). Następnie strcmp porówna ciąg w p do łańcucha w p, a ponieważ oba parametry wskazują na ten sam adres, zawartość jest z definicji taka sama. –