Указатель на функцию как создать
Перейти к содержимому

Указатель на функцию как создать

  • автор:

Указатели на функции

Чаще всего к ошибкам приводит использование указателей па функцию. Хотя функция — это не переменная, она по-прежнему имеет физическое положение в памяти, которое может быть присвоено указателю. Адрес, присвоенный указателю, является входной точкой в функцию. Указатель может использоваться вместо имени функции. Он также позволяет передавать функции как обычные аргументы в другие функции.

Чтобы понять, как работают указатели на функции, необходимо понять, как компилируются и вызываются функции в С. По мере компиляции функций исходный код преобразуется в объектный и устанавливается точка входа. При вызове функции происходит обращение к данной точке входа. Поэтому указатель на функцию может использоваться для вызова функции.

Адрес функции получается при использовании имени функции без каких-либо скобок или аргументов. (Очень похоже на массивы, где адрес получается с использованием имени массива без индексов.) Рассмотрим следующую программу, предназначенную для демонстрации нюансов объявления:

#include
#include
void check(char *a, char *b, int (*cmp) (const char *, const char *));
int main(void)
char s1 [80], s2[80];
int (*p) (const char*, const char*);
p = strcmp; /* получение адреса strcmp() */
gets(s1);
gets (s2);
check(s1, s2, p);
return 0;
>

void check (char *a, char *b, int (*cmp) (const char *, const char *))
printf(«Testing for equality.\n»);
if(!(*cmp) (a, b)) printf(«Equal»);
else printf(«Not equal»);
>

Когда вызывается check(), ей передаются два указателя на символы и один указатель на функцию. В функции check() аргументы объявляются как указатели на символы и указатель на функцию. Надо обратить внимание на способ объявления указателя на функцию. Следует использовать аналогичный метод при объявлении других указателей на функцию, за исключением тех случаев, когда отличается возвращаемый тип или передаваемые параметры. Скобки вокруг *cmp необходимы для правильной интерпретации компилятором данного выражения.

При объявлении указателя на функцию можно по-прежнему использовать прототип, как показано в предыдущей программе. Тем не менее в большинстве случаев имена настоящих параметров неизвестны. Поэтому можно оставить имена пустыми или можно использовать любые понравившиеся имена.

Рассмотрим работу функции strcmp() в функции check(). Оператор

if (!(*cmp) (a, b) ) printf(«Equal»);

осуществляет вызов функции, в данном случае strcmp(), с помощью cmp, который указывает на данную функцию. Вызов происходит с аргументами a и b. Данный оператор демонстрирует общий вид использования указателя на функцию для вызова функции, на которую он указывает. Круглые скобки вокруг *cmp необходимы вследствие наличия приоритетов. На самом деле можно напрямую использовать cmp, как показано ниже:

if (!cmp(a, b)) printf(«Equal»);

Данная версия также вызывает функцию, на которую указывает cmp, но она использует нормальный синтаксис. Использование ( cmp) помогает всем, читающим программу, понять, что указатель на функцию используется для вызова функции вместо вызова функции cmp. Возможно вызвать напрямую check(), используя strcmp, как показано ниже:

check(s1, s2, strcmp);

Данный оператор устраняет необходимость наличия дополнительной переменной-указателя.

Можно задаться вопросом, почему кто-то хочет написать программу таким способом. В данном примере ничего не достигается, но появляются большие проблемы. Тем не менее иногда бывают моменты, когда выгодно передавать функции в процедуры или хранить массивы функций. Следующий пример демонстрирует использование указателей на функции. При написании интерпретатора наиболее типично использование вызовов функций для различных подпрограмм поддержки, типа синус, косинус и тангенс. Вместо использования большого списка для оператора switch, можно использовать массив указателей на функции, в котором доступ к необходимой функции осуществляется с помощью индекса. В данной программе check() может использоваться для проверки как алфавитного, так и численного равенства простым вызовом различных функций сравнения.

#include
#include
#include
#include
void check(char *a, char *b, int (*cmp) (const char *, const char *));
int numcmp (const char *a, const char *b) ;
int main(void)
char s1[80], s2 [80];
gets (s1);
gets (s2);
if(isalpha(*s1))
check (s1, s2, strcmp);
else
check(s1, s2, numcmp);
return 0;
>

void check(char *a, char *b, int (*cmp) (const char *,const char *))
printf(«Testing for equality.\n»);
if(!(*cmp) (a, b)) printf («Equal»);
else printf(«Hot equal»);
>

int numcmp (const char *a, const char *b)
If(atoi(a)==atoi(b)) return 0;
else return 1;
>

Указатель на функцию как создать

В языке программирования C функция тоже имеет адрес и может иметь указатель. Указатель на функцию представляет собой выражение или переменную, которые используются для представления адреса функции. Указатель на функцию содержит адрес первого байта в памяти, по которому располагается выполняемый код функции.

Самым распространенным указателем на функцию является ее имя. С помощью имени функции мы можем вызывать ее и получать результат ее работы.

Но также указатель на функцию можно определять в виде отдельной переменной с помощью следующего синтаксиса:

тип (*имя_указателя) (типы_параметров);

Здесь тип представляет тип возвращаемого функцией значения.

имя_указателя представляет произвольно выбранный идентификатор в соответствии с правилами о наименовании переменных.

После названия указателя в скобках идут через запятую типы параметров. Если функция не принимает параметров, то указывается void .

Например, определим указатель на функцию:

void (*message) (void);

Здесь определен указатель, который имеет имя message . Он может указывать на функции без параметров, которые возвращают тип void (то есть ничего не возвращают). После названия указателя идет (void) , что указывает, что функция не принимает параметров.

Применим этот указатель на функцию:

#include void hello() < printf("Hello, World \n"); >void goodbye() < printf("Good Bye, World \n"); >int main(void) < // определяем указатель на функцию void (*message) (void); message=hello; // указатель указывает на функцию hello message(); // вызываем функцию, на которую указыывет указатель message = goodbye; // указатель указывает на функцию goodbye message(); // вызываем функцию, на которую указыывет указатель return 0; >

Указателю на функцию можно присвоить функцию, которая соответствует указателю по возвращаемому типу и спецификации параметров:

message=hello;

То есть в данном случае указатель message теперь хранит адрес функции hello. И посредством обращения к указателю мы можем вызвать эту функцию:

message();

Впоследствии мы можем присвоит указателю адрес другой функции, как в данном случае. В итоге результатом данной программы будет следующий вывод:

Hello, World Good Bye, World

При определении указателя стоит обратить внимание на скобки вокруг имени. Так, использованное выше определение

void (*message) (void);

НЕ будет аналогично следующему определению:

void *message (void);

Во втором случае определен не указатель на функцию, а прототип функции message, которая возвращает указатель типа void* .

Следует учитывать, что указатель на функцию должен по типу возвращаемого значения и типу параметров соответствовать функции, иначе он не сможет соответствовать этой функции.

Рассмотрим еще один указатель на функцию, которая возвращает значение типа int и принимает два параметра типа int :

#include int sum(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, int); operation=sum; 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 . Соответственно мы можем присвоить указателю адреса функций sum и subtract и вызвать их, передав при вызове в указатель нужные значения для параметров.

Массивы указателей на функции

Кроме одиночных указателей на функции мы можем определять их массивы. Для этого используется следующий формальный синтаксис:

тип (*имя_массива[размер]) (параметры)
double (*actions[]) (int, int)

Здесь actions представляет массив указателей на функции, каждая из которых обязательно должна принимать два параметра типа int и возвращать значение типа double .

Посмотрим применение массива указателей на функции на примере:

#include void sum(int x, int y) < printf("x + y = %d \n", x + y); >void subtract(int x, int y) < printf("x + y = %d \n", x - y); >void multiply(int x, int y) < printf("x * y = %d \n", x * y); >int main(void) < int a = 10; int b = 5; void (*operations[3])(int, int) = ; // получаем длину массива int length = sizeof(operations)/sizeof(operations[0]); for(int i=0; i < length; i++) < operations[i](a, b); // вызов функции по указателю >return 0; >

Здесь массив operations содержит три функции sum, subtract и multiply, которые последовательно вызываются в цикле через перебор массива в функции main.

Указатели на функции

К ак уже обсуждалось ранее функции – это набор команд, которые расположены в соответствующей области памяти. Вызов функции – это сохранение состояния, передача аргументов и переход по адресу, где располагается функция. В си есть возможность создавать указатели на функции. Указатели на функции позволяют упростить решение многих задач. Совместно с void указателями можно создавать функции общего назначения (например, сортировки и поиска). Указатели позволяют создавать функции высших порядков (функции, принимающие в качестве аргументов функции): отображение, свёртки, фильтры и пр. Указатели на функции позволяют уменьшать цикломатическую сложность программ, создавать легко масштабируемые конструкции. Рассмотрим пример. Создадим функцию и указатель на эту функцию

#include #include int sum(int a, int b) < return a + b; >void main () < //Объявляем указатель на функцию int (*fptr)(int, int) = NULL; int result; //Присваиваем указателю значение - адрес функции //Это похоже на работу с массивом: операцию взятия адреса использовать не нужно fptr = sum; //Вызов осуществляется также, как и обычной функции result = fptr(10, 40); printf("%d", result); getch(); >
#include #include int dble(int a) < return 2*a; >int deleteEven(int a) < if (a % 2 == 0) < return 0; >else < return a; >> //Функция принимает массив, его размер и указатель на функцию, //которая далее применяется ко всем элементам массива void map(int *arr, unsigned size, int (*fun)(int)) < unsigned i; for (i = 0; i < size; i++) < arr[i] = fun(arr[i]); >> void main () < int a[] = ; unsigned i; map(a, 10, deleteEven); for (i = 0; i < 10; i++) < printf("%d ", a[i]); >map(a, 10, dble); printf("\n"); for (i = 0; i < 10; i++) < printf("%d ", a[i]); >getch(); >

В этом примере мы создали функцию отображения, которая применяет ко всем элементам массива функцию, которая передаётся ей в качестве аргумента. Когда мы вызываем функцию map, достаточно просто передавать имена функций (они подменяются указателями). Запишем теперь функцию map, которая получает в качестве аргумента массив типа void:

#include #include void dbleInt(void *a) < *((int*) a) *= 2; >void deleteEvenInt(void* a) < int tmp = *((int*) a); if (tmp % 2 == 0) < *((int*) a) = 0; >> void dbleDouble(void *a) < *((double*) a) *= 2.0; >void deleteEvenDouble(void* a) < int tmp = *((double*) a); if (tmp % 2 == 0) < *((double*) a) = 0; >> //Функция принимает массив, его размер, размер одного элемента и указатель на функцию, //которая далее применяется ко всем элементам массива void map(void *arr, unsigned num, size_t size, void (*fun)(void *)) < unsigned i; char *ptr = (char*) arr; for (i = 0; i < num; i++) < fun((void*) (ptr + i*size)); >> void main () < int a[] = ; double b[] = ; unsigned i; //Работаем с массивом типа int map(a, 10, sizeof(int), deleteEvenInt); for (i = 0; i < 10; i++) < printf("%d ", a[i]); >map(a, 10, sizeof(int), dbleInt); printf("\n"); for (i = 0; i < 10; i++) < printf("%d ", a[i]); >printf("\n"); //Работаем с массивом типа double map(b, 10, sizeof(double), deleteEvenDouble); for (i = 0; i < 10; i++) < printf("%.3f ", b[i]); >map(b, 10, sizeof(double), dbleDouble); printf("\n"); for (i = 0; i < 10; i++) < printf("%.3f ", b[i]); >getch(); >

Вот где нам понадобились указатели типа void. Так как map получает указатель на функцию, то все функции должны иметь одинаковые аргументы и возвращать один и тот же тип. Но аргументы функций должны быть разного типа, поэтому мы делаем их типа void. Функция map получает указатель типа void (*)(void*), поэтому ей теперь можно передавать любую из четырёх функций.
Пример другой функции: функция filter получает указатель на массив и возвращает размер нового массива, оставляя в нём только те элементы, для которых переданный предикат возвращает логическую истину (предикат – функция, которая возвращает истину или ложь). Сначала напишем для массива типа int:

#include #include #include int isOdd(int a) < return (a % 2 != 0); >int isGtThree(int a) < return a >3; > unsigned int filter(int *arr, unsigned size, int (*pred)(int), int** out) < unsigned i; unsigned j; //размер возвращаемого масива *out = (int*) malloc(sizeof(int)*size); for (i = 0, j = 0; i < size; i++) < if (pred(arr[i])) < (*out)[j] = arr[i]; j++; >> *out = (int*) realloc(*out, j*sizeof(int)); return j; > void main () < int a[] = ; int *aOdd = NULL; int *aGtThree = NULL; unsigned i; unsigned size; size = filter(a, 10, isOdd, &aOdd); for (i = 0; i < size; i++) < printf("%d ", aOdd[i]); >printf("\n"); size = filter(a, 10, isGtThree, &aGtThree); for (i = 0; i < size; i++) < printf("%d ", aGtThree[i]); >free(aOdd); free(aGtThree); getch(); >

Теперь для массива типа void

#include #include #include #include #include int isOddInt(void *a) < return (*((int*) a) % 2 != 0); >int isGtThreeInt(void* a) < return *((int*) a) >3; > int isOddDouble(void* a) < return (int)*((double*) a) / 2 != 0; >int isGtThreeDouble(void* a) < return *((double*) a) >3.0; > unsigned int filter(void *arr, unsigned num, size_t size, int (*pred)(void*), void** out) < unsigned i; unsigned j; //размер возвращаемого масива char* ptrIn = (char*) arr; char* ptrOut = NULL; *out = (void*) malloc(num*size); ptrOut = (char*) (*out); for (i = 0, j = 0; i < num; i++) < if (pred(ptrIn + i*size)) < memcpy(ptrOut + j*size, ptrIn + i*size, size); j++; >> *out = (void*) realloc(*out, j*size); return j; > void main () < int a[] = ; double b[] = ; int *aOdd = NULL; int *aGtThree = NULL; double *bOdd = NULL; double *bGtThree = NULL; unsigned i; unsigned size; size = filter(a, 10, sizeof(int), isOddInt, (void**)&aOdd); for (i = 0; i 7lt; size; i++) < printf("%d ", aOdd[i]); >printf("\n"); size = filter(a, 10, sizeof(int), isGtThreeInt, (void**)&aGtThree); for (i = 0; i < size; i++) < printf("%d ", aGtThree[i]); >printf("\n"); size = filter(b, 10, sizeof(double), isOddDouble, (void**)&bOdd); for (i = 0; i < size; i++) < printf("%.3f ", bOdd[i]); >printf("\n"); size = filter(b, 10, sizeof(double), isGtThreeDouble, (void**)&bGtThree); for (i = 0; i < size; i++) < printf("%.3f ", bGtThree[i]); >free(aOdd); free(bOdd); free(aGtThree); free(bGtThree); getch(); >

Ещё одна функция – свёртка. Она получает в качестве аргументов массив и функцию от двух аргументов. Эта функция действует следующим образом: сначала она применяется к первым двум аргументам, затем она применяется к третьему аргументу и результату предыдущего вызова, затем к четвёртому аргументу и результату предыдущего вызова и т.д. С помощью свёртки можно, например, найти сумму всех элементов массива, максимальный элемент массива, факториал числа и т.п.

#include #include int sum(int a, int b) < return a + b; >int maxx(int a, int b) < return (a >b)? a: b; > int mul(int a, int b) < return a*b; >void fold(int *arr, unsigned size, int (*fun)(int, int), int *acc) < unsigned i; *acc = fun(arr[0], arr[1]); for (i = 2; i < size; i++) < *acc = fun(*acc, arr[i]); >> void main () < int a[] = ; int result; fold(a, 10, sum, &result); printf("%d\n", result); fold(a, 10, maxx, &result); printf("%d\n", result); fold(a, 10, mul, &result); printf("%d\n", result); getch(); >

Последний пример: функция сортировки вставками для массива типа void. Так как тип массива не известен, то необходимо передавать функцию сравнения.

#include #include #include #include int cmpIntDesc(void *a, void* b) < return *((int*) a) < *((int*) b); >int cmpIntAsc(void *a, void* b) < return *((int*) a) >*((int*) b); > int cmpDoubleAsc(void *a, void* b) < return *((double*) a) < *((double*) b); >int cmpDoubleDesc(void *a, void* b) < return *((double*) a) >*((double*) b); > void insertionSort(void* arr, unsigned num, size_t size, int (*cmp)(void *a, void *b)) < unsigned i, j; char *ptr = (char*) arr; char *tmp = (char*) malloc(size); for (i = 1; i < num; i++) < if (cmp(ptr + i*size, ptr + (i-1)*size)) < j = i; while (cmp(ptr + j*size, ptr + (j-1)*size) && j >0) < memcpy(tmp, ptr + j*size, size); memcpy(ptr + j*size, ptr + (j-1)*size, size); memcpy(ptr + (j-1)*size, tmp, size); j--; >> > > void main () < int a[] = ; double b[] = ; int i; insertionSort(a, 10, sizeof(int), cmpIntAsc); for (i = 0; i < 10; i++) < printf("%d ", a[i]); >printf("\n"); insertionSort(a, 10, sizeof(int), cmpIntDesc); for (i = 0; i < 10; i++) < printf("%d ", a[i]); >printf("\n"); insertionSort(b, 10, sizeof(double), cmpDoubleAsc); for (i = 0; i < 10; i++) < printf("%.3f ", b[i]); >printf("\n"); insertionSort(b, 10, sizeof(double), cmpDoubleDesc); for (i = 0; i < 10; i++) < printf("%.3f ", b[i]); >getch(); >

Массив указателей на функции

М ассив указателей на функции определяется точно также, как и обычный массив – с помощью квадратных скобок после имени:

#include #include #include #include #define ERROR_DIV_BY_ZERO -2 #define EPSILON 0.000001f float doSum(float a, float b) < return a + b; >float doSub(float a, float b) < return a - b; >float doMul(float a, float b) < return a * b; >float doDiv(float a, float b) < if (fabs(b) return a / b; > void main() < float (*menu[4])(float, float); int op; float a, b; menu[0] = doSum; menu[1] = doSub; menu[2] = doMul; menu[3] = doDiv; printf("enter a: "); scanf("%f", &a); printf("enter b: "); scanf("%f", &b); printf("enter operation [0 - add, 1 - sub, 2 - mul, 3 - div]"); scanf("%d", &op); if (op >= 0 && op < 4) < printf("%.6f", menu[op](a, b)); >getch(); >

Точно также можно было создать массив динамически

void main() < float (**menu)(float, float) = NULL; int op; float a, b; menu = (float(**)(float, float)) malloc(4*sizeof(float(*)(float, float))); menu[0] = doSum; menu[1] = doSub; menu[2] = doMul; menu[3] = doDiv; printf("enter a: "); scanf("%f", &a); printf("enter b: "); scanf("%f", &b); printf("enter operation [0 - add, 1 - sub, 2 - mul, 3 - div]"); scanf("%d", &op); if (op >= 0 && op < 4) < printf("%.6f", menu[op](a, b)); >free(menu); getch(); >

Часто указатели на функцию становятся громоздкими. Работу с ними можно упростить, если ввести новый тип. Предыдущий пример можно переписать так

#include #include #include #include #define ERROR_DIV_BY_ZERO -2 #define EPSILON 0.000001f typedef float (*operation)(float, float); float doSum(float a, float b) < return a + b; >float doSub(float a, float b) < return a - b; >float doMul(float a, float b) < return a * b; >float doDiv(float a, float b) < if (fabs(b) return a / b; > void main() < operation *menu = NULL; int op; float a, b; menu = (operation*) malloc(4*sizeof(operation)); menu[0] = doSum; menu[1] = doSub; menu[2] = doMul; menu[3] = doDiv; printf("enter a: "); scanf("%f", &a); printf("enter b: "); scanf("%f", &b); printf("enter operation [0 - add, 1 - sub, 2 - mul, 3 - div]"); scanf("%d", &op); if (op >= 0 && op < 4) < printf("%.6f", menu[op](a, b)); >free(menu); getch(); >

Ещё один пример: функция any возвращает 1, если в переданном массиве содержится хотя бы один элемент, удовлетворяющий условию pred и 0 в противном случае.

#include #include typedef int (*Predicat)(void*); int isBetweenInt(void* a) < return *((int*) a) >10 && *((int*) a) < 12; >int isBetweenDouble(void* a) < return *((double*) a) >10.0 && *((double*) a) < 12.0; >int any(void* arr, unsigned num, size_t size, Predicat pred) < unsigned i; char* ptr = (char*) arr; for (i = 0; i < num; i++) < if (pred(ptr + i*size)) < return 1; >> return 0; > void main() < int a[10] = ; double b[10] = ; printf("has 'a' any value > 10 and < 12? %d\n", any(a, 10, sizeof(int), isBetweenInt)); printf("has 'b' any value >10 and

qsort и bsearch

В библиотеке stdlib си имеется несколько функций, которые получают в качестве аргументов указатели на функции. Функция qsort получает такие же аргументы, как и написанная нами функция insertionSort: массив типа void, размер массива, размер элемента и указатель на функцию сравнения. Давайте посмотрим простой пример — сортировка массива строк:

#include #include #include #include #define SIZE 10 //qsort передаёт функции сравнения указатели на элементы. //но наш массив - это массив указателей, так что qsort будет //передавать указатели на указатели int cmpString(const void* a, const void* b) < return strcmp(*(const char**) a, *(const char**) b); >void main() < char *words[SIZE]; char buffer[128]; int i, length; printf("Enter %d words:", SIZE); for (i = 0; i < SIZE; i++) < scanf("%127s", buffer); length = strlen(buffer); words[i] = (char*) malloc(length+1); strcpy(words[i], buffer); >printf("\n"); qsort(words, SIZE, sizeof(char*), cmpString); for (i = 0; i < SIZE; i++) < printf("%s\n", words[i]); free(words[i]); >getch(); >

Функция bsearch проводит бинарный поиск в отсортированном массиве и получает указатель на функцию сравнения, такую же, как и функция qsort. В случае, если элемент найден, то она возвращает указатель на этот элемент, если элемент не найден, то NULL.

#include #include int cmpInt(const void* a, const void* b) < return *(int*) a - *(int*) b; >void main() < int a[10] = ; int elm; int *index; printf("Enter number to search: "); scanf("%d", &elm); index = (int*) bsearch(&elm, a, 10, sizeof(int), cmpInt); if (index == NULL) < printf("element not found"); >else < printf("index = %d", (index - a)); >getch(); >

ru-Cyrl 18- tutorial Sypachev S.S. 1989-04-14 sypachev_s_s@mail.ru Stepan Sypachev students

email

Всё ещё не понятно? – пиши вопросы на ящик

Указатель на функцию как создать

Указатель на функцию (function pointer) хранит адрес функции. По сути указатель на функцию содержит адрес первого байта в памяти, по которому располагается выполняемый код функции.

Самым распространенным указателем на функцию является ее имя. С помощью имени функции можно вызывать ее и получать результат ее работы.

Но также указатель на функцию мы можем определять в виде отдельной переменной с помощью следующего синтаксиса:

тип (*имя_указателя) (типы_параметров);
  • тип представляет тип возвращаемого функцией значения.
  • имя_указателя представляет произвольно выбранный идентификатор в соответствии с правилами о наименовании переменных.
  • параметры определяют типы параметров через запятую (при их наличии).

Указатель может указывать только на такую функцию, которая имеет тот же возвращаемый тип и типы параметров, что и определение указателя на функцию.

Например, определим указатель на функцию:

void (*message) ();

В данном случае определен указатель, который имеет имя message . Он может указывать на функции без параметров, которые возвращают тип void (то есть ничего не возвращают).

Используем указатель на функцию:

#include void hello(); void goodbye(); int main() < void (*message)(); // определение указателя на функцию message=hello; message(); message = goodbye; message(); >void hello() < std::cout void goodbye()

Указателю на функцию можно присвоить функцию, которая соответствует указателю по возвращаемому типу и спецификации параметров:

message=hello;

То есть в данном случае указатель message теперь хранит адрес функции hello. И посредством обращения к указателю мы можем вызвать эту функцию:

message();

В качестве альтернативы мы можем обращаться к указателю на функцию следующим образом:

(*message)();

Впоследствии мы можем присвоить указателю адрес другой функции, которая также соответствует определению указателя. В итоге результатом данной программы будет следующий вывод:

Hello, World Good Bye, World

При определении указателя стоит обратить внимание на скобки вокруг имени. Так, использованное выше определение

void (*message) ();

НЕ будет аналогично следующему определению:

void *message ();

Во втором случае определен не указатель на функцию, а прототип функции message, которая возвращает указатель типа void* .

Определение и инциализация указателя

При определении указатель можно сразу инициализировать:

void (*message)() ; // указывает на функцию hello // или так void (*message2)() =hello; // указывает на функцию hello

Можно инициализировать значением nullptr :

void (*message)() < nullptr>;

Если указатель при определении инициализируется какой-либо функцией, то можно опустить все определение типа и просто использовать слово auto :

auto message < hello>; // указывает на функцию hello auto message2 = hello; // указывает на функцию hello

Можно подчеркнуть, что переменная является именно указателем, указав после auto символ звездочки:

auto* message < hello>;

Но особой разницы — что со звездочкой, что без звездочки нет.

Стоит отметить, что при присвоении функции мы можем применять операцию получения адреса:

auto message < &hello>;

Но в принципе применение такого символа, как и символа звездочки с auto, ни на что не влияет.

Указатель на функцию с параметрами

Рассмотрим еще один указатель на функцию:

#include int sum(int, int); int subtract(int, int); int main() < int a; int b; int (*operation)(int, int) ; // указатель operation указывает на функцию sum int result = operation(a, b); // result = (*operation)(a, b); // альтернативный вариант std::cout int, возвращающую также значение типа int. Соответственно мы можем присвоить указателю адреса функций add и subtract и вызвать их, передав при вызове указателю некоторые значения для параметров.

Массивы указателей на функции

Кроме одиночных указателей на функции мы можем определять их массивы. Для этого используется следующий формальный синтаксис:

тип (*имя_массива[размер]) (параметры)
double (*actions[]) (int, int)

Здесь actions представляет массив указателей на функции, каждая из которых обязательно должна принимать два параметра типа int и возвращать значение типа double .

Посмотрим применение массива указателей на функции на примере:

#include void add(int, int); void subtract(int, int); void multiply(int, int); int main() < int a ; int b ; void (*operations[3])(int, int) = ; // получаем длину массива unsigned length = std::size(operations); for(unsigned i<>; i < length; i++) < operations[i](a, b); // вызов функции по указателю >> void add(int x, int y) < std::cout void subtract(int x, int y) < std::cout void multiply(int x, int y) < std::cout x + y = 15 x - y = 5 x * y = 50

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *