Указатели на функцию
Адресное выражение, стоящее перед скобками определяет адрес вызываемой функции. Это значит, что функция может быть вызвана через указатель на функцию.
Пример:
int (*fun)(int x, int *y);Здесь объявлена переменная fun как указатель на функцию с двумя параметрами: типа int и указателем на int. Сама функция должна возвращать значение типа int. Круглые скобки, содержащие имя указателя fun и признак указателя *, обязательны, иначе запись
int *fun (int x, int *y);будет интерпретироваться как объявление функции fun возвращающей указатель на int.
Вызов функции возможен только после инициализации значения указателя fun и имеет вид:
(*fun)(i, &j);В этом выражении для получения адреса функции, на которую ссылается указатель fun, используется операция разадресации *.
Указатель на функцию может быть передан в качестве параметра функции. При этом разадресация происходит во время вызова функции, на которую ссылается указатель на функцию. Присвоить значение указателю на функцию можно в операторе присваивания, употребив имя функции без списка параметров.
Пример:
double (*fun1)(int x, int y); double fun2(int k, int l); fun1=fun2; /* инициализация указателя на функцию */ (*fun1)(2,7); /* обращение к функции */В рассмотренном примере указатель на функцию fun1 описан как указатель на функцию с двумя параметрами, возвращающую значение типа double, и также описана функция fun2. В противном случае, т.е. когда указателю на функцию присваивается функция, описанная иначе, чем указатель, произойдет ошибка.
Рассмотрим пример использования указателя на функцию в качестве параметра функции вычисляющей производную от функции cos(x).
Пример:
#include <stdio.h>#include <math.h> double proiz(double x, double dx, double (*f)(double x) ); double fun(double z); int main() { double x; /* точка вычисления производной */ double dx; /* приращение */ double z; /* значение производной */ scanf("%lf%lf", &x, &dx); /* ввод значений x и dx */ z=proiz(x, dx, fun); /* вызов функции */ printf("%f", z); /* печать значения производной */ return 0; } double proiz(double x, double dx, double (*f)(double z) ) { /* функция, вычисляющая производную */ double xk,xk1,pr; xk=(*f)(x); xk1=(*f)(x+dx); pr=(xk1/xk-1.)*xk/dx; return pr; } double fun( double z) { /* функция от которой вычисляется производная */ return (cos(z)); }Для вычисления производной от какой-либо другой функции можно изменить тело функции fun или использовать при вызове функции proiz имя другой функции. В частности, для вычисления производной от функции cos(x) можно вызвать функцию proiz в форме
z=proiz(x,dx,cos);а для вычисления производной от функции sin(x) в форме
z=proiz(x,dx,sin);Рекурсия
Любая функция в программе на языке СИ может быть вызвана рекурсивно, т.е. она может вызывать саму себя. Компилятор допускает любое число рекурсивных вызовов. При каждом вызове для формальных параметров и переменных с классом памяти auto и register выделяется новая область памяти, так что их значения из предыдущих вызовов не теряются, но в каждый момент времени доступны только значения текущего вызова.
Переменные, объявленные с классом памяти static, не требуют выделения новой области памяти при каждом рекурсивном вызове функции и их значения доступны в течение всего времени выполнения программы.
Классический пример рекурсии — это математическое определение факториала n!:
n! = 1 при n=0; n*(n-1)! при n>1 .Функция, вычисляющая факториал, будет иметь следующий вид:
long fakt(int n) { return ( (n==1) ? 1 : n*fakt(n-1) ); }Хотя компилятор языка СИ не ограничивает число рекурсивных вызовов функций, это число ограничивается ресурсом памяти компьютера и при слишком большом числе рекурсивных вызовов может произойти переполнение стека.
Дата добавления: 2016-07-27; просмотров: 1762;