#c #pointers
#c #указатели
Вопрос:
У меня есть одна функция:
int compare(char * c1, char * c2){
...
...
}
Каковы различные стили, в которых я могу написать функцию int ret_compare(void * item)
, которая возвращает указатель для сравнения?
Ответ №1:
Существует два основных стиля: один использует a typedef
, а другой нет (с двумя вариантами typedef
). Ваш компаратор должен принимать постоянные указатели, как показано ниже:
int compare(const char *c1, const char *c2) { ... }
// Raw definition of a function returning a pointer to a function that returns an int
// and takes two constant char pointers as arguments
int (*ret_compare1(void *item))(const char *, const char *)
{
// Unused argument - item
return compare;
}
// More usual typedef; a Comparator2 is a pointer to a function that returns an int
// and takes two constant char pointers as arguments
typedef int (*Comparator2)(const char *, const char *);
// And ret_compare2 is a function returning a Comparator2
Comparator2 ret_compare2(void *item)
{
// Unused argument - item
return compare;
}
// Less usual typedef; a Comparator3 is a function that returns an int
// and takes two constant char pointers as arguments
typedef int Comparator3(const char *, const char *);
// And ret_compare3 is a function returning a pointer to a Comparator3
Comparator3 *ret_compare3(void *item)
{
// Unused argument - item
return compare;
}
Обратите внимание, что эти компараторы нельзя использовать с bsearch()
и qsort()
(если вы не используете довольно ужасные приведения), потому что ожидается, что эти компараторы будут принимать const void *
аргументы.
Также обратите внимание, что для сравнения строк, в отличие от отдельных символов, функция, используемая qsort()
или bsearch()
должна быть похожа на:
int string_comparator(const void *v1, const void *v2)
{
const char *s1 = *(char **)v1;
const char *s2 = *(char **)v2;
return(strcmp(s1, s2));
}
Комментарии:
1. Разве аргумент функции сравнения не должен быть void *?
2. @Bruce Это та же функция сравнения, которую вы использовали в качестве примера.
3. Второй вариант
typedef
часто упускается из виду. Мне это нравится, потому что тогда заголовочные файлы могут объявлять функции компаратора какComparator2 compare1; Comparator2 compare2;
, что на 100% ясно, что функция предназначена для использования какComparator2
. (Кроме того, при передаче в функциюfunc(Comparator2 cmp)
это то жеfunc(Comprator2 *cmp)
самое, что и .)4. @Bruce — Это зависит от API.
qsort
API требуетint (*)(const void *, const void *)
. API вашего примера кодаint (*)(char *, char *)
. (Гораздо более разумный) API этого ответа используетсяconst char *
для предотвращения случайного изменения значений в компараторе.5. @Bruce: это зависит от контекста. Если вы планируете использовать компараторы со стандартными
bsearch()
qsort()
функциями or , тогда да, аргументы должны бытьconst void *
(и, как правило, базовое значение для сравнения строкchar **
— это, а неchar *
). Однако, поскольку исходная функция былаint compare(char *c1, char *c2) { ... }
, я сохранил тип исходной функции и добавил определительconst
типа. Это будет использоваться в пользовательском коде, а не сqsort()
.