Возьмите следующее:
int i = 10;
Соответствующий указатель может быть определен так:
int* p = &i;
Переменная «p» очень похожа на «i» в том, что они оба числа Однако значение 'p' является адресом памяти переменной 'i', другими словами, это точный адрес памяти, где хранится значение 10. Кроме того, 'p' знает тип значения по этому адресу памяти. Он знает, что это int, поскольку он был определен как int + star.
Аналогично рассмотрим функцию:
int m(char* arg1, double arg2)
{
/* do something */
}
C предоставляет возможность доступа к адресу памяти, где хранится эта функция. Функция не похожа на значение, например его нельзя изменить, поэтому, когда кто-то говорит адрес памяти функции, это фактически означает адрес памяти, в котором находится код функции, например, все, что написано между фигурными скобками.
Однако существует сходство между функцией и переменной. У них обоих есть тип. Тип функции состоит из:
- Тип возврата
- Список типов параметров , а именно:
- Тип параметра # 1
- Тип параметра # 2
- ...
- Тип параметра # N
C рассматривает все функции, которые имеют одинаковые списки возвращаемого типа и типа параметра, как " того же типа функции ". Подобно тому, как две переменные, объявленные как «int i, j», рассматриваются как один и тот же тип, так и две функции с одинаковой сигнатурой считаются одним и тем же типом.
Синтаксис для описания типа функции включает в себя минимум: тип возвращаемого значения и типы каждого параметра (в правильном порядке):
return-type (* <variable-name>)(Type-of-Param-1, Type-of-Param-2, ..., Type-of-Param-N)
Фактически, чтобы объявить указатель на функцию 'm' выше:
int (*p)(char*, double) = &m;
«int» - это тип возвращаемого значения метода «m», первая пара круглых скобок и звезда являются частью синтаксиса, «p» - это имя переменной, «char *» - тип первого параметра. и "double" является типом второго параметра. Нет ссылки на имена параметров - поскольку имена параметров не имеют отношения к типу / сигнатуре функции.
Обратите внимание, что, как и для переменной, адрес метода получается точно так же, как и для переменной, т. Е. Путем добавления к нему амперсанда.
Указатели на функции могут передаваться вокруг указателей на переменные, и, что более важно, может вызываться код функции по этому конкретному адресу памяти. Например, чтобы вызвать функцию 'm' с помощью указателя 'p', потребуется что-то вроде этого:
int result = p(NULL, 10.0);
int result = (*p) (NULL, 10.0); // alternative syntax