Ваш профессор пытается научить вас концепции, которая распространена в функциональном программировании, которая является идеей функции высшего порядка . Функция высшего порядка может принимать другие функции в качестве параметров, вроде
list_of_cosines = map(cos, list_of_inputs)
, где list of inputs
- серия значений с плавающей запятой, а cos
- нормальная функция косинуса. Функция map
будет вызывать cos
для каждого значения в list_of_inputs
и возвращать список соответствующих результатов.
Функции C не могут принимать другие типы функций в качестве параметров, но они могут принимать указатели на функции в качестве параметров (обычно называемые callback ); каноническим примером является библиотечная функция qsort()
, которая принимает в качестве одного из своих параметров указатель на функцию, которая принимает два указателя на void и возвращает -1, 0 или 1 в зависимости от того, v1 v2 соответственно. Например:
int compareIntValues(const void *v1, const void *v2)
{
int lv1 = *(int *) v1; // convert inputs from pointers to void
int lv2 = *(int *) v2; // to the type we're actually interested in
if (lv1 < lv2) return -1;
if (lv1 > lv2) return 1;
return 0;
}
int main(void)
{
int values[] = {3, 1, 4, 5, 7, 9, 6, 2};
...
qsort(values, // buffer containing items to sort
sizeof values / sizeof values[0], // number of items to sort
sizeof values[0], // size of each item
compareIntValues); // comparison function
...
}
qsort()
вызовет compareIntValues
, чтобы упорядочить элементы в values
. Подобно выражениям массива, тип функции-указателя будет неявно преобразован из «функции, возвращающей T» в «указатель на функцию, возвращающую T» в зависимости от контекста.
На данный момент я предполагаю, но мне кажется, что ваш профессор хочет, чтобы вы написали функцию list_map
, чтобы она вызывала функцию сортировки f
со списком в качестве параметр, что-то вроде следующего:
void list_map(INTLIST *list, void (*f)(void *))
{
// sort the list by passing it to f
f(list); // or (*f)(list);
}
void sortListAscending(void *ptr)
{
INTLIST *ilptr = ptr;
/**
* sort the list in ascending order
*/
}
void sortListDescending(void *ptr)
{
INTLIST *ilptr = ptr;
/**
* sort the list in descending order
*/
}
int main(void)
{
INTLIST *theList;
...
list_map(theList, sortListAscending); // sort the list in ascending order
...
list_map(theList, sortListDescending); // sort the list in descending order
...
}
Интерфейс, предоставленный вашим профессором, немного запутан; либо указатель списка и параметр для f () должны быть void *
(в этом случае вы можете использовать list_map
для сопоставления функций с различными типами списка), либо указатель списка и параметр для f должны быть INTLIST *
( так как вы, кажется, имеете дело с типами INTLIST).
Если я прав, то упражнение на поверхности немного бессмысленно (почему бы не вызвать функцию сортировки напрямую?), Но, возможно, ваш профессор выстраивает что-то более общее. В конце концов, нет причины, по которой f
должна быть функцией сортировки; это может быть функция для отображения списка, или сохранения списка в файл, или что-то еще.
У меня есть другой пример того, как использовать обратные вызовы для сортировки списка здесь ; это может помочь проиллюстрировать, почему этот метод полезен.
EDIT
Пример того, что нужно сделать для list_map, вероятно, гораздо ближе к тому, что задумал ваш профессор, чем к тому, что я написал.