Указатели на функции как параметры

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

double rectangle(double (* pf)(double), double a, double b)

{

int N=20; int i;

double h,s=0.0;

h=(b-a)/N;

for (i=0; i<N; i++)

s+=pf(a+h/2+i*h);

return h*s;

}

Параметры функции rectangle(): pf - указатель на функцию с параметром типа double, возвращающую значение типа double. Это указатель на функцию, вычисляющую значение подынте­гральной функции при заданном значении аргумента. Парамет­ры a, b - пределы интегрирования. Число интервалов разбиения отрезка интегрирования фиксировано: N=20. Пусть текст функ­ции под именем rect.c сохранен в каталоге пользователя.

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

Программа для решения этой задачи может иметь следую­щий вид:

#include "stdafx.h"

#include "stdio.h"

#include "conio.h"

#include "locale.h"

#include "math.h"

#include "rect.c" /* Включение определения функции rectangle() */

double ratio(double x) /* Подынтегральная функция */

{

double z; /* Вспомогательная переменная */

z=x*x+1;

return x/(z*z);

}

double cos4_2(double v) /* Подынтегральная функция */

{

double w; /* Вспомогательная переменная */

w=cos(v);

return 4*w*w;

}

int _tmain(int argc, _TCHAR* argv[])

{

setlocale(LC_ALL,"Russian");

double a,b,c;

a=-1.0;

b=2.0;

c=rectangle(ratio,a,b);

printf("\n Первый интеграл: %f",c);

printf("\n Второй интеграл: %f", rectangle(cos4_2,0.0,0.5));

_getch();

return 0;

}

Результат выполнения программы:

Первый интеграл: 0.149847

Второй интеграл: 1.841559

Директива #include "rect.c" включает на этапе препроцессорной обработки в программу определение функции rectangle(). Предполагается, как упомянуто выше, что текст этого опреде­ления находится в файле rect.c.

Определения функций ratio() и cos4_2(), позволяющих вы­числять значения подынтегральных выражений по заданному значению аргумента, ничем не примечательны. Их прототипы соответствуют требованиям спецификации первого параметра функции rectangle():

double имя (double)

В основной программе main() функция rectangle() вызыва­ется дважды с разными значениями параметров. Для разнообра­зия вызовы выполнены по-разному, но каждый раз первый пара­метр - это имя конкретной функции, т.е. константный указатель на функцию.

4. Указатель на функцию как возвращаемое функцией зна­чение

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

Рассмотрим программу, демонстрирующую особенности та­кой организации меню.

В программе определены три функции: первые две функции f1 () и f2() с прототипом вида

int f (void);

(пустой список параметров, возвращается значение типа int) и третья функция menu() с прототипом

int (*menu(void)) (void);

которая возвращает значение указателя на функции с пустыми списками параметров, возвращающие значения типа int.

При выполнении функции menu() пользователю дается воз­можность выбора из двух пунктов меню. Пунктам меню соот­ветствуют определенные выше функции f1 () и f2(), указатель на одну из которых является возвращаемым значением. При не­верном выборе номера пункта возвращаемое значение становит­ся равным NULL.

В основной программе определен указатель r, который мо­жет принимать значения адресов функций fl() иf2(). В беско­нечном цикле выполняются обращения к функции menu(),и если результат равен NULL, то программа печатает "The End" и завершает выполнение. В противном случае вызов

t=(*r) ();

обеспечивает исполнение той из функций f1 () или f2(), адрес которой является значением указателя r. Текст программы:

#include "stdafx.h"

#include "stdio.h"

#include "conio.h"

#include "locale.h"

int f1(void)

{

printf(" The first actions: ");

return 1;

}

int f2(void)

{

printf(" The second actions: ");

return 2;

}

int (* menu(void))(void)

{

int choice; /* Номер пункта меню */

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

int (* menu_items[])() = {f1, f2};

printf("\n Pick the menu item (1 or 2): ");

scanf("%d",&choice);

if (choice < 3 && choice > 0)

return menu_items[choice - 1];

else

return NULL;

}

int _tmain(int argc, _TCHAR* argv[])

{

int (*r) (void); /* Указатель на функции.*/

int t;

while (1)

{/* Обращение к меню: */

r=menu();

if (r == NULL)

{

printf("\nThe End!");

_getch();

return 0;

}

/* Вызов выбранной функции */

t=(*r) ();

printf("\tt= %d",t);

}

_getch();

return 0;

}

Результаты выполнения программы:

Pick the menu item (1 or 2): 2

The second actions: t=2

Pick the menu item (1 or 2): 1

The first actions: t=l

Pick the menu item (1 or 2): 24

The End!

В функции menu() определен массив menu_items[ ] указате­лей на функции. В качестве инициализирующих значений в списке использованы имена функций f1() и f2():

int(* menu_items[ ]) () = {fl, f2};

Такое определение массива указателей на функции по мень­шей мере не очень наглядно. Упростить такие определения можно с помощью вспомогательных обозначений (имен), вво­димых спецификатором typedef.Например, то же самое опреде­ление массива указателей можно ввести так:

typedef int (*Menu_action) (void);

Menu_action menu_items [ ] = {fl, f2};

Здесь typedef вводит обозначение Menu_action для типа "ука­затель на функции с пустым списком параметров, возвращаю­щие значения типа int".



Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: