Предположим, вы хотите отсортировать массив из int
с помощью qsort
.
int numbers[] = {10, 50, 35, 62, 22};
Во-первых, необходимо создать функцию, которая может сравнить два int
с.
int intCompare(void* p1, void* p2)
{
int n1 = *(int*)p1;
int n2 = *(int*)p2;
return (n1 < n2);
}
Затем, вы можете использовать:
qsort(numbers, 5, sizeof(int), intCompare);
Когда numbers
передается qsort
, она затухает к int*
и передается как void*
. Когда нам нужно извлечь номер из void*
в intCompare
, нам нужно отдать его int*
, прежде чем мы разыграем указатель и сравним значения.
Принимая аналогию строк, скажем, вы хотите отсортировать:
char* strings[] = { "abc", "xyz", "def" };
Вызов qsort
будет:
qsort(strings, 3, sizeof(char*), scmp);
Когда strings
передается qsort
, она затухает к char**
и передан как void*
. Нижеуказанные типы указателей, передаваемых на scmp
, на qsort
будут иметь тип char**
, а не char*
. Следовательно, правильно использовать:
int scmp(const void *p1, const void * p2)
{
char *v1, *v2;
v1 = *(char **) p1;
v2 = *(char **) p2;
return strcmp(v1,v2);
}
Первая версия работает из-за случайного совпадения в некоторых случаях. Вот примерная программа, которая показывает пару случаев, когда она не работает, пока вторая версия всегда должна работать.
#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();
}
Выход (с помощью GCC 4.8.4):
abc
xyz
def
abc
def
xyz
abc
xyz
def
abc
def
xyz
Вторая версия кажется правильным для меня.Трудно сказать, как работает первая версия, не видя остальной части вашего кода. –
как вы называете эту функцию? Если вы вызываете эту функцию как 'scmp (« hello »,« hello »),' будет работать только первая версия: http://ideone.com/P96Wmj – mch
Возможно, это работает в некоторых случаях, но это не будет работа для всех случаев. Если, например, p1 указывает на строку «abcdefgh» и p2 на другую строку «abcdefgh». Теперь строки равны, поэтому оба они интерпретируются как один и тот же адрес (назовем его p). Затем strcmp будет сравнивать строку в p с строкой в p, и поскольку оба параметра указывают на один и тот же адрес, содержимое по определению одно и то же. –