Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Программирование на языке высокого уровня Паскаль. Учебное пособие для СПО

.pdf
Скачиваний:
0
Добавлен:
07.09.2026
Размер:
1 Мб
Скачать
☆
данные в подпрограмму передавать по адресу не рекомендуется, чтобы исключить возможность их непреднамеренного изменения.
Проиллюстрируем передачу параметров-значений и параметров­переменных на примере (пример 4.3).
var a, b, c, d, e : word; procedure X(a, b, c : word; var d : word); var e : word; begin c := a + b; d := c; e := c; writeln ('Значения переменных в подпрограмме:'); writeln ('c = ', c, ' d = ', d, ' e = ', e); end; begin a := 3; b := 5; x(a, b, c, d); writeln ('Значения переменных в главной программе:'); writeln ('c = ', c, ' d = ', d, ' e = ', e); end.
Листинг 4.3. Параметры-значения и параметры-переменные
Результаты работы этой программы приведены ниже.
Значения переменных в подпрограмме: c = 8 d = 8 e = 8 Значения переменных в главной программе: c = 0 d = 8 e = 0
Как видите, значение переменной с в главной программе не изменилось, поскольку переменная передавалась по значению, а значение переменной е не изменилось потому, что в подпрограмме была описана локальная переменная с тем же именем.
Параметры-константы
Параметр-константу можно узнать по ключевому слову const перед описанием параметра. Оно говорит о том, что в пределах
Программирование на я зыке высокого уровня ПаскальТ.А. Павловская
81
подпрограммы данный параметр изменить невозможно:
const имя : тип;
При вызове подпрограммы на месте параметра-константы, как и в случае параметра-значения, может быть записано выражение, тип которого совместим по присваиванию с типом параметра. Однако компилятор при передаче параметров-констант формирует более эффективный код, чем для параметров-значений. Фактически параметры-константы передаются по адресу, но доступ к ним обеспечивается только для чтения. Поэтому опасность переполнения стека и затраты, связанные с копированием и размещением параметров, исключаются.
Например, параметр-константа целого типа в процедуре Р записывается так:
procedure P(const x : integer);
Подведем итоги. Если данные передаются в подпрограмму по значению, их можно изменять, но эти изменения затронут только копию в области параметров и не отразятся на значении аргумента в вызывающей программе. Если данные передаются как параметры­константы, изменять их в подпрограмме нельзя. Следовательно, эти два способа передачи должны использоваться для передачи в подпрограмму исходных данных.
Параметры составных типов (массивы, записи, строки) предпочтительнее передавать как константы, потому что при этом не расходуется время на копирование и место в стеке (размер стека не может превышать 64 Кбайт, а по умолчанию устанавливается равным 16 Кбайт).
Результаты работы процедуры следует передавать через параметры­переменные, результат функции — через ее имя.
СОВЕТ В списке параметров записывайте сначала все входные параметры, затем — все выходные. Давайте параметрам имена, по которым можно получить представление об их назначении.
Программирование на я зыке высокого уровня ПаскальТ.А. Павловская
82
Открытые массивы и строки
Чтобы можно было передавать в подпрограмму массивы с различным количеством элементов, в списке ее параметров разрешается определять открытый массив, например:
procedure P(a : array of real);
Он может быть только одномерным и состоять из элементов любого типа, кроме файлового. На место открытого массива можно передавать одномерный массив любой размерности, состоящий из элементов такого же типа. Передавать открытый массив можно как значение, переменную или константу.
Его элементы нумеруются с нуля. Номер максимального элемента в массиве можно определить с помощью функции High.. Рассмотрите пример (пример 4.4).
function max_el(const mas : array of integer) : integer; var i, max : integer; begin max := mas[0]; for i := 0 to High(mas) do if mas[i] > max then max := mas[i]; max_el := max; end;
Листинг 4.4. Максимальный элемент любого целочисленного массива
Для передачи в подпрограмму по адресу строк любой длины используется либо специальный тип OpenString, называемый открытой строкой, либо тип string при включенном режиме {$P+} (по умолчанию этот режим выключен).
Напомню, что если параметр передается в подпрограмму как значение или константа, от него не требуется точного совпадения с типом аргумента — достаточно соответствия по присваиванию. Поскольку присваивать друг другу строки разной длины можно, их можно
Программирование на я зыке высокого уровня ПаскальТ.А. Павловская
83
использовать и в качестве параметров, то есть на место параметра­значения или параметра-константы типа string можно передавать
строку любой длины без использования открытых строк.
Пример передачи строк в подпрограмму:
type s20 = string[20]; var s1 : string[40]; s2 : string[10]; procedure P(const x : s20; y : string; var z : openstring); ... begin ... P(s2, s1, s1); ... end.
Параметры процедурного типа
Все рассмотренные параметры подпрограмм позволяли выполнять один и тот же алгоритм с различными данными. В Паскале есть и другая возможность — параметризовать алгоритм функциями и процедурами. Это может пригодиться, если требуется выполнить одну и ту же последовательность действий, внутри которой выполняется обращение к разным функциям или процедурам.
Описание параметра подпрограммы в большинстве случаев состоит из имени и типа. Имя функции является константой процедурного ( функционального ) типа, который требуется описать в разделе type, например:
type fun = function(x : real) : real; pr = procedure; proc = procedure(a, b : word; var c : word);
Здесь вводится описание трех типов. Первый из них соответствует любой функции с одним аргументом вещественного типа, возвращающей вещественное значение, второй — процедуре без параметров, а третий — процедуре с тремя параметрами типа word. Как видно из примеров, описание процедурного (функционального)
Программирование на я зыке высокого уровня ПаскальТ.А. Павловская
84
типа соответствует заголовку подпрограммы без имени. Имя типа используется затем в списке параметров подпрограммы аналогично другим типам.
Пример. Программа, вычисляющая определенные интегралы методом прямоугольников для двух функций
на интервале [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);
Программирование на я зыке высокого уровня ПаскальТ.А. Павловская
85
writeln(' Интеграл для второй функции: ', integr(R, a, b, n):8:3); end.
Листинг 4.5. Вычисление определенного интеграла методом прямоугольников
Вычисление определенного интеграла методом прямоугольников состоит в приближенном подсчете площади, ограниченной осью абсцисс, графиком функции и границами интервала. Интервал разбивается на заданное количество промежутков, и площади получившихся фигур заменяются площадями прямоугольников.
Итак, чтобы передать имя функции или процедуры в подпрограмму, необходимо:
1. Определить соответствующий процедурный тип.
2. Задать для функций и процедур, предназначенных для передачи в подпрограмму, ключ компилятора {$F +}, определяющий дальнюю адресацию. При этом компилятор формирует полный адрес, состоящий из сегмента и смещения. Альтернативный способ — указать в заголовке каждой функции директиву far:
function Q(x : real) : real; far;
Рекурсивные подпрограммы
Рекурсивной называется подпрограмма, в которой содержится обращение к самой себе. Такая рекурсия называется прямой. Есть также косвенная рекурсия, когда две или более подпрограмм вызывают друг друга.
При обращении подпрограммы к самой себе происходит то же самое, что и при обращении к любой другой функции или процедуре: в стек записывается адрес возврата, резервируется место под локальные переменные, происходит передача параметров, после чего управление передается первому исполняемому оператору подпрограммы. При повторном вызове этот процесс повторяется. Для завершения вычислений каждая рекурсивная подпрограмма должна содержать хотя
Программирование на я зыке высокого уровня ПаскальТ.А. Павловская
86
бы одну нерекурсивную ветвь, заканчивающуюся возвратом в вызывающую программу.
При завершении подпрограммы область ее локальных переменных освобождается, а управление передается на оператор, следующий за рекурсивным вызовом.
Простой пример рекурсивной функции — вычисление факториала (это не означает, что факториал следует вычислять именно так). Чтобы получить факториал числа 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 для работы с экраном в графическом режиме. Модули применяются как библиотеки, которые могут использоваться различными программами, и для разбиения сложной программы на составные части.
Программирование на я зыке высокого уровня ПаскальТ.А. Павловская
87
Чтобы использовать модуль, достаточно знать только его интерфейс: детали реализации модуля скрыты от его пользователя. Это позволяет успешно создавать программы большого объема, поскольку мозг человека может хранить одновременно довольно ограниченный объем информации. Кроме того, использование модулей позволяет преодолеть ограничение в один сегмент на объем кода исполняемой программы, поскольку код каждого подключаемого к программе модуля содержится в отдельном сегменте.
Модули можно разделить на стандартные, которые входят в состав системы программирования, и пользовательские, то есть создаваемые программистом. Чтобы подключить модуль к программе, его требуется предварительно скомпилировать. Результат компиляции каждого модуля хранится на диске в отдельном файле с расширением .tpu.
Описание модулей
Исходный текст каждого модуля хранится в отдельном файле с расширением .pas. Модуль состоит из секций (разделов). Общая структура модуля:
unit имя; { заголовок модуля } interface { ------------- интерфейсная секция модуля } { описание глобальных элементов модуля (видимых извне) } implementation { --------------- секция реализации модуля } { описание локальных (внутренних) элементов модуля } begin { ------------------- секция инициализации } { может отсутствовать } end.
ВНИМАНИЕ Имя файла, в котором хранится модуль, должно совпадать с именем, заданным после ключевого слова unit.
Модуль может использовать другие модули, для этого их надо перечислить в операторе uses, который может находиться только непосредственно после ключевых слов interface или
implementation. Если модули подключаются к интерфейсной части,
все константы и типы данных, описанные в интерфейсной секции этих
Программирование на я зыке высокого уровня ПаскальТ.А. Павловская
88
модулей, могут использоваться в любом описании в интерфейсной части данного модуля. Если модули подключаются к части реализации, все описания из этих модулей могут использоваться только в секции реализации.
В интерфейсной секции модуля определяют константы, типы данных, переменные, а также заголовки процедур и функций. Полностью же подпрограммы описываются в секции реализации, скрытой от пользователя модуля. Это естественно, поскольку для применения подпрограммы требуется знать только информацию, которая содержится в ее заголовке.
В секции реализации описываются подпрограммы, заголовки которых приведены в интерфейсной части. Заголовок подпрограммы должен или быть идентичным указанному в секции интерфейса, или состоять только из ключевого слова procedure или function и имени подпрограммы. Для функции также указывается ее тип.
Кроме того, в этой секции можно определять константы, типы данных, переменные и внутренние подпрограммы. Они используются внешними элементами модуля и видны только в секции реализации.
Секция инициализации предназначена для присваивания начальных значений переменным, используемым в модуле или в программе, к которой он подключен. Операторы, расположенные в секции инициализации модуля, выполняются перед операторами основной программы. Если к программе подключено более одного модуля, их секции инициализации вызываются на выполнение в порядке, указанном в операторе uses.
В оболочках Borland Pascal и Turbo Pascal результат компиляции по умолчанию размещается в оперативной памяти и на диск не записывается. Поэтому для сохранения скомпилированного модуля на диске требуется установить значение пункта Compile ( Destination в значение Disk. Компилятор создаст файл с расширением .tpu, который надо переместить в специальный каталог, путь к которому указан в пункте меню Options ( Directories в поле Unit Directories.
В качестве примера оформим в виде модуля подпрограмму вычисления среднего арифметического значения элементов массива из пример 4.1
Программирование на я зыке высокого уровня ПаскальТ.А. Павловская
89
(пример 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. Пример оформления модуля
Список параметров подпрограммы в разделе реализации указывать не обязательно.
Использование модулей
Чтобы использовать в программе величины, описанные в интерфейсной части модуля, имя модуля следует указать в разделе
uses. Можно записать несколько имен модулей через запятую,
например:
program example; uses Average, Graph, Crt;
После этого все описания, расположенные в интерфейсных секциях модулей, становятся известными в программе, и ими можно пользоваться точно так же, как и величинами, определенными в ней непосредственно. Поиск модулей выполняется сначала в библиотеке исполняющей системы, затем в текущем каталоге, а после этого — в каталогах, заданных в диалоговом окне Options ( Directories.
Программирование на я зыке высокого уровня ПаскальТ.А. Павловская
90
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]