Как к qsort массив указателей для обугливания в C?

Предположим, что у меня есть массив указателей для обугливания в C:

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

И я хочу отсортировать этот массив с помощью qsort:

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

Я не могу придумать сравнить функцию. По некоторым причинам это не работает:

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

Я сделал большой поиск и нашел, что должен был использовать ** в 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_);
}

И это работает.

Может любой объяснять использование *(const char **)name1 в этой функции? Я не понимаю это вообще. Почему двойной указатель? Почему мой оригинал не функционировал работа?

Спасибо, Boda Cydo.

23
задан bodacydo 15 August 2010 в 20:39
поделиться

6 ответов

Если это поможет вам разобраться, то тип, к которому вы должны приводить указатели в компараторе, совпадает с исходным типом указателя данных, который вы передаете в qsort (который в документации по qsort называется base). Но чтобы qsort был универсальным, он просто обрабатывает все как void*, независимо от того, чем это "на самом деле" является.

Так, если вы сортируете массив ints, то вы передадите int* (преобразованный в void*). qsort вернет вам два void* указателя на компаратор, которые вы преобразуете в int* и разыменуете, чтобы получить int, которые вы действительно сравниваете.

Теперь замените int на char*:

если вы сортируете массив из char*, то вы передадите char** (преобразованный в void*). qsort вернет вам два void* указателя на компаратор, которые вы преобразуете в char** и разыменуете, чтобы получить char* значения, которые вы действительно сравниваете.

В вашем примере, поскольку вы используете массив, char**, который вы передаете, является результатом того, что массив char* "распадается" до указателя на его первый элемент. Поскольку первый элемент - это char*, указатель на него - это char**.

21
ответ дан 29 November 2019 в 02:41
поделиться

Представьте, что ваши данные были двойными данными [5] .

Ваш метод сравнения будет получать указатели (double *, переданные как void *) на элементы (double).
Теперь снова замените double на char *.

3
ответ дан 29 November 2019 в 02:41
поделиться

qsort достаточно общий для сортировки массивов, состоящих не из указателей, а из других объектов. Поэтому и есть параметр размера. Он не может напрямую передавать элементы массива в функцию сравнения, так как во время компиляции не знает, насколько они велики. Следовательно, он передает указатели. В вашем случае вы получите указатели на char * , char ** .

2
ответ дан 29 November 2019 в 02:41
поделиться

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

- это инструкция, запрашивающая у компилятора массив 5 символьных указателей. . Вы инициализировали эти указатели на строковые литералы, но для компилятора это все еще массив из пяти указателей.

Когда вы передаете этот массив в qsort , массив указателей распадается на указатель, указывающий на первый элемент, в соответствии с правилами передачи параметров массива C.

Следовательно, вы должны обработать один уровень косвенного обращения, прежде чем сможете перейти к фактическим символьным массивам, содержащим константы.

0
ответ дан 29 November 2019 в 02:41
поделиться

от 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.

Похоже, функция сравнения получает указатели на элементы массива. Теперь указатель на char * является char ** (т.е. указатель на указатель на символ).

0
ответ дан 29 November 2019 в 02:41
поделиться

Функция сравнения принимает указатели на тип объекта, находящегося в массиве, который вы хотите отсортировать. Поскольку массив содержит char *, ваша функция сравнения принимает указатели на char *, он же char **.

2
ответ дан 29 November 2019 в 02:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: