Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЯП - ПОИТ (Бахтизин) часть 1 редакт.doc
Скачиваний:
0
Добавлен:
07.01.2020
Размер:
1.76 Mб
Скачать

5.4. Рекурсивные функции

Функция может вызывать саму себя. Это называется рекурсией, которая может быть прямой и косвенной. Если функция вызывает саму себя – это прямая рекурсия, если же она вызывает другую функцию, которая в свою очередь вызывает первую, то это косвенная рекурсия. Рекурсия полезна в тех случаях, когда выполняется процедура над данными и потом эту же процедуру надо выполнить над полученным результатом.

Важно рекурсию когда-нибудь прекратить (задать некоторое условие), иначе рекурсивная функция будет вызывать себя до тех пор, пока приложение не будет аварийно завершено в результате переполнения стека. Также при каждом обращении к такой функции ей должны передаваться модифицированные данные, а после завершения каждого экземпляра рекурсивной функции в вызывающую должен возващаться некоторый результат для дальнейшего использования. Рекурсивый процесс должен шаг за шагом так упрощать задачу, чтобы в конце концов на последнем шаге для нее появилось нерекурсивное решение.

Когда функция вызывает саму себя, передаётся новая копия данных этой функции, что приводит иногда к большим затратам памяти. Локальные переменные во второй версии независимы от локальных переменных первой и не могут непосредственно влиять друг на друга.

Пример использования рекурсии рассмотрим на программе нахождения определённого члена ряда Фибоначчи:

1,1,2,3,5,8,13,21,34…

Каждое число ряда представляет собой сумму двух предыдущих чисел. В общем случае n-e число равно сумме (n-2)-го и (n-1)-го чисел.

Для рекурсивных функций необходимо условие прекращения рекурсии, в ряду Фибоначчи условием прекращения будет n<3.

#include <stdio.h>

int fib (int);

void main()

{

int n, answer;

printf(“Введите номер для нахождения: ”);

scanf(“%d”, &n);

answer = fib(n);

printf(“\n answer is: %d”, answer);

}

int fib(int n)

{

if (n<3)

return 1;

else

return (fib(n-2) + fib(n-1));

}

После ввода параметра, программа проверяет, не меньше ли он числа 3, и, если это так, то функция fib() возвращает значение 1. В противном случае выводится сумма значений, возвращаемых при вызове функции fib() с параметрами n-2 и n-1. Таким образом, эту программу можно представить как циклический вызов функции fib(). Единственными вызовами, которые немедленно возвращают 1, являются вызовы функций fib(1) и fib(2). Рекурсивное использование функции fib() показано на рис 5.3.

Рис.5.3. Использование рекурсии

5.5. Использование функций в качестве параметров функций

Вполне допустимо для одной функции принимать в качестве параметра значение, возвращаемое другой функцией. Это можно рассмотреть на простом примере:

Имеются некоторые функции: double() – удвоение числа, triple() – утроение числа, square() – возведение в квадрат, cube() – возведение в куб, возвращающие некоторые целые значения. Можно записать:

answer = (doubleValue(tripleValue(square(cube(x)))));

Это выражение принимает переменную х, и передаёт её в качестве параметра функции cube(), возвращаемое значение которой (куб числа) передаётся как параметр функции square(). После этого возвращаемое значение функции (квадрат числа) передаётся в качестве параметра функции tripleValue(). Возвращаемое значение данной функции (утроенное число) передаётся как параметр функции doubleValue(). Наконец, значение возврата функции doubleValue() (удвоенное число) присваивается переменной answer.

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

unsigned long x = 2;

unsigned long cub = cube(x); // 2 в кубе = 8

unsigned long squar = square(cub); // 8 в квадрате = 64

unsigned long tripl = tripleValue(squar); // 64 * 3 = 192

unsigned long answer = doubleValue(tripl); // 192 * 2 = 384

Применены значения параметров, используемые по умолчанию.

Для каждого параметра, объявляемого в прототипе и определении функции, должно быть передано соответствующее значение в вызове функции. Передаваемое значение должно иметь объявленный тип. Из этого правила существует исключение. Если в прототипе функции для параметра объявляется стандартное значение, то это значение используется, если при вызове функции для этого параметра не установлено никакого значения. Например, прототип функции:

long myFunc(int x = 50);

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

long myFunc(int = 50);

Имя параметра, для которого в прототипе устанавливается значение по умолчанию, может не совпадать с именем параметра, указываемого в заголовке функции (значение, заданное по умолчанию присваивается по позиции, а не по имени).