2012-05-07 2 views
1

Я ищу через одну из моих учебников, и я вижу следующую строку кода для функции C:передавая функции в качестве аргументов в C

node_t* func(node_t* n, int f(node_t *)) 

Что именно это означает? В качестве аргумента есть функция. В чем смысл этого? Разве вы не можете просто вызвать любую функцию в файле, если она была объявлена? Также, с точки зрения сборки, является ли это ссылкой на ячейку памяти int f()?

спасибо.

ответ

4
node_t* func(node_t* n, int f(node_t *)) 

Есть функция, называемая FUNC, которая принимает два параметра: п, указатель на node_t и п, указатель на функцию, которая принимает указатель node_t и возвращает Int. Функция func возвращает указатель на node_t.

В любом случае, наиболее распространенное использование этого, которое приходит на ум, - это общие алгоритмы.

«Разве вы не можете просто вызвать любую функцию в файле, если она была объявлена?»

Пока функция была объявлена ​​в блоке компиляции, и компоновщик может найти ее во время соединения, это правда. Тем не менее, указатели на функции используются, когда вы хотите иметь возможность решать во время выполнения, какую функцию использовать (или время компиляции, если вы просто хотите использовать общую функцию).

В качестве осязаемого примера рассмотрим qsort:

void qsort (void * base, size_t num, size_t size, int (* comparator) (const void *, const void *)); 

Теперь рассмотрим это:

typedef struct Student { int id; char* name; } 

Student students[10]; 

//populate students 

int sortByName(void* a, void* b) 
{ 
    Student* sa = a; 
    Student* sb = b; 
    return strcmp(a->name, b->name); 
} 

int sortById(void* a, void* b) 
{ 
    Student* sa = a; 
    Student* sb = b; 
    return a->id - b->id; 
} 

//sort by name: 
qsort(students, 10, sizeof(Student), sortByName); 

//sort by id: 
qsort(students, 10, sizeof(Student), sortById); 

Важной частью является то, что сортировка код не должен быть изменен. Реализация сортировки является фактически общей. Это один алгоритм, который работает с разными типами данных, и в этом случае этому обобщению способствует указатель на функцию.

Существует и другое использование указателей функций (немало из них), таких как обратные вызовы или ветвление на основе карты, которая передает что-то функции.

1

Второй аргумент - это указатель на функцию с сигнатурой int(node_t *). Таким образом, вы можете пройти обратный вызов к func, как это:

int foo(node_t * p) { /* ... */ } 

node_t n; 
func(&n, foo); // note: the second argument is the function pointer 

Вот очень глупый пример, чтобы использовать эту функцию, чтобы перемещаться по фиктивным массива:

T * array_next(T * arr, int n) { return arr + n; } 
T * array_prev(T * arr, int n) { return arr - n; } 

T * move_in_array(T * arr, T * (*f)(T *, int)) 
{ 
    return f(arr, 1); 
} 

Теперь вы можете напишите код, который перемещается по массиву в определенном порядке времени с использованием обратных вызовов:

T * p = move_in_array(some_array, flag ? array_next : array_prev); 

Основная идея дизайна заключается в том, что у нас есть общая функция действия move_in_array, чья конкретная реализация передается как аргумент в виде указателя функции.