Передача функций в качестве аргументов
Часть раздела Object Oriented Programming путешествия по C на Coddy — урок 36 из 61.
Одним из наиболее мощных способов использования указателей на функции является их передача в качестве аргументов другим функциям. Это позволяет внедрять настраиваемое поведение в функцию без изменения её кода — метод, который иногда называют callback.
Рассмотрим функцию, которая выполняет вычисление над двумя числами. Вместо жесткого кодирования операции вы можете передать указатель на функцию, который определяет, какую операцию следует выполнить:
typedef int (*Operation)(int, int);
int compute(int a, int b, Operation op) {
return op(a, b);
}Функция compute не знает, выполняет ли она сложение, вычитание или что-то совсем другое. Она просто вызывает ту функцию, которая ей передана:
int add(int a, int b) { return a + b; }
int multiply(int a, int b) { return a * b; }
int main() {
printf("%d\n", compute(5, 3, add)); // Результат: 8
printf("%d\n", compute(5, 3, multiply)); // Результат: 15
return 0;
}Обратите внимание, как одна и та же функция compute выдает разные результаты в зависимости от того, какую функцию мы передаем. Этот паттерн является основополагающим для написания гибкого, переиспользуемого кода — вы пишете структуру один раз, а пользователи вашей функции предоставляют конкретную логику, которая им необходима.
Задание
ЛегкоНапишите функцию apply_twice, которая принимает два целых числа и код операции, применяет операцию к числам дважды последовательно и возвращает конечный результат.
Ваша функция получит код операции, который определяет, какую операцию использовать. Вы должны определить функции операций внутри вашего решения и передать их во вспомогательную функцию compute, которая принимает указатель на функцию.
Требуемая структура:
- Определите
typedefс именемOperationдля указателя на функцию, которая принимает два параметра типаintи возвращаетint - Определите две функции операций:
add(возвращает a + b) иmultiply(возвращает a * b) - Определите функцию
compute, которая принимает два целых числа и указатель на функциюOperation, а затем возвращает результат вызова этой операции - В функции
apply_twiceвыберите соответствующую операцию на основе кода, затем используйтеcomputeдважды: сначала с исходными числами, затем с полученным результатом и вторым числом снова
Логика:
- Выберите функцию операции на основе
op_code(1 = add, 2 = multiply) - Вызовите
compute(a, b, operation), чтобы получить промежуточный результат - Вызовите
compute(intermediate, b, operation), чтобы получить конечный результат - Верните конечный результат
Параметры:
a(int): Первое числоb(int): Второе числоop_code(int): Код операции (1 для add, 2 для multiply)
Возвращает: Результат после двукратного последовательного применения операции (int)
Пример: Для a = 5, b = 3, op_code = 1 (add):
- Первое вычисление: 5 + 3 = 8
- Второе вычисление: 8 + 3 = 11
- Результат: 11
Для a = 2, b = 4, op_code = 2 (multiply):
- Первое вычисление: 2 × 4 = 8
- Второе вычисление: 8 × 4 = 32
- Результат: 32
Шпаргалка
Указатели на функции могут передаваться в качестве аргументов другим функциям, обеспечивая работу обратных вызовов (callbacks) — способа внедрения пользовательского поведения без изменения кода самой функции.
Определите тип указателя на функцию с помощью typedef:
typedef int (*Operation)(int, int);Создайте функцию, которая принимает указатель на функцию в качестве параметра:
int compute(int a, int b, Operation op) {
return op(a, b);
}Передавайте различные функции для достижения разного поведения:
int add(int a, int b) { return a + b; }
int multiply(int a, int b) { return a * b; }
int main() {
printf("%d\n", compute(5, 3, add)); // Результат: 8
printf("%d\n", compute(5, 3, multiply)); // Результат: 15
return 0;
}Этот паттерн позволяет писать гибкий, переиспользуемый код, в котором структура определяется один раз, а пользователи предоставляют конкретную логику, которая им необходима.
Попробуйте сами
int apply_twice(int a, int b, int op_code) {
// Напишите код здесь
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Object Oriented Programming
1Основы модульного программирования
Заголовочные файлыСтражи включенияИсходные файлыСтатические функцииПовторение: Модульный калькулятор4Инкапсуляция
Концепция непрозрачных указателейОпределение непрозрачных структурГеттеры и сеттерыВалидация в сеттерахИтоги: Секретный ящик7Указатели на функции
Объявление указателей на функцииВызов указателей на функцииTypedef для указателей на функцииПередача функций в качестве аргументовИтоги: Диспетчеризация калькулятора2Объекты и методы
Структуры как объектыУказатель 'Self'Константная корректностьУказатель против значенияВспомогательные методыИтоги: Point Manager5Проект: Простой банковский счет
Настройка проектаРеализация счета3Жизненный цикл объекта
Паттерн «Конструктор»Паттерн «Деструктор»Инициализация в стекеГлубокое копированиеПовторение: String Wrapper6Наследование через композицию
Встраивание структурПравило первого элементаДоступ к элементам родителяUpcastingПовторение: Иерархия фигур9Проект: Рисование фигур
Обзор проектаРеализация круга