Опубликован: 03.09.2010 | Доступ: свободный | Студентов: 3417 / 749 | Оценка: 4.11 / 3.69 | Длительность: 10:38:00
Лекция 4:

Модульное программирование

< Лекция 3 || Лекция 4: 1234 || Лекция 5 >

Параметры процедурного типа

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

Описание параметра подпрограммы в большинстве случаев состоит из имени и типа. Имя функции является константой процедурного ( функционального ) типа, который требуется описать в разделе type, например:

type fun  = function(x : real) : real;    
     pr   = procedure;
     proc = procedure(a, b : word; var c : word);

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

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

q=\frac{2x}{\sqrt{1-sin\:2x}}\qquad\gamma=cos\:x-0,2x

на интервале [a, b] с заданным количеством его разбиений ( пример 4.5).

program integrals;
type fun = function(x : real) : real;            { 1 }
var a, b : real;
    n    : integer;
{$F+}
function Q(x : real) : real;
    begin
        Q := 2 * x / sqrt(1 – sin(2 * x));
    end;
function R(x : real) : real;
    begin
        R := cos(x) – 0.2 * x;
    end;
{$F–}
function integr(f : fun; a, b : real; n : integer) : real;
    var sum, x, h : real;
                i : integer;
    begin
        h := (b – a) / n; sum := 0; x := a;
        for i := 1 to n do begin
            sum := sum + f(x); x := x + h;
        end;
        integr := sum * h;
    end;
begin
    writeLn('Введите интервал и количество шагов');
    readln(a, b, n);
    writeln('Интеграл для первой функции: ', integr(Q, a, b, n):8:3);
    writeln(' Интеграл для второй функции: ', integr(R, a, b, n):8:3);
end.
Листинг 4.5. Вычисление определенного интеграла методом прямоугольников

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

Итак, чтобы передать имя функции или процедуры в подпрограмму, необходимо:

  1. Определить соответствующий процедурный тип.
  2. Задать для функций и процедур, предназначенных для передачи в подпрограмму, ключ компилятора {$F +}, определяющий дальнюю адресацию. При этом компилятор формирует полный адрес, состоящий из сегмента и смещения. Альтернативный способ — указать в заголовке каждой функции директиву far:

function Q(x : real) : real; far;

Рекурсивные подпрограммы

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

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

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

Простой пример рекурсивной функции — вычисление факториала (это не означает, что факториал следует вычислять именно так). Чтобы получить факториал числа n, требуется умножить на n факториал ( n – 1)!. Известно также, что 0! = 1 и 1! = 1.

function fact(n : byte) : longint;
begin
    if (n = 0) or (n = 1) then fact := 1    
    else fact := n * fact(n – 1);    
end;

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

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

Модули

Модуль — это подключаемая к программе библиотека ресурсов. Он может содержать описания типов, констант, переменных и подпрограмм. В модуль обычно объединяют связанные между собой ресурсы: например, в составе оболочки есть модуль Graph для работы с экраном в графическом режиме. Модули применяются как библиотеки, которые могут использоваться различными программами, и для разбиения сложной программы на составные части.

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

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

Описание модулей

Исходный текст каждого модуля хранится в отдельном файле с расширением .pas. Модуль состоит из секций (разделов). Общая структура модуля:

unit имя;                                                    { заголовок модуля }
interface                            { ------------- интерфейсная секция модуля }
                         { описание глобальных элементов модуля (видимых извне) }
implementation                       { --------------- секция реализации модуля }
                             { описание локальных (внутренних) элементов модуля }
begin                                { ------------------- секция инициализации }
                                                          { может отсутствовать }
end.
ВНИМАНИЕ Имя файла, в котором хранится модуль, должно совпадать с именем, заданным после ключевого слова unit.

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

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

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

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

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

В оболочках Borland Pascal и Turbo Pascal результат компиляции по умолчанию размещается в оперативной памяти и на диск не записывается. Поэтому для сохранения скомпилированного модуля на диске требуется установить значение пункта Compile ( Destination в значение Disk. Компилятор создаст файл с расширением .tpu, который надо переместить в специальный каталог, путь к которому указан в пункте меню Options ( Directories в поле Unit Directories.

В качестве примера оформим в виде модуля подпрограмму вычисления среднего арифметического значения элементов массива из пример 4.1 ( пример 4.6).

unit Average;
interface
    const n = 10;
    type mas = array[1 .. n] of real;
    procedure average(x : mas; var av : real);
implementation
    procedure average(x : mas; var av : real);
        var i : integer;
    begin
        av := 0;
        for i := 1 to n do av := av + x[i];
        av := av / n;
 end;
end.
Листинг 4.6. Пример оформления модуля

Список параметров подпрограммы в разделе реализации указывать не обязательно.

< Лекция 3 || Лекция 4: 1234 || Лекция 5 >
София Шишова
София Шишова

Я завершила экзамен 90 баллов на 5. Сертификат не заказала. Сейчас пытаюсь найти как его заказать. у меня указано экзамен пройден баллы оценка видно, а чтоб заказать сертификат нигде не видно.