4. Использование подпрограмм в Турбо Паскале.

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

4.3.
Описание функции

4.4.
Формальные и фактические параметры

4.5.
Область действия имен

4.6.
Процедуры  и функции  без параметров

4.7.
Рекурсивные процедуры и функции

4.8.
Предварительно-определенные процедуры

4.9.
Модули


4.1. Структура программы на языке Паскаль.

Синтаксически программа на языке Паскаль делится на 2 части: заголовок и программный блок.

Общий вид заголовка:

PROGRAM <имя программы>[(<список файлов>)];

Заголовок программы может отсутствовать. Стандартные файлы INPUT (входной) и OUTPUT (выходной) также могут опускаться, т.к. принимаются по умолчанию.

Блок программы состоит из следующих разделов:

LABEL <описание меток>; - раздел описания меток
CONST <описание констант>; - раздел описания констант
TYPE <описание типов>; - раздел описания типов
VAR <описание переменных>; - раздел описания переменных
PROCEDURE <описание процедуры>; - раздел описания
FUNCTION <описание функции>; процедур и функций

BEGIN

<исполнительная часть программы> - раздел операторов

END.

Текст программы записывается произвольно в виде строк длиной не более 127 символов. В Турбо Паскале порядок следования разделов описаний произвольный и каждый из разделов может появляться произвольное число раз или отсутствовать. Раздел операторов - это выполняемая часть программы, состоящая из операторов, разделенных точкой с запятой. Начинается BEGIN и заканчивается END. Исполняемая часть программы всегда должна присутствовать и может быть единственной частью программы.

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

{$I <имя файла>},

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

Например,

PROGRAM A1;
VAR ...
{$I B1.PAS}
BEGIN
...
END.
Файл B1.PAS может иметь вид:
PROCEDURE PP;
VAR ...
BEGIN
...
END;

наверх

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;

Отличие описания функции от процедуры:

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

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

S:=PRF ( A,B,C);
Writeln ( PRF ( A,B,C));
If PRF ( A,B,C)>20 then K=K+1;

наверх

4.4. Формальные и фактические параметры.

При описании процедуры (функции) в ее заголовке могут быть указаны параметры следующих видов:

  • параметры-значения;
  • параметры-переменные;
  • параметры-константы;
  • параметры-процедуры;
  • параметры-функции.

При записи параметров необходимо помнить:

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

При передаче в подпрограмму массива его тип объявляют предва-рительно в разделе описания типов TYPE. Например.
TYPE TV=ARRAY [1..30] OF INTEGER;
TM=ARRAY [1..20,1..20] OF REAL;
...
PROCEDURE TOP ( A:TM; VAR B: TV ; N: INTEGER);
...

Здесь описаны два типа массивов. TV - для одномерного массива и TM для двумерного массива. Затем в списке формальных параметров для переменных А и В используются эти ранее определенные типы при описании соответственно матрицы и вектора.

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

Параметры-значения.

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

Параметры-переменные.

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

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

Рассмотрим пример использования открытого массива. Пусть требуется подсчитать сумму элементов одномерного массива.

FUNCTION SUM (VAR A: ARRAY OF INTEGER):INTEGER;
VAR S,I : INTEGER;
BEGIN
S:=0;
FOR I:=0 TO HIGH(A) DO
S:=S+A[I];
SUM:=S;
END;

В основной программе такой массив может быть описан даже как 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я вывод полученных результатов.

USES CRT;
TYPE TMAS=ARRAY[1..100,1..100] OF WORD;
TVECT=ARRAY[1..100] OF WORD;
VAR A:TMAS;
V:TVECT;
N,M,K:BYTE;
I,J:BYTE;

PROCEDURE FORM(VAR X:TMAS;) {матрица}
N,M:BYTE; {количество строк и столбцов}
VAR R:TVECT; {результат - вектор}
VAR K:BYTE); {длина полученного вектора}

VAR I,J,Z,S:BYTE;
F:BOOLEAN;

FUNCTION PROS(B:WORD):BOOLEAN;
{функция проверки простого числа}
VAR I:WORD;
BEGIN
IF B<>1 THEN PROS:=TRUE
ELSE PROS:=FALSE;
FOR I:=2 TO B DIV 2 DO
IF B MOD I = 0 THEN PROS:=FALSE;

END;
BEGIN
K:=0;
FOR J:=1 TO M DO
BEGIN
Z:=0;
S:=0;
F:=TRUE;
FOR I:=1 TO N-1 DO
BEGIN
IF X[I,J]>X[I+1,J] THEN Z:=Z+1;
IF X[I,J]< X[I+1,J] THEN S:=S+1
END;
IF (Z = N-1) OR (S = N-1) THEN
BEGIN
FOR I:=1 TO N DO
IF NOT(PROS(X[I,J])) THEN F:=FALSE;
IF F THEN
BEGIN
K:=K+1; R[K]:=J
END;
END;
END;
END;
BEGIN
WRITELN('Введите N и M:');
READLN(N,M);
WRITELN('Введите матрицу:');
FOR I:=1 TO N DO
FOR J:=1 TO M DO
READLN(A[I,J]);
FORM(A,N,M,V,K);
WRITELN('Результат:');
FOR I:=1 TO K DO
WRITE(V[I],' ');
READKEY
END.

В этом примере в процедуру передаются входные данные: двумерный массив и его размерность. Массив передается как параметр-переменная, чтобы в процедуре не выделялась память для его копии. Результаты: вектор и его размерность обязательно передаются как параметры-переменные. Функция проверки простого числа является внутренней для процедуры и недоступна из главной программы.

Параметры-константы.

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

PROCEDURE <имя процедуры> (CONST <имя константы>: <тип>; ...);

FUNCTION <имя функции> (CONST <имя константы> : <тип> ; ...): <тип результата> ;

Параметр-константу нельзя передавать в качестве параметра в другую подпрограмму.

Параметры-процедуры и параметры-функции.

Для объявления процедурного типа используется заголовок подпрограммы , в котором опускается имя процедуры(функции).

Например:

TYPE
TPR1= PROCEDURE( X,Y : REAL; VAR Z : REAL);
TPR2= PROCEDURE ;
TF1= FUNCTION: STRING;
TF2=FUNCTION ( VAR S: STRING) : REAL;

Ниже приведен пример использования функции FF в качестве параметра другой функции RR.
USES CRT;
TYPE FUN=FUNCTION (X,Y: REAL): REAL;
VAR ...
FUNCTION FF (X,Y: REAL): REAL; FAR;
...
BEGIN
...
END;
FUNCTION RR (X,Y: REAL; F : FUN): REAL; FAR;
...
BEGIN
...
END;
PROCEDURE TP (VAR Z : REAL; X,Y: REAL; CONST R: INTEGER);
...
BEGIN
...
END ;
BEGIN
...
Z:=RR(3 , 1 , FF);
TP (Z,X,Y,R);
...
END.

В этом примере используются :

  • X,Y - параметры-значения;

  • Z- параметр-переменная;

  • F- параметр-функция;

  • R- параметр-константа.

наверх

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! Рекурсивное определение значение факториала можно записать следующим образом:

при М=1 F=1
при М> 1 F= M!= M*(M-1)!, т.е. М! определяется через (М-1)!

a) Рекурсивная функция

PROGRAM MAIN;
VAR M: INTEGER;
F:REAL;
FUNCTION FACT (N:INTEGER): REAL;
BEGIN
IF N=1 THEN
FACT:=1
ELSE
FACT:= N* FACT(N-1);
END;
BEGIN
READLN(M);
F:= FACT ( M );
WRITELN (' M!=', F);
END.
b) Рекурсивная процедура

PROGRAM MAIN;
VAR M: INTEGER;
F:REAL;
PROCEDURE FACT(N:INTEGER; VAR F: REAL);
VAR Q : REAL;
BEGIN
IF N=1 THEN Q:=1
ELSE FACT(N-1,Q);
F:=N*Q;
END;
BEGIN
READLN(M);
FACT ( M, F );
WRITELN (' M!=', F);
END.

B варианте а) при м=4 выполняются следующие действия:

FACT:=4*FACT(3); FACT:=3*FACT(2); FACT:=2*FACT(1); FACT(1):=1.

При входе в функцию в первый раз отводится память под локальную переменную, соответствующую параметру-значению; ей присваивается значение фактического параметра (М). При каждом новом обращении строятся новые локальные переменные. Так как FACT(1)=1, то выполнение функции заканчивается. После этого выполняются действия:

FACT(1):=1; FACT:=2*FACT(1);
FACT(2):=2; FACT:=3*FACT(2);
FACT(3):=3*2=6; FACT:=4*FACT(3); т.е. FACT=24

наверх

4.8. Предварительно-определенные процедуры.

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

Например:

PROGRAM KOSV_R;
VAR X,Y: INTEGER;
PROCEDURE LR ( A : INTEGER); FORWARD;
PROCEDURE TT (B: INTEGER);
...
BEGIN
...
LR (...);
END;
PROCEDURE LR ;
...
BEGIN
...
TT(...) ;
...
END;
BEGIN
...
TT( X) ;
LR(Y);
...
END.

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

наверх

4.9. Модули.

Процедуры и функции могут быть сгруппированы в отдельный модуль. Модуль (unit)- это программная единица, текст которой компилируется автономно (независимо от главной программы). Если модуль откомпилирован для реального режима, то результат имеет расширение TPU; модули, откомпилированные для защищенного режима, имеют расширение TPP. Структура модуля отличается от структуры обычной программы на языке Турбо Паскаль. Модули имеют четыре основные части: заголовок, который следует за зарезервированным словом UNIT; описательную (интерфейсную) часть, которая начинается за зарезервированным словом INTERFACE (в ней помещаются объявления переменных, процедур, функций, констант и типов данных, которые должны быть доступны для других программных модулей, использующих данный модуль); исполнительную (внутреннюю) часть, которая начинается словом IMPLEMENTATION (в нее входит текст подпрограмм и локальные объекты, доступные только внутри данного модуля) и необязательную часть (секцию инициализации), расположенную после исполнительной части между словами BEGIN и END (при этом, если инициализация модуля не нужна, то в секции помещается лишь слово END). При описании подпрограмм модуля допустимо использовать сокращенные заголовки (без параметров и указания типа результата для функции) как, например, в случае использования директивы FORWARD. Начинается модуль заголовком, состоящим из зарезервированного слова UNIT и имени модуля. Имя модуля обязательно должно совпадать с именем файла (имеющим расширение PAS), в котором он находится. Модуль имеет следующую структуру:

UNIT <имя модуля>;
INTERFACE
USES <список подключаемых модулей>;
TYPE <описание типов, определенных в данном модуле и доступных для других модулей>;

CONST <описание констант, определенных в данном модуле и доступных для других модулей >;

VAR <описание переменных, определенных в данном модуле и доступных для других модулей >;

PROCEDURE <заголовки процедур, определенных в данном модуле и доступных для других модулей >;

FUNCTION <заголовки функций, определенных в данном модуле и доступных для других модулей >;

IMPLEMENTATION

USES <список подключаемых модулей>;

TYPE <описание типов, определенных в данном модуле и недоступных для других модулей>;

CONST <описание констант, определенных в данном модуле и недоступных для других модулей >;

VAR <описание переменных, определенных в данном модуле и недоступных для других модулей >;

PROCEDURE <реализация процедур, определенных в данном модуле и доступных для других модулей >;

FUNCTION <реализация функций, определенных в данном модуле и доступных для других модулей >;

PROCEDURE <заголовки и реализация процедур, определенны в данном модуле и недоступных для других модулей >;

FUNCTION <заголовки и реализация функций, определенных в данном модуле и недоступных для других модулей >;

BEGIN< это слово необходимо, если имеются операторы секции инициализации>

<Необязательная часть модуля>

END.

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

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

USES CRT,MODSORT;
VAR A:MAS;
I:BYTE;
N:BYTE;
BEGIN
WRITELN('ВВОД ИСХОДНЫХ ДАННЫХ:');
READLN(N);
FOR I:=1 TO N DO
READLN(A[I]);
SORT(A,N);
FOR I:=1 TO N DO
WRITELN(A[I]);
READKEY
END.

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

Кроме того тип, с которым описывается массив отсутствует в главной программе, т.к. он присутствует в модуле.

UNIT MODSORT;
INTERFACE
TYPE MAS=ARRAY[1..100] OF INTEGER;
PROCEDURE SORT(VAR A:MAS; N:BYTE);
IMPLEMENTATION
PROCEDURE SORT;
VAR I,J:BYTE;
X:INTEGER;
BEGIN
FOR J:=1 TO N-1 DO
FOR I:=1 TO N-J DO
IF A[I]>A[I+1] THEN
BEGIN
X:=A[I]; A[I]:=A[I+1]; A[I+1]:=X
END;
END;
END.

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

наверх

к следующей главе

Hosted by uCoz