4. Использование подпрограмм в Турбо Паскале.4.1.Структура
программы на языке Паскаль 4.1. Структура программы на языке Паскаль.Синтаксически программа на языке Паскаль делится на 2 части: заголовок и программный блок. Общий вид заголовка: PROGRAM <имя программы>[(<список файлов>)]; Заголовок программы может отсутствовать. Стандартные файлы INPUT (входной) и OUTPUT (выходной) также могут опускаться, т.к. принимаются по умолчанию. Блок программы состоит из следующих разделов:
Текст программы записывается произвольно в виде строк длиной не более 127 символов. В Турбо Паскале порядок следования разделов описаний произвольный и каждый из разделов может появляться произвольное число раз или отсутствовать. Раздел операторов - это выполняемая часть программы, состоящая из операторов, разделенных точкой с запятой. Начинается BEGIN и заканчивается END. Исполняемая часть программы всегда должна присутствовать и может быть единственной частью программы. Видом работы компилятора можно управлять директивами. Их включают в исходный текст в виде комментариев со специальным син-таксисом. Если описание процедуры или функции хранится в виде отдельного файла, то для включения их в исходный текст программы компилятору задается директива INCLUDE следующего вида: {$I <имя файла>}, которая должна быть помещена в разделе описаний процедур и функций.Например,
наверх4.2. Описание и вызов процедур.Для реализации многократно повторяющихся участков вычислений и для обеспечения модульности программ в языке Турбо Паскаль предусмотрена возможность использования процедур и функций. Процедура - это поименованное сложное действие, которое представляет собой совокупность операторов, вычисляющих некоторое число результатов в зависимости от некоторого числа аргументов. Процедура или функция (общее название - подпрограмма) определяется в разделе описаний основной программы или другой процедуры(функции). Процедура(функция) имеет ту же структуру, что и основная программа, т.е. состоит из заголовка, описательной части и выполняемой части. Синтаксис заголовка процедуры: PROCEDURE < имя процедуры > [( <список формальных параметров >)]; Например :PROCEDURE PR1 ( A,B,C : INTEGER; VAR S: REAL); Здесь PR1 - имя процедуры, а А,В,С,S - имена переменных, являющих-ся параметрами. В отличие от основной программы заголовок в процедуре обязателен, но завершается процедура не точкой, а точкой с запятой. Описание процедуры выполняется с формальными параметрами. Оператор процедуры служит для вызова процедуры из основной программы или из другой процедуры(функции). Вызов осуществляется в следующей форме: <имя процедуры > [(<список фактических параметров>)]; Таким образом, для приведенного заголовка процедуры можно написать такой оператор вызова: PR1 (A,B,C,S); Формат списка параметров в заголовке процедуры и при вызове процедуры отличаются. При вызове переменные, константы или выражения следуют через запятую, а в заголовке запись переменных напоминает объявление переменных в разделе описания переменных. Для всех элементов списка должен быть указан тип данных. Несколько переменных, отнесенных к одному типу , пишутся через запятую, а группы переменных различного типа отделяются точкой с запятой. После обращения к процедуре управление передается на выполнение следующего за вызовом процедуры оператора. наверх4.3. Описание функции.Функция предназначена для вычисления какого-либо одного значения и используется в выражениях аналогично стандартным функци-ям. Синтаксис заголовка функции: FUNCTION < имя функции >[(<список формальных параметров>)]: <тип результата>; Например:FUNCTION PRF (A,B,C: INTEGER) : REAL; Отличие описания функции от процедуры:
Для вызова функции используется указатель функции (имя функции со списком фактических параметров), который обязательно должен входить в какое-либо выражение (в правой части оператора присваивания, в операторе вывода, в условном операторе и т.д.). Для приведенного заголовка функции вызов функции может быть одним из следующих вариантов:
наверх4.4. Формальные и фактические параметры.При описании процедуры (функции) в ее заголовке могут быть указаны параметры следующих видов:
При записи параметров необходимо помнить:
При передаче в подпрограмму массива его тип объявляют предва-рительно в разделе описания типов TYPE. Например.
Здесь описаны два типа массивов. TV - для одномерного массива и TM для двумерного массива. Затем в списке формальных параметров для переменных А и В используются эти ранее определенные типы при описании соответственно матрицы и вектора. Список параметров, задаваемых в заголовке процедуры или функции обеспечивает связь подпрограммы с вызывающей программой. Через него в подпрограмму передаются исходные данные и возвращается результат (в процедуре). В языке Турбо Паскаль предусмотрены два принципиально отличающихся механизма передачи параметров : по значению и по ссылке. Параметры-значения.При передаче параметров по значению в стеке, в котором осуществляется выделение памяти под внутренние (локальные) переменные подпрограммы, выделяется дополнительная память, в которую копируются значения соответствующих фактических параметров. В вызывающей программе в качестве аргумента подпрограммы для параметра-значения может использоваться не только переменная, но и выражение. После завершения работы подпрограммы выделенная этим параметрам память становится недоступной, поэтому передача параметров по значению не может использоваться в подпрограммах для получения результатов. Параметры-переменные.При вызове по ссылке в подпрограмме память под передаваемые переменные не отводится. В подпрограмму передается не значение переменной, а ссылка на место в памяти соответствующего фактического параметра. Подпрограмма, выполняющая некоторые действия с этой переменной, в действительности производит действия с соответствующим фактическим параметром, поэтому после выполнения процедуры , изменения, выполненные над этой переменной, сохраняются. Перед записью параметров-переменных в списке формальных параметров указывается ключевое слово VAR (действует до " ; "). Для вычисляемых результатов могут быть использованы только параметры-переменные. Формальным параметрам-переменным не могут соответствовать в качестве фактических значений константы или выражения ,так как они не имеют адреса для передачи. В качестве параметров-переменных могут быть использованы массивы и строки открытого типа, у которых не задаются размеры. Открытый массив представляет собой формальный параметр подпрограммы, описывающий базовый тип элементов, но не определяющий его размерность и границы. Индексация элементов в этом случае начинается с нуля. Верхняя граница открытого массива возвращается функцией HIGH . Такое описание возможно только для одномерных массивов. Для открытого массива в стеке создается его копия, что может вызвать переполнение стека. Рассмотрим пример использования открытого массива. Пусть требуется подсчитать сумму элементов одномерного массива. FUNCTION SUM (VAR A: ARRAY OF INTEGER):INTEGER;
В основной программе такой массив может быть описан даже как Var A: array [ -2 .. 3] of integer; Фактические границы массива здесь значения не имеют. Важно только то, что количество элементов массива в данном случае равно 6. Открытая строка может задаваться с помощью стандартного типа OPENSTRING и стандартного типа STRING с использованием дирек-тивы компилятора {$P+}. Например, PROCEDURE ZAP ( VAR ST : OPENSTRING; R: INTEGER ); {$P+} PROCEDURE ZAP ( VAR ST : STRING; R: INTEGER ); В языке Турбо Паскаль можно устанавливать режим компиляции, при котором отключается контроль за совпадением длины формального и фактического параметра строки {$V- }. При передаче строки меньшего размера формальный параметр будет иметь ту же длину, что и параметр обращения; при передаче строки большего размера происходит усечение до максимального размера формального параметра. Контроль включает-ся только при передаче параметров-переменных , для параметров - значений длина не контролируется. Рассмотрим пример, в котором используются процедура и функция. Требуется написать процедуру, в которой для матрицы, содержащей M столбцов и N строк, необходимо составить вектор номеров столбцов, все элементы которых упорядочены по возрастанию или убы-ванию и являются простыми числами. В главной программе вводятся все входные данные, производится обращение к процедуре и осуществляетcя вывод полученных результатов.
В этом примере в процедуру передаются входные данные: двумерный массив и его размерность. Массив передается как параметр-переменная, чтобы в процедуре не выделялась память для его копии. Результаты: вектор и его размерность обязательно передаются как параметры-переменные. Функция проверки простого числа является внутренней для процедуры и недоступна из главной программы. Параметры-константы.Так как аргументы, передаваемые в процедуру или функцию , размещаются в стеке, то в случае передачи значением массива большого размера, может произойти переполнение стека. В языке Турбо Паскаль 7.0 введен описатель CONST, который может задаваться для формальных параметров подпрограмм. Аргумент, соответствующий такому параметру, передается по ссылке, подобно параметру с описателем Var, но в самой процедуре(функции) запрещается присваивать этому аргументу новое значение. PROCEDURE <имя процедуры> (CONST <имя константы>: <тип>; ...); FUNCTION <имя функции> (CONST <имя константы> : <тип> ; ...): <тип результата> ; Параметр-константу нельзя передавать в качестве параметра в другую подпрограмму. Параметры-процедуры и параметры-функции.Для объявления процедурного типа используется заголовок подпрограммы , в котором опускается имя процедуры(функции). Например:
Ниже приведен пример использования функции FF в качестве параметра другой функции RR.
В этом примере используются :
наверх4.5. Область действия имен.Любая подпрограмма представляет собой блок со своей областью описаний. Она может содержать внутри этого блока описания других процедур и функций , а также ращения к ним. Объекты, описанные внутри какого-либо блока, являются по отношению к нему локальными и не доступны внешним блокам. На них можно ссылаться только внутри блока, в котором они описаны. Под объектами понимаются име-на констант, типов, переменных, процедур, функций. Объекты, описанные во внешних блоках и не описанные во внутренних, являются глобальными по отношению к внутренним и доступны как во внешних блоках , так и во внутренних. При совпадении имен глобальных и локальных переменных, локальные переменные отменяют действия глобальных в пределах области своего действия. На рисунке схематично представлены области действия отдельных идентификаторов: Y - локальная переменная по отношению к блоку 4, недоступна в блоках 1,2,3. K, L - локальная переменная для блока 2, недоступна в блоках 1,3,4. C - глобальная переменная по отношению к блоку 3, недоступна в блоках 1 и 2. B, D- глобальные переменные для блоков 2,3,4.Доступны в блоках 1,2,3,4. T - общий тип Идентификатор А обозначает две разные переменные : А - областью действия которой являются блоки 1 и 2, и переменная А' - область действия которой блоки 3 и 4 . То же самое с именем Х: одна переменная Х - с областью действия 1,2 и 3 блоки и переменная Х', которая действует только в блоке 4. Если подпрограмма имеет параметры, то идентификаторы из списка формальных параметров являются локальными для этой процедуры(функции) и глобальными для каждой подпрограммы в ней (если таковые имеются) . наверх4.6. Процедуры и функции без параметров.В случае использования процедур и функций без параметров связь данных осуществляется через глобальные переменные. Подпрограммы должны быть, по возможности, независимы от основной программы, поэтому все переменные , нужные только в пределах подпрограммы, должны описываться как локальные. Связь основной программы с процедурой или функцией должна осуществляться, как правило, через список параметров, что придает подпрограммам необходимую гибкость. Вместе с тем, слишком большое число параметров замедляет работу программы, поэтому переменные заведомо общие в основной программе и подпрограммах целесообразно использовать как глобальные. наверх4.7. Рекурсивные процедуры и функции.Рекурсия - это способ организации вычислительного процесса, при котором процедура или функция в процессе выполнения входящих в ее состав операторов обращается сама к себе непосредственно, либо через другие процедуры и функции. Рекурсия может быть прямой или косвенной. При прямой рекурсии оператор вызова подпрограммы содержится непосредственно в ее исполняемой части. Любую рекурсивную процедуру (функцию) можно сделать не рекурсивной. Рекурсивное описание обычно короче и нагляд-нее, но требует больших затрат машинного времени (за счет повторных обращений) и памяти машины (за счет дублирования переменных) . Рекурсивная подпрограмма однократно вызывается извне. Условие полного окончания работы рекурсивной процедуры или функции должно находиться в ней самой. Рассмотрим пример. Вычислить значение F=M! Рекурсивное определение значение факториала можно записать следующим образом:
a) Рекурсивная функция
B варианте а) при м=4 выполняются
следующие действия:
При входе в функцию в первый раз отводится память под локальную переменную, соответствующую параметру-значению; ей присваивается значение фактического параметра (М). При каждом новом обращении строятся новые локальные переменные. Так как FACT(1)=1, то выполнение функции заканчивается. После этого выполняются действия:
наверх4.8. Предварительно-определенные процедуры.При косвенной рекурсии одна подпрограмма вызывает другую, которая либо сама, либо посредством других подпрограмм вызывает исходную. В этом случае используется предварительное описание процедур (функций), так как в языке Турбо Паскаль все процедуры и функции должны быть описаны до их вызова. В этом случае отдельно от текста процедуры (функции) записывается ее заголовок и к нему после символа ";" добавляется ключевое слово FORWARD. Сам текст подпрограммы начинается урезанным заголовком, в котором задается только ее имя, а список параметров (и тип результата для функции ) отсутствует. Например:
В этом примере одна процедура вызывает другую, а вторая вызывает первую. При такой схеме взаимодействия процедур невозможно описать обе процедуры так, чтобы обращение к ним следовало после описания, как требует Паскаль. Для разрешения противоречия используется предварительное описание одной из процедур. наверх4.9. Модули.Процедуры и функции могут быть сгруппированы в отдельный модуль. Модуль (unit)- это программная единица, текст которой компилируется автономно (независимо от главной программы). Если модуль откомпилирован для реального режима, то результат имеет расширение TPU; модули, откомпилированные для защищенного режима, имеют расширение TPP. Структура модуля отличается от структуры обычной программы на языке Турбо Паскаль. Модули имеют четыре основные части: заголовок, который следует за зарезервированным словом UNIT; описательную (интерфейсную) часть, которая начинается за зарезервированным словом INTERFACE (в ней помещаются объявления переменных, процедур, функций, констант и типов данных, которые должны быть доступны для других программных модулей, использующих данный модуль); исполнительную (внутреннюю) часть, которая начинается словом IMPLEMENTATION (в нее входит текст подпрограмм и локальные объекты, доступные только внутри данного модуля) и необязательную часть (секцию инициализации), расположенную после исполнительной части между словами BEGIN и END (при этом, если инициализация модуля не нужна, то в секции помещается лишь слово END). При описании подпрограмм модуля допустимо использовать сокращенные заголовки (без параметров и указания типа результата для функции) как, например, в случае использования директивы FORWARD. Начинается модуль заголовком, состоящим из зарезервированного слова UNIT и имени модуля. Имя модуля обязательно должно совпадать с именем файла (имеющим расширение PAS), в котором он находится. Модуль имеет следующую структуру:
Интерфейсная и реализационная части могут быть пустыми, но присутствовать должны обязательно. При подключении модуля вначале выполняются операторы секции инициализации (если они имеются), а затем операторы основного блока главной программы, в которую включен данный модуль. Рассмотрим пример. Требуется написать главную программу, в которой вводится размерность вектора и элементы вектора и вызывается процедура сортировки одномерного массива целых чисел в порядке возрастания. Длина массива не превышает 100. Процедуру оформить в виде модуля.
Первым предложением программы является Uses, в котором подключается стандартный модуль и модуль Modsort, в котором и находится процедура сортировки. Кроме того тип, с которым описывается массив отсутствует в главной программе, т.к. он присутствует в модуле.
В интерфейсной части модуля описан тип mas и заголовок процедуры сортировки. Поэтому при подключении этого модуля с помощью предложения Uses в любой программе становятся доступны и этот тип и процедура, что и продемонстрировано в главной программе. наверхк следующей главе |