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

Зачастую внесение рекурсивности в программы придает им изящность. Но всегда оно же «заставляет» программы расходовать больше памяти. Дело в том, что каждый «отложенный» вызов функции или процедуры — это свой набор значений всех локальных переменных этой функции, размещенных в стеке. Если будет, например, 100 рекурсивных вызовов функции, то в памяти должны разместиться 100 наборов локальных переменных этой функции. В Турбо Паскале размер стека (он регулируется первым параметром директивы компилятора $M) не может превышать 64К — а это не так уж много.

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

| FUNCTION IntPower(x : Real; n : Word ) : Real;

| VAR

| i : Word; m : Real;

| BEGIN

| m : = 1;

| for i:=1 to n do

| m:=m*x;

| IntPower := m

| END;

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

Отметим, что в общем случае класс функций вида

- 124 -

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

В заключение несколько слов о работе оператора Exit в рекурсивных процедурах. Он срабатывает всегда на один «уровень» глубины рекурсии. Таким образом, выйти из рекурсивной подпрограммы до ее естественного завершения довольно непросто.

Все сказанное выше будет также верно и для так называемой косвенной рекурсии — когда подпрограмма A вызывает подпрограмму B, а в B содержится вызов A. Только расход памяти будет еще больше из-за необходимости сохранения локальных переменных B.

<p>6.10. Модули. Структура модулей</p>

Модуль (UNIT) в Турбо Паскале — это специальным образом оформленная библиотека определений типов, констант, переменных, а также процедур и функций. Модуль в отличие от программы не может быть запущен на выполнение самостоятельно: он может только участвовать в построении программы или другого модуля. Но в отличие от фрагментов, подключаемых к программе при компиляции директивой {$1 ИмяФайла}, модули предварительно компилируются независимо от использующей их программы. Результатом компиляции модуля является файл с расширением .TPU (Turbo Pascal Unit). Для того чтобы подключить модуль к программе (или другому модулю), необходимо и достаточно указать его имя в директиве USES.

Все системные библиотеки Турбо Паскаля реализованы как модули, и чтобы воспользоваться, например, библиотеками функций операционной системы DOS и графики Graph, нужно только указать директиву

USES

DOS, Graph;

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

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

- 125 -

построения собственных библиотек процедур и функций, которые впоследствии могут подключаться к разным программам, не требуя при этом никаких переделок. Во-вторых, именно модульность позволяет создавать программы практически любого размера. Дело в том, что ни программа, ни модуль, не могут произвести выполнимый код объемом более 64K, если они не используют при построении другие модули. В то же время сумма объемов модулей, составляющих программу, ограничена лишь объемом ОЗУ ПЭВМ, и то, если не используется оверлейная структура. Общая структура модуля приводится на рис. 6.17.

UNIT ИмяМодуля;

INTERFACE ← начало раздела объявлений

USES { используемые при объявлениях модули: }

Имя_Модуля1, Имя_Модуля2, ... ;

CONST Блок объявления библиотечных констант

TYPE Блок объявления библиотечных типов

VAR Блок объявления библиотечных переменных

Заголовки библиотечных процедур и (или) функций

IMPLEMENTATION ← начало раздела реализации

USES { используемые при реализации модули:}

Имя_Модуля101, Имя_Модуля202, ... ;

CONST Блок объявления внутренних констант

TYPE Блок объявления внутренних типов

VAR Блок объявления внутренних переменных

LABEL Блок описания меток блока инициализации

BEGIN

Блок инициализации модуля

END.

Рис. 6.17

Модуль разделяется на четыре части:

— заголовок модуля (UNIT имя);

Перейти на страницу:

Поиск

Похожие книги