Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции по программированию.doc
Скачиваний:
7
Добавлен:
17.04.2019
Размер:
1.6 Mб
Скачать

5.4. Описание процедур

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

Принципы модульного программирования

Целью МП является: возможность независимого написания и отладки отдель­ного модуля; возможность замены модуля без изменения всей программы; облег­чение тестирования (проверки) модулей программы.

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

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

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

Для модуля должны быть известны: алгоритм решения задачи; область допу­стимых входных значений; область воз­можных выходных значений.

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

На рис. 5.4 в виде блок-схемы приведен проект будущей программы, имеющей линейную структуру.

Эта программа должна обеспечить ввод с клавиатуры двух матриц А и В, осу­ществить их умножение, результатом которого является матрица С, и вывести мат­рицу С на экран монитора. Тело программы содержит вызовы трех подпрограмм MOD1, MOD2, MOD3, имеющих один вход и один выход.

В таком представлении (рис. 5.4) процесс разработки программы сводится к последовательному программированию модулей, если разработчик один, или сра­зу всех, если разработчика три. Предположим, что MOD2 и MOD3 разработаны, а MOD1 — нет. В этом случае вместо MOD1 ставят «заглушку», то есть модуль ими­тирующий процесс работы MOD1.

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

Структура и синтаксис процедуры

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

Исходные данные

Глобальные или локальные переменные

более высоких уровней

Результаты расчетов

Параметры процедуры (параметры значения)

Формальные параметры

Алгоритм процедуры

Формальные параметры

Параметры процедуры (параметры переменные)

Рис. 5.5. Схема процедуры

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

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

PROCEDURE < имя > [(< список формальных параметров >)]; { Заголовок }

< Разделы описаний > { Тело процедуры }

BEGIN

< Раздел операторов >

END;

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

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

Пример 51. Используя принцип модульного проектирования программ разрабо­тать программу вычисления произведения двух матриц С = А х В по формуле:

где Aj,k – элементы прямоугольной матрицы Amxp ; m – число строк матрицы Amxp ; р – число столбцов Amxp, и число строк матрицы Bpxn; Bk,j – компоненты матрицы Bpxn, n – число столбцов матрицы Bpxn; Сi,j – компоненты матрицы Cmxn, получае­мые в результате умножения.

PROGRAM PR51;

TYPE MAT = ARRAY [1..10, 1..10] OF REAL;

VAR AF, BF, CF: MAT; MF, NF, PF: INTEGER;

PROCEDURE MOD1(CH:CHAR; VAR M, N: INTEGER; VAR W: MAT);

VAR I, J: INTEGER;

BEGIN { Ввод матрицы W, размерностью M на N}

WRITELN('Введите размерность М и N матрицы ', СН);

READLN(M, N);

WRITELN('Введите матрицу', СН);

FOR I := 1 ТО М DO FOR J := 1 ТО N DO READ (W[I, J]);

END; {MODI }

PROCEDURE MOD2(M, P, N: INTEGER; A, B: MAT; VAR C: MAT);

VAR I, J, K: INTEGER;

BEGIN {Умножение матриц А и В}

FOR I := 1 TO M

DO FOR J:=l TON DO BEGIN

C[I,J]:=0;

FOR K:=1 TO P

DO C[I,J]:=C[I,J] + A[I,K]*B[K,J]

END

END; {MOD2}

PROCEDURE MOD3(CH: CHAR; M, N: INTEGER; W: MAT); VAR I. J: INTEGER;

BEGIN { Отображение матрицы W, размерностью M на N }

WRlTELN('Матрица', СН, ':');

FOR I:=1 TO M

DO BEGIN

FOR J := 1 TO N DO WRITE(W[I, J]: 10:5);

WRITELN

END

END; {MOD3}

BEGIN {Тело программы}

MOD1('A', MF, PF, AF); { Ввод матрицы А, размерностью MF на PF}

MOD1('B', PF, NF, BF); { Ввод матрицы В, размерностью PF нa NF}

MOD2(MF, PF, NF, AF, BF, CF); { Умножение матриц А и В }

MOD3('C', MF, NF, CF) { Отображение матрицы С, размерностью MF на NF}

END.

Спецификация процедуры

Процедура представляет собой программу в миниатюре, являясь в свою оче­редь частью основной программы или другой процедуры. Синтаксис процедуры полностью повторяет синтаксис программы. Отличие состоит только в заголовках. Заголовок процедуры всегда начинается ключевым словом PROCEDURE, а про­граммы — PROGRAM, которое, впрочем, писать необязательно. Процедуры могут быть простыми и маленькими (всего с десяток операторов), а могут быть очень слож­ными и большими (несколько сотен операторов). Процедуры могут содержать свои собственные процедуры и функции. Поэтому на процедуры, как и на программы, распространяется методология проектирования программных систем. Эта методо­логия предусматривает разработку спецификации на каждую программную еди­ницу, в том числе и на процедуру.

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

Построим спецификацию для процедуры MOD1 программы PR7 (см. пример 7).

Назначение процедуры. Ввод с клавиатуры двумерного массива размерностью MxN.

Описание потоков данных. Существуют специальные диаграммы Варнье-Орра для описания потоков данных, которые применяются в информационных системах. Однако наш пример достаточно прост, поэтому можно ограничится табличным описанием дан­ных, с которыми работает описываемая процедура. Эти данные сведены в табл. 1.1.

Таблица 5.1.

№ п/п

Иденти­фикатор

Данное

Тип переменной

Содержательный смысл

1

CH

Параметр-значение

CHAR

Наименование массива W: литера «А» или «В»

2

M

Параметр-переменная

INTEGER

Нижняя граница вводимого с клавиатуры массива W

3

N

Параметр-переменная

INTEGER

Верхняя граница вводимого с клавиатуры массива W

4

W

Параметр-переменная

ARRAY [1..10, 1..10] OF REAL

Значения элементов массива W

Напомним, что параметры-переменные в списке формальных параметров про­цедуры отличаются от параметров-значений наличием ключевого слова VAR, рас­положенного перед перечнем переменных. Переменные I и J являются локальны­ми для процедуры MOD1, поэтому в табл. 1.1 не представлены.

Алгоритм. Алгоритм подпрограммы достаточно прост и описан ниже с помо­щью структурограммы.

Структурограмма процедуры MOD1(CH, М, N, W)

Ввод размерности М, N массива СН; Ввод элементов массива W;

Для I от 1 до М с шагом 1 делать:

Для J от 1 до N с шагом 1 делать:

Ввести с клавиатуры значение элемента массива W[I, J];

Спецификации процедур MOD2 и MOD3 аналогичны процедуре MOD1. По­пробуйте составить их сами.

Размещение процедур и функций в оперативной памяти

В языке Паскаль используется два способа передачи параметров: по значению и ссылке (адресу переменной). Соответственно различают параметры-значения и параметры-переменные.

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

6

Р екурсивный стек

Динамически распределяемая область памяти

Верхняя граница памяти

5

Глобальные переменные

4

Библиотечные модули (встроенные процедуры и функции)

3

Константы и таблицы переходов операторов CASE

2

Код программы

Нижняя граница памяти

1

Префикс программного сегмента

Рис. 5.6. Карта распределения оперативной памяти

Префикс программного сегмента строится операционной системой при загруз­ке *.ЕХЕ модуля в оперативную память ЭВМ, представляет собой совокупность данных, важных для выполнения программы под управлением операционной системой. Остальная память выделяется для программы на время ее выполнения. Рекурсивный стек размещается в памяти непосредственно перед верхней грани­цей памяти и заполняется страницами по мере вызова процедур и функций при выполнении программы. Структура страницы представлена на рис. 5.7.

Предыдущая страница стека

С тек расширяется по направлению к младшим адресам памяти

5

Возвращаемое значение функции

4

Параметры

3

Указатель возврата

2

Локальные переменные

1

Указатели связи

Рис. 5.7. Структура страницы стека

Поле 5 присутствует только в странице, отводимой при вызове функции. В это поле записывается результат (значение) функции, которое будет возвращено в тело вызывающего программного модуля. Параметры (поле 4) — это значения перемен­ных, переданных в функцию или процедуру как параметры-значения. Для пара­метров-переменных здесь хранятся только адреса, а сами переменные находятся либо в поле 5 «Глобальные переменные», либо в поле 2 «Локальные переменные» одной из предыдущих страниц стека, если данная процедура (функция) была вызвана другой подпрограммой. Указатель возврата (адрес) обеспечивает выход из подпрограммы после ее завершения на оператор, следующий за операто­ром вызова подпрограммы. Если в подпрограмме используются переменные более высоких уровней вложения, то для связи с ними необходимо поле 1, содержащее адреса этих переменных.

Некоторые соображения по использованию подпрограмм

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

2. Величина параметра-значения хранится в странице стека только в процессе выполнения подпрограммы и стирается при ее завершении, а значение пара­метра-переменной хранится на более высоком уровне и меняется подпрограм­мой во время ее выполнения. Когда страница стека стирается, то уничтожается лишь адрес этой переменной, а значение сохраняется.

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

4. Динамическая организация выполнения подпрограмм делает возможным вы­зов подпрограммой самой себя с новыми значениями фактических параметров. Это называется рекурсией.

5. Вложенность описания подпрограмм не должна превышать 10. Это не отно­сится к рекурсиям, то есть вложенности при выполнении, которая ограничива­ется только физическими размерами поля ОЗУ, отводимого под стек.

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