Адрес функции
Адресное выражение, стоящее перед скобками определяет адрес вызываемой
функции. Это значит, что функция может быть вызвана через указатель на функцию.
Пример:
int (*fun)(int x, int *y);
Здесь объявлена переменная fun как указатель на функцию с двумя параметрами:
типа int и указателем на int. Сама функция должна возвращать значение типа int.
Круглые скобки, содержащие имя указателя fun и признак указателя *,обязательны, иначе запись
int *fun (intx,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).
Пример:
doubleproiz(double x, double dx, double (*f)(double x) );
double fun(double z);
int main()
{
double x; /* точка вычисления производной */
doubledx; /* приращение */
double z; /* значение производной */
scanf("%f,%f",&x,&dx); /* ввод значений x и dx */
z=proiz(x,dx,fun); /* вызов функции */
printf("%f",z); /* печать значения производной */
return 0;
}
doubleproiz(double x,double dx, double (*f)(double z) )
{ /* функция вычисляющая производную */
double xk,xk1,pr;
xk=fun(x);
xk1=fun(x+dx);
pr=(xk1/xk-1e0)*xk/dx;
returnpr;
}
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! :
Функция, вычисляющая факториал, будет иметь следующий вид:
longfakt(int n) { return ( n ? 1 : n*fakt(n-1) ); }
Хотя компилятор языка СИ не ограничивает число рекурсивных вызовов функций,
это число ограничивается ресурсом памяти компьютера и при слишком большом числерекурсивных вызовов может произойти переполнение памяти.