В языке программирования C функция тоже имеет адрес и может иметь указатель. Указатель на функцию представляет собой выражение или переменную, которые используются для представления адреса функции. Указатель на функцию содержит адрес первого байта в памяти, по которому располагается выполняемый код функции.
Самым распространенным указателем на функцию является ее имя. С помощью имени функции мы можем вызывать ее и получать результат ее работы.
Но также можно создать указатель на функцию, написав его определение. Синтаксис создания переменной-указателя на функцию содержит две пары круглых скобок. Как только встречается такая "непонятная" конструкция, сразу можно догадаться, что это указатель на функцию.
Пример определения указателя на функцию:
возвращаемый_тип (*имя_указателя) (параметры);
Пример вызова функции по указателю:
имя_указателя();
Здесь:
- возвращаемый_тип представляет собой тип возвращаемого функцией значения.
- имя_указателя представляет собой имя переменной-указателя на функцию, в соответствии с правилами о наименовании переменных.
- параметры определяют тип и название параметров через запятую при их наличии.
Например, определим указатель на функцию:
void (*message) (void);
Здесь определен указатель, который имеет имя message. Он может указывать на функции без параметров, которые возвращают тип void (то есть ничего не возвращают).
Применим этот указатель на функцию:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 |
#include <stdio.h>
void hello(void)
{
printf("Hello, World \n");
}
void goodbye()
{
printf("Good Bye, World \n");
}
int main(void)
{
void (*message) (void);
message=hello;
message();
message = goodbye;
message();
return 0;
} |
Указателю на функцию можно присвоить функцию, которая соответствует указателю по возвращаемому типу и спецификации параметров:
message=hello;
То есть в данном случае указатель message теперь хранит адрес функции hello. И посредством обращения к указателю мы можем вызвать эту функцию:
message();
Впоследствии мы можем присвоить указателю адрес другой функции, как в данном случае. В итоге результатом данной программы будет следующий вывод:
Hello, World
Good Bye, World
При определении указателя снова стоит обратить внимание на скобки вокруг имени. Так, использованное выше определение
void (*message) (void);
НЕ будет аналогично следующему определению:
void *message (void);
Во втором случае определен не указатель на функцию, а прототип функции message, которая возвращает указатель типа void*.
Рассмотрим еще один указатель на функцию:
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 |
#include <stdio.h>
int add(int x, int y)
{
return x+y;
}
int subtract(int x, int y)
{
return x-y;
}
int main(void)
{
int a = 10;
int b = 5;
int result;
int (*operation)(int a, int b);
operation=add;
result = operation(a, b);
printf("result=%d \n", result); // result=15
operation = subtract;
result = operation(a, b);
printf("result=%d \n", result); // result=5
return 0;
} |
Здесь определен указатель operation, который может указывать на функцию с двумя параметрами типа int, возвращающую также значение типа int. Соответственно мы можем присвоить указателю адреса функций add и subtract и вызвать их, передав при вызове в указатель нужные значения для параметров.