Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
TP_теория и практикум.doc
Скачиваний:
11
Добавлен:
20.08.2019
Размер:
861.7 Кб
Скачать

Побочный эффект рекурсии

В теле подпрограммы известны, то есть доступны все объекты, описанные в объемлющем блоке, в том числе и имя самой подпрограммы. Внутри тела подпрограммы возможен вызов самой подпрограммы. Параметры и функции использующие вызовы “самих себя“, называются рекурсивными. Допустима также косвенная рекурсия, при которой параметр А вызывает параметр В, а тот, в свою очередь, вызывает С, который вызывает первоначальный параметр А.

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

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

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

Пример:

Program Side Effect;

Var a,z :integer;

Function change (x: integer): integer;

Begin

Z:=z-x; {изменяем значение нелокальной переменной}

Change:= sqr (x)

End;

Begin

Z:=10; a:=change (z); writeln(a,z);

Z:=10; a:=change (10)*change (z);

Writeln(a,z);

Z:=10; a:=change (z) * change(10);

Writeln (a,z)

End.

Выполнение этой программы приводит к следующему результату на дисплее:

100 0

10000 -10

0 0

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

Следует всячески избегать такой зависимости функции от глобальных по отношению к ней переменных. Заметим, что современные языки, например, Ada содержит прямые запреты на подобные действия.

Предварительное описание (ссылки вперед)

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

Пример :

Program Demo;

Var a, b ,c : real ;

Procedure Ring (var s , l : real ; d : real);

Begin L:=3.14 *d; {длина окружности }

S:=cir (d) ; {компилятор еще не знает о функции cir}

End;

Function Cir (d: real): real; {площадь круга }

Begin cir:= 3.14* sqr(d) / 4;

End;

………………………………………………………………………

Очевидный выход – поменять порядок строк так, чтобы функция Cir была определена перед процедурой Ring(…) .Однако можно и иначе.

Действия:

1. Оставить подпрограмму (функцию cir) на своем месте, вычеркнув из ее заголовка все параметры: Function cir;

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

Function cir (d: real): real;

  1. После полного заголовка добавить слово Forward.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]