Подпрограммы – параметры других подпрограмм. Указатели на функции в Си. Лекция 5

Содержание

Слайд 2

В каких задачах используются подпрограммы-параметры (в Си функции-параметры)? Когда некоторый алгоритм,

В каких задачах используются подпрограммы-параметры (в Си функции-параметры)?

Когда некоторый алгоритм, описанный

как подпрограмма, применим к множеству алгоритмов, каждый из которых также задается подпрограммой.
Классические примеры таких ситуаций дают численные методы. В подпрограммах численных методов (вычисления определенного интеграла, нахождения экстремумов и нулей функций, вывода графиков, линий уровня, таблиц функций) обрабатываемые функции задаются как параметры.
Возможности использования параметров-подпрограмм имеются во всех алгоритмических языках, предназначенных для решения вычислительных задач (СИ, Фортран, Паскаль, Матлаб, …).
Слайд 3

Средства СИ для работы с подпрограммами-параметрами: указатели на функцию Указатель на

Средства СИ для работы с подпрограммами-параметрами: указатели на функцию
Указатель на функцию:
тип

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

Скобки обязательны, чтобы * не относилась к типу функции. Допустимо: тип* ( *имя_функции(с_ф_п)

Слайд 4

ОПИСАНИЕ ФУНКЦИИ В СИ

ОПИСАНИЕ ФУНКЦИИ В СИ

Слайд 5

ОПИСАНИЕ ФУНКЦИИ В СИ

ОПИСАНИЕ ФУНКЦИИ В СИ

Слайд 6

Пример 1. Решение двух уравнений (в одной программе) на отрезке [0.1,

Пример 1. Решение двух уравнений (в одной программе) на отрезке [0.1,

2] c погрешностью 0.0001 (задача 1.8.N,N+1 – таблица 1).

fx1(x)

fx2(x)

Слайд 7

Си-программа #include #define _USE_MATH_DEFINES #include #include #include /*fx1 и fx2 -

Си-программа

#include
#define _USE_MATH_DEFINES
#include
#include
#include
/*fx1 и fx2 - функции, задающие

левую часть уравнений, их заголовки соответствуют указателю на функцию вызывающей функции root */
double fx1(double x)
{return (x*x-1);
}
double fx2(double x)
{return (log(x+1)/(0.001+pow(x,1.0/4)*pow(sin(x),2))-1/(M_PI*x*pow(x,1.0/3))-exp(x/7));
}
Слайд 8

Си-программа (продолжение) /*root - функция вычисления корня уравнения f(x)=0 на отрезке

Си-программа (продолжение)

/*root - функция вычисления корня уравнения f(x)=0 на отрезке [a,b]

методом дихотомии*/
/*с точностью e*/
double root(double(*f)(double),double a,double b, double e)
{double x;
while(fabs(b-a)>e)
{x=(a+b)/2.0;
if ((*f)(a)*(*f)(x)>0)
a=x;
else
b=x;
}
x=(a+b)/2;
return x;
}

вызов формальной функции

Слайд 9

Си-программа (продолжение) void main() {double r1,r2; /*значения корней*/ setlocale(LC_ALL, ""); r1=root(*fx1,0.1,2,1e-4);

Си-программа (продолжение)

void main()
{double r1,r2; /*значения корней*/
setlocale(LC_ALL, "");
r1=root(*fx1,0.1,2,1e-4);
r2=root(*fx2,0.1,2,1e-4);
printf("корень

первого уравнения=%7.4f f(r1)=%8.5f \n"
"корень второго уравнения=%7.4f f(r2)=%8.5f\n",r1,fx1(r1),r2,fx2(r2));
_getch();
}

Подстановка указателя на фактическую функцию

Слайд 10

Приближенное решение уравнения на отрезке Известно, что уравнение F(x)=0 (*) на

Приближенное решение уравнения на отрезке

Известно, что уравнение
F(x)=0 (*)
на отрезке [A,B] имеет

ровно один корень.
Требуется найти приближенное значение корня с точностью ε:
|x*-xпр|< ε,
где x* - точное значение корня, xпр – приближенное значение корня.
Слайд 11

Приближенное решение уравнения на отрезке A B x y=F(x) x* Если

Приближенное решение уравнения на отрезке

A

B

x

y=F(x)

x*

Если уравнение (*) имеет на отрезке [A,B]

ровно один корень, то F(A)*F(B)≤0.
Слайд 12

Метод деления отрезка пополам (дихотомии) Если F(x)*F(A)>0, то x*∉[A,x] ⇒ корень

Метод деления отрезка пополам (дихотомии)

Если F(x)*F(A)>0, то x*∉[A,x] ⇒ корень надо

искать на правой половине отрезка x*∈[x,B] : A=x;
иначе x*∈[A,x] ⇒ корень надо искать на левой половине отрезка: B=x.
Далее деление пополам нового отрезка.

x1

x2

x3

Слайд 13

Метод деления отрезка пополам (дихотомии) i-ая итерация (цикл): вычисление xi -

Метод деления отрезка пополам (дихотомии)

i-ая итерация (цикл): вычисление xi - середины

i-го отрезка и выбор его левой или правой половины.
{xi}→ x* при i →∞.
Условие продолжения цикла: B-A>ε.
Слайд 14

Метод деления отрезка пополам (дихотомии) – блок-схема функции root Алгоритм для

Метод деления отрезка пополам (дихотомии) – блок-схема функции root

Алгоритм для идеального

случая: на [A,B] ровно один корень.
Слайд 15

Как протестировать программу? 1. Вывести не только r1, r2, но и

Как протестировать программу?

1. Вывести не только r1, r2, но и fx1(r1),

fx2(r2). Эти значения функций должны быть близкими к нулю. Если они сильно отличаются от нуля, то программа работает неправильно. Однако их близость к нулю не гарантирует правильность программы.
Слайд 16

Как протестировать программу? 2. Построить графики функций или решить уравнение в другой вычислительной среде

Как протестировать программу? 2. Построить графики функций или решить уравнение в

другой вычислительной среде
Слайд 17

Как еще можно использовать указатели на функции Описывается шаблон указателя на

Как еще можно использовать указатели на функции

Описывается шаблон указателя на функцию:
тип

(*имя_функции)(список формальных параметров); /*такой функции не существует, просто объявлен шаблон*/
имя_функции= имя_функции_существующей;
Далее, когда пишется имя функции шаблона, вызывается существующая функция.
Слайд 18

Пример 2 #include #include int add(int a, int b) {return (a+b);

Пример 2

#include
#include
int add(int a, int b)
{return (a+b);
}
int substruct(int a,

int b)
{return (a-b);
}
int multiplicate(int a, int b)
{return (a*b);
}
int divide(int a, int b)
{return (a/b);
}

Объявлены реальные функции, соответствующие одному шаблону