Указатели на функции как параметры и результаты функций
Указатели на функции как параметры
Указатель на функцию может передаваться в другую функцию в качестве параметра. Например:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <stdio.h>
int add(int x, int y)
{
return x+y;
}
int subtract(int x, int y)
{
return x-y;
}
int operation(int (*op)(int, int), int a, int b)
{
return op(a, b);
}
int main(void)
{
int a = 10;
int b = 5;
int result;
result = operation(add, a, b);
printf("result=%d \n", result);
result = operation(subtract, a, b);
printf("result=%d \n", result);
return 0;
}
Здесь в функции operation первый параметр - указатель int (*op)(int, int) представляет функцию, которая возвращает значение типа int и принимает два параметра типа int. Результатом функции является вызов той функции, на которую указывает указатель.
Определению указателя соответствуют две функции: add и subtract, поэтому их адрес можно передать в вызов функции operation: operation(add, a, b);.
Другой пример - функция, которая может принимать в качестве параметра некоторое условие:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>
int isEven(int x)
{
return x%2==0;
}
int isPositive(int x)
{
return x>0;
}
void action(int (*condition)(int), int numbers[], int n)
{
for(int i=0; i<n; i++)
{
if(condition(numbers[i])!=0)
{
printf("%d \t", numbers[i]);
}
}
}
int main(void)
{
int nums[] = {-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5};
int n = sizeof(nums)/sizeof(nums[0]);
printf("\n Even numbers: ");
action(isEven, nums, n);
printf("\n Positive numbers: ");
action(isPositive, nums, n);
return 0;
}
Первый параметр функции action - указатель int (*condition)(int) представляет функцию, которая принимает целое число и в зависимости от того, соответствует оно условию или нет, возвращает 1 (если соответствует) или 0. На момент определения функции action точное условие может быть неизвестно.
В текущей программе условия представлены двумя функциями. Функция isEven() возвращает 1, если число четное, и 0, если число нечетное. А функция isPositive() возвращает 1, если число положительное, и 0, если отрицательное.
При вызове функции action() в нее можно передать нужное условие: action(isEven, nums, n);. В итоге программа выведет на экран числа из массива nums, которые соответствуют переданному условию:
Even numbers: -4 -2 0 2 4
Positive numbers: 1 2 3 4 5
Указатель на функцию как возвращаемое значение
Функция может возвращать указатель на другую функцию. Это может быть актуально, если имеется ограниченное количество вариантов - выполняемых функций, и надо выбрать одну из них. Но при этом набор вариантов и выбор из них определяется в промежуточной функции.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <stdio.h>
int action1(void)
{
printf("Action 1");
return 1;
}
int action2(void)
{
printf("Action 2");
return 2;
}
int action3(void)
{
printf("Action 3");
return 3;
}
int (*select(void))(void)
{
int choice; // выбранный пункт
// массив указателей на функции, которые будут возвращаться
int (*actions[])() = {action1, action2, action3};
// выбираем действие по номеру
printf("Select action (1, 2, 3): ");
scanf("%d", &choice);
// возвращаем нужную функцию
if(choice >0 && choice<4)
return actions[choice-1];
else
return NULL;
}
int main(void)
{
int (*action)(void); // указатель на выбранную функцию
int actionNumber; // результат функции - номер действия
while(1)
{
action = select(); // получаем указатель на функцию
if(action==NULL)
break;
actionNumber = action(); // выполняем функцию
printf("\nselected action %d \n", actionNumber);
}
printf("End");
return 0;
}
В данной программе мы предполагаем, что пользователь должен выбрать для выполнения одну из трех функций: action1, action2, action3.
Сам выбор происходит в функции select(). Она возвращает указатель на функцию - по сути выбранную функцию.
Все выбираемые функции имеют прототип вида:
1
int action1(void);
И прототип функции select должна соответствовать этому прототипу:
1
int (*select(void))(void)
Для хранения всех действий в функции select определен массив указателей на функции actions:
1
int (*actions[])() = {action1, action2, action3};
С помощью введенного с клавиатуры числа определяем номер нужного действия, которое надо выполнить. Если номер меньше 1 или больше 3, то возвращается константа NULL.
В главной функции main() в бесконечном цикле вызываем функцию select, получая в качестве результата указатель на функцию:
1
action = select();
И если указатель не равен NULL, то после этого мы сможем вызвать функцию по указателю и получить ее результат:
1
actionNumber = action();
Консольный вывод работы программы:
Select action (1, 2, 3): 1
Action 1
selected action 1
Select action (1, 2, 3): 3
Action 3
selected action 3
Select action (1, 2, 3): 4
End