Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Кетков.doc
Скачиваний:
17
Добавлен:
27.09.2019
Размер:
2.22 Mб
Скачать

8.10. Указатели на функцию и передача их в качестве параметров

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

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

Объявление указателя pf на функцию f(x), аргумент которой и возвращаемое значение имеют тип double, выглядит следующим образом:

double (*pf)(double x);

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

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

double int_rect(double a, double b, double (*f)(double x))

{ int i, n=100;

double s=0,h=(b-a)/n;

for(i=0; i<=n; i++) s += f(a+i*h);

return s*h;

}

Последним аргументом процедуры int_rect является указатель на функцию. Поэтому в качестве фактического параметра мы должны подставить имя подынтегральной функции. Таковым, в частности, может быть имя любой стандартной функции из библиотеки math.h:

cout << int_rect(0,M_PI,sin) << endl; //результат= 1.99984

cout << int_rect(0,M_PI,cos) << endl; //результат=-4.18544e-17

В качестве второго примера рассмотрим программу нахождения корня уравнения y=f(x), если известно, что на интервале [x1, x2] эта функция меняет знак. Алгоритм базируется на делении отрезка пополам. В точке xmid=(x1+x2)/2 смотрим знак функции f, который совпадет либо со знаком f(x1), либо со знаком f(x2). Выбираем ту половину отрезка, на концах которой функция принимает разные знаки. Затем исследуем его середину и т.д. Как только длина очередного отрезка станет достаточно малой или значение функции в центре отрезка окажется меньше заданной точности, процесс поиска корня прекращается.

#include <iostream.h>

#include <conio.h>

#include <math.h>

double y(double x) //функция f(x)=x2-4

{ return x*x-4; }

double root(double x1,double x2,double eps,double(*f)(double x))

{ double f12,f1,f2,xmid;

f1=f(x1); f2=f(x2);

if(f1*f2>0)

{ cerr<<"Error: sign(f1)=sign(f2)"; getch(); exit(0); }

while(x2-x1 > eps)

{ xmid=(x1+x2)/2.;

f12=f(xmid);

if(fabs(f12) < eps)

return xmid;

if(f12*f1>0) { x1=xmid; f1=f12; }

else {x2=xmid; f2=f12; }

}

return (x1+x2)/2.;

}void main()

{ cout<<root(0,10,1e-4,y);

getch();

}

//=== Результат работы ===

2.00001

8.11. "Левые" функции

В документации по системам программирования и в сообщениях об ошибках иногда можно встретить термины lvalue и rvalue. Они обозначают, соответственно, величины, которые могут находиться слева (lvalue = left value) от знака равенства в операторе присваивания или справа (rvalue = right value).

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

Приведем в качестве примера функцию, возвращающую ссылку на максимум из двух своих аргументов:

double& max(double &x, double &y)

{ return (x>y)? x : y; }

Ее обычное использование:

double r=max(a,b);

Использование с учетом "левизны":

double a=5,b=6;

max(a,b)=10; //эквивалентно b=10;

Аналогичный вариант, когда функция max возвращает указатель:

double* max(double *x, double *y)

{ return (*x>*y)?*x:*y; }

.........................

double a=5,b=6;

*max(&a,&b)=10; //эквивалентно b=10;

Левая функция, возвращающая ссылку на максимальный элемент массива:

int& Mmax(int a[],int n)

{ int im=0; //индекс максимального элемента

for(int j=1;j<n;j++) im=(a[im>a[j])? im : j;

return a[im];

}

Левая функция, возвращающая указатель на максимальный элемент массива:

int* Mmax(int a[],int n)

{ int im=0; //индекс максимального элемента

for(int j=1;j<n;j++) im=(a[im>a[j])? im : j;

return &a[im];

}

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

const double& max(double &x, double &y)

{ return (x>y)? x : y); }