Подпрограммы – параметры других подпрограмм. Указатели на функции в Си
Выбери формат для чтения
Загружаем конспект в формате ppt
Это займет всего пару минут! А пока ты можешь прочитать работу в формате Word 👇
Подпрограммы – параметры
других подпрограмм.
Указатели на функции в Си
лекция №5
В каких задачах использую тся
подпрограммы -параметры (в Си функциипараметры )?
• Когда некоторый алгоритм, описанный как
подпрограмма, применим к множеству алгоритмов,
каждый из которых также задается подпрограммой.
• Классические примеры таких ситуаций дают
численные методы. В подпрограммах численных
методов (вычисления определенного интеграла,
нахождения экстремумов и нулей функций, вывода
графиков, линий уровня, таблиц функций)
обрабатываемые функции задаются как параметры.
• Возможности использования параметровподпрограмм имеются во всех алгоритмических
языках, предназначенных для решения
вычислительных задач (СИ, Фортран, Паскаль,
Матлаб, …).
Средства СИ для работы с
подпрограммами-параметрами: указатели на
функцию
Скобки обязательны, чтобы * не относилась к
типу функции. Допустимо: тип*
( *имя_функции(с_ф_п)
•
Указатель на функцию:
тип (*имя_функции)(список формальных параметров)
По имени функции определяется адрес ее начала (точки входа) как указатель на
функцию.
•
В списке формальных параметров основной функции приводится полный
заголовок указателя на формальную функцию (возможно, без имен формальных
параметров):
тип (*имя_формальной_функции)(список формальных параметров)
В теле основной функции формальная функция вызывается так:
(*имя_формальной_функции)(список фактических параметров)
•
В список фактических параметров подставляется указатель
*имя_фактической_функции.
Заголовок фактической функции должна совпадать с формальным указателем
на функцию с точностью до обозначений (т. е. типы функций и формальных
параметров должны быть одинаковыми.
ОПИСАНИЕ ФУНКЦИИ В СИ
Заголовок
Тип ИмяФункции(СписокФормальныхПараметров)
{Описание данных
Б
Операторы
л
return (выражение,возвращаемое функцией)
о
как в главной функции
}
к
тип возвращаемого значения; если отсутствует, то int;
если void, то значение не возвращается, т. е. имеем аналог
подпрограммы общего назначения, в этом случае return не нужен
В списке формальны х параметров может стоять
указатель на функцию
ОПИСАНИЕ ФУНКЦИИ В СИ
Заголовок
Тип ИмяФункции(СписокФормальныхПараметров)
Два смысла: 1) имя алгоритма,точнее - адрес точки входа в функцию
2) возвращаемое значение (имя функции можно использовать в
выражениях).
Если имя функции main, то это главная функция, она первой
получает управление после запуска программы. main обязательно
присутствует в программе. Пока рассматриваем main без
параметров.
В списке формальны х параметров может стоять
указатель на функцию
Пример 1. Решение двух уравнений (в одной
программе) на отрезке [0.1, 2] c
погрешностью 0.0001 (задача 1.8.N,N+1 –
таблица 1).
fx1(x)
x 2 1 0
fx2(x)
ln x 1
2
4
0,001 x sin x
1
3
x x
e x 7 0
Си-программа
#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));
}
Си-программа (продолжение)
/*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;
}
Си-программа (продолжение)
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();
}
Приближенное решение
уравнения на отрезке
Известно, что уравнение
F(x)=0
(*)
на отрезке [A,B] имеет ровно один корень.
Требуется найти приближенное значение корня с
точностью :
|x*-xпр|< ,
где x* - точное значение корня,
xпр – приближенное значение корня.
Приближенное решение
уравнения на отрезке
y=F(x)
A
x*
B
x
Если уравнение (*) имеет на отрезке [A,B] ровно один
корень, то F(A)*F(B)0.
Метод деления отрезка
пополам (дихотомии)
y=F(x)
A
x=(a+b)/2
x1
x*
x2
B
x3
x
Если F(x)*F(A)>0, то x*[A,x] корень надо искать на
правой половине отрезка x*[x,B] : A=x;
иначе x*[A,x] корень надо искать на левой половине
отрезка: B=x.
Далее деление пополам нового отрезка.
Метод деления отрезка
пополам (дихотомии)
i-ая итерация (цикл): вычисление xi - середины
i-го отрезка и выбор его левой или правой
половины.
{xi} x* при i .
Условие продолжения цикла: B-A>.
Метод деления отрезка пополам
(дихотомии) – блок-схема функции root
Можно определить число N итераций
(циклов), необходимых для обеспечения
погрешности . В конце N-го цикла
длина отрезка, накрывающего корень,
равна:
Алгоритм для идеального
случая: на [A,B] ровно один
корень.
передача a,b,,F
l
x:=(A+B)/2
-
F(x)*F(A)>0
B:=x
B A
+
A:=x
root=(A+B)/2
передача root
.
Число итераций можно вычислить из
соотношения:
l .
B-A<
+
2
N
Откуда:
log2(B-A)-N log2(),
и, следовательно,
N=log2(B-A)- log2,
Как протестировать программу?
1. Вывести не только r1, r2, но и fx1(r1), fx2(r2). Эти
значения функций должны быть близкими к нулю. Если
они сильно отличаются от нуля, то программа
работает неправильно. Однако их близость к нулю не
гарантирует правильность программы.
Как протестировать программу?
2. Построить графики функций или решить
уравнение в другой вычислительной среде
14
12
10
8
fx1
fx2
6
4
2
-2
0,2
0,4
0,6
0,8
1
1,2
1,4
1,6
1,8
2
2,2
2,4
Как еще можно использовать
указатели на функции
• Описывается шаблон указателя на функцию:
тип (*имя_функции)(список формальных параметров);
/*такой функции не существует, просто объявлен
шаблон*/
• имя_функции= имя_функции_существующей;
• Далее, когда пишется имя функции шаблона,
вызывается существующая функция.
Пример 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);
}
Объявлены реальные
функции,
соответствующие
одному шаблону
Продолжение примера 2
void main()
{int a,b; int operation;
int (*f)(int, int); //объявляется шаблон
printf("input a,b, operation\n");
scanf_s("%d%d%d",&a,&b,&operation);
printf("op=%d\n", operation);
switch (operation)
{
case 1: f=add; break;
case 2: f=substruct; break;
case 3: f=multiplicate; break;
case 4: f=divide; break;
default:
puts("no such operation");
}
printf("f(a,b)=%d\n", f(a,b)); //вызывается выбранная функция
_getch();
}