Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Язык программирования C++ (Практикум, часть 1).doc
Скачиваний:
5
Добавлен:
01.07.2025
Размер:
5.28 Mб
Скачать

Рекурсия

Рекурсивной называют функцию, которая в своём теле вызывает саму себя (прямая рекурсия). Когда две или более функций вызывают друг друга, возникает косвенная рекурсия.

Пример: вычисление факториала числа (0! = 1 и 1! = 1)

n ! = 123(n–1)n

// Листинг 9.2

#include <iostream>

using namespace std;

int factorial(int); // Прототип функции

int main() {

int k = 4;

cout <<"k="<< k <<"; k! ="<< factorial(k) <<endl;

return 0; }

int factorial(int n) {

if (n < 0) {

cout << "ERROR!" << endl; return -1;

}

// Рекурсивный вызов

return (n > 1) ? n*factorial(n–1) : 1;

}

Каждое обращение к функции при рекурсии сопровождается организацией в стеке нового полного набора её локальных переменных и переданных ей параметров. Поэтому рекурсивны­ми функциями следует пользоваться с осторожностью, оценивая глубину рекурсии (иначе возможно переполнение стека).

Очень важно при организации рекурсивных функций предусмотреть проверку условия выхода из рекурсии. Иначе можно «улететь» в бесконечную рекурсию. Любую рекурсивную функцию можно реализовать без использования рекурсии.

Достоинство рекурсии – компактная запись.

Недостатки рекурсии – расход времени и памяти на повторные вызовы функции и передачу ей копий параметров, а также опасность переполнения стека.

Передача параметров в функцию

При передаче параметров в функцию используется неявное преобразование типов в соответствии с существующей в языке иерархией типов:

bool, char, shortint;

floatdouble.

В заголовке функции можно указать значения параметров по умолчанию. Они должны быть последними в списке и могут опускаться при вызове функции. Если при вызове параметр опущен, должны быть опущены и все параметры, стоящие в списке за ним.

В качестве значений параметров по умолчанию могут использоваться константы, глобальные переменные, выражения.

Например,

int f1(int x, int y = 0);

void f2(int, int = 20, char * = 0);

i nt a = 15;

// Вызовы функций:

f1(5); // x = 5, y = 0

f1(a, 1); // x = a, y = 1

f2(a); // 1-й параметр = a, 2-й = 20, 3-й = 0

f2(a, 10); // 1-й параметр = a, 2-й = 10, 3-й = 0

f2(7, 100, "text"); // 1-й параметр = 7, 2-й = 100,

// 3-й = указателю на строку "text"

// f2(a, , "text"); неверно: поскольку опущен 2-й

// параметр, должен быть опущен и 3-й.

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

Язык С++ снабжён двумя средствами для передачи по ссылке.

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

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

void swap1(int & a, int & b) { // Передаются ссылки

int temp = a;

a = b;

b = temp;

}

Вызов этой функции:

int x = 5, y = 11;

swap1(x, y); // Аргументы передаются по ссылке

cout << "x=" << x << " y=" << y << endl; //x=11 y=5

Второй способ – передача по ссылке с аргументами-указателями (стиль языка С). Указатели, подобно ссылкам, так­же можно использовать для модификации одного или более зна­чений переменных в вызывающем операторе, или передавать ука­затели на большие объекты данных, чтобы избежать накладных расходов (при создании копий), сопутствующих передаче объек­тов по значению. При вызове функции с аргументами, которые должны быть модифицированы, передаются адреса аргументов. Это обычно сопровождается операцией & получения адреса пере­менной, которая должна быть модифицирована. При передаче функции адреса переменной в теле функции может использовать­ся операция * (косвенной адресации или разыменования) для модификации значения ячейки в памяти вызывающего оператора.

В этом случае аналогичная функция будет выглядеть так:

void swap2(int *pa, int *pb){//Передаются указатели

int temp = *pa; // К указателям применяется

*pa = *pb; // операция разыменования *

*pb = temp;

}

а её вызов так:

int x = 5, y = 11;

swap2(&x,&y);//Использ-ся операция получения адреса

cout << "x=" << x << " y=" << y << endl; //x=11 y=5