Передача функций
Передавайте обратные вызовы как аргументы
«Передача функций» — бесплатный урок C Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C Academy содержит 4 уроков всего.
Функции как аргументы
Поскольку указатель на функцию — это обычное значение, функцию можно передать другой функции. Полученная функция называется функцией обратного вызова.
Это позволяет одной процедуре настраивать часть своего поведения.
#include <stdio.h>
int apply(int x, int (*f)(int)) {
return f(x);
}
int square(int x) { return x * x; }
int main(void) {
printf("%d\n", apply(6, square));
return 0;
}Параметр функции обратного вызова
Параметр функции обратного вызова объявляется так же, как переменная-указатель на функцию. Внутри функции его можно вызывать как любую другую функцию.
#include <stdio.h>
void run_twice(void (*action)(void)) {
action();
action();
}
void beep(void) { printf("beep\n"); }
int main(void) {
run_twice(beep);
return 0;
}Замена поведения
Передавайте разные функции обратного вызова, чтобы получать разные результаты от одной и той же функции высшего порядка.
#include <stdio.h>
int combine(int a, int b, int (*op)(int, int)) {
return op(a, b);
}
int add(int a, int b) { return a + b; }
int mul(int a, int b) { return a * b; }
int main(void) {
printf("%d\n", combine(3, 4, add));
printf("%d\n", combine(3, 4, mul));
return 0;
}Применение к массиву
Функция map применяет функцию обратного вызова к каждому элементу массива непосредственно в нём.
#include <stdio.h>
void map(int *a, int n, int (*f)(int)) {
for (int i = 0; i < n; i++) a[i] = f(a[i]);
}
int inc(int x) { return x + 1; }
int main(void) {
int a[] = {1, 2, 3};
map(a, 3, inc);
for (int i = 0; i < 3; i++) printf("%d ", a[i]);
printf("\n");
return 0;
}Фильтрация с помощью предиката
Предикат — это функция обратного вызова, возвращающая значение true или false. Используйте его, чтобы подсчитывать или выбирать подходящие элементы.
#include <stdio.h>
int count_if(int *a, int n, int (*pred)(int)) {
int c = 0;
for (int i = 0; i < n; i++) if (pred(a[i])) c++;
return c;
}
int is_even(int x) { return x % 2 == 0; }
int main(void) {
int a[] = {1,2,3,4,5,6};
printf("%d\n", count_if(a, 6, is_even));
return 0;
}Сведение к одному значению
Функция reduce сворачивает массив в одно значение с помощью бинарной функции обратного вызова и начального аккумулятора.
#include <stdio.h>
int reduce(int *a, int n, int init, int (*op)(int,int)) {
int acc = init;
for (int i = 0; i < n; i++) acc = op(acc, a[i]);
return acc;
}
int add(int a, int b) { return a + b; }
int main(void) {
int a[] = {1,2,3,4};
printf("%d\n", reduce(a, 4, 0, add));
return 0;
}Передача функции сравнения
Для сортировки и поиска часто передают функцию обратного вызова для сравнения, чтобы один и тот же алгоритм работал с любым порядком элементов.
#include <stdio.h>
int max_by(int a, int b, int (*greater)(int,int)) {
return greater(a, b) ? a : b;
}
int gt(int a, int b) { return a > b; }
int main(void) {
printf("%d\n", max_by(3, 8, gt));
return 0;
}typedef для типов функций обратного вызова
Имя типа функции обратного вызова, заданное с помощью typedef, делает сигнатуры функций более понятными.
#include <stdio.h>
typedef int (*IntFn)(int);
int apply(int x, IntFn f) { return f(x); }
int neg(int x) { return -x; }
int main(void) {
printf("%d\n", apply(5, neg));
return 0;
}Запасной вариант для функции обратного вызова
Если функция обратного вызова может иметь значение NULL, предусмотрите поведение по умолчанию, чтобы вызывающая сторона могла отказаться от неё.
#include <stdio.h>
int apply(int x, int (*f)(int)) {
if (f == NULL) return x;
return f(x);
}
int dbl(int x) { return x * 2; }
int main(void) {
printf("%d\n", apply(9, NULL));
printf("%d\n", apply(9, dbl));
return 0;
}Функции обратного вызова разделяют код
Функции обратного вызова позволяют общему алгоритму не зависеть от конкретной операции. Библиотека предоставляет цикл, а Вы — поведение.
#include <stdio.h>
void for_each(int *a, int n, void (*visit)(int)) {
for (int i = 0; i < n; i++) visit(a[i]);
}
void show(int x) { printf("[%d]", x); }
int main(void) {
int a[] = {7, 8, 9};
for_each(a, 3, show);
printf("\n");
return 0;
}Выбор функции обратного вызова во время выполнения
Объедините выбор по условию с передачей функции: выберите функцию обратного вызова, а затем передайте её функции высшего порядка.
#include <stdio.h>
int apply(int x, int (*f)(int)) { return f(x); }
int sq(int x) { return x * x; }
int cube(int x) { return x * x * x; }
int main(void) {
int power = 3;
int (*f)(int) = (power == 2) ? sq : cube;
printf("%d\n", apply(2, f));
return 0;
}Быстрая проверка
Проверьте, насколько хорошо Вы понимаете передачу функций.
Итоги
Вы научились передавать функции как функции обратного вызова:
- Объявляйте параметр функции обратного вызова так же, как указатель на функцию.
- Создавайте функции высшего порядка, такие как map, filter, reduce и for_each.
- Используйте
typedef, чтобы давать имена типам функций обратного вызова. - Защищайтесь от функций обратного вызова со значением
NULLс помощью поведения по умолчанию.
Изучай C с ИИ-репетитором — бесплатно
Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.
- Курсы
- 39
- Уроки
- 144
Часто задаваемые вопросы
Урок «Передача функций» бесплатный?
Да — полный текст урока «Передача функций» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C Academy, подпишись на CoddyKit PRO. Курс C Academy содержит 4 уроков всего.
Чему я научусь в уроке «Передача функций»?
Передавайте обратные вызовы как аргументы Ты практикуешь C Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать C Academy?
Предыдущий опыт не требуется. C Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.
Сколько времени занимает урок «Передача функций»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке C Academy?
Да. Каждый урок C Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.