Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Развёрнутые лекции по Паскалю.doc
Скачиваний:
8
Добавлен:
01.03.2025
Размер:
512.51 Кб
Скачать

17.1.Объявление и вызов подпрограмм

а)Объявление подпрограмм

Структура подпрограммы почти полностью совпадает со структурой

программы. Действительно:

=>Заголовок подпрограммы:

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

Function <имя>[(<список формальных параметров>)]:<тип резу-

льтата>;

Отметим, что в отличии от заголовка программы заголовок у под-

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

имя подпрограммы, отделить ее текст от всей программы и обратиться

к ней в программе.

=>Раздел описаний. Он, как в программе, может включать в себя

несколько секций, но не может быть секции Uses. Как правило, отсут-

ствует секция подключения процедур и функций из внешних файлов.

=>Операторная часть. Она аналогична операторной части програм-

мы, только в конце ставится ;.

Пример 36. ┌─ заголовок подпрограммы (в данном случае-процедуры)

Procedure P1(X,Y,Z:Integer;C:Char;Var B:Byte;Var K:ShortInt);

Const N=10; ─┐

Type Ar=Array[1..5] Of String[10]; ├─ раздел описания

Var Ari:Ar; ─┘ локальные переменные

Begin ─┐

... ├─ операторная (исполняемая) часть

End; ─┘

Function F1(X,Y,Z:Integer;C:Char;Var K:ShortInt):Byte;

Const=10;

Type Ar=Array[1..5] Of String[10];

Var Ari:Ar;

Begin

...

F1:=<результат: 0..255 (байт)>;

End;

Примечания:

->Тип результата функции может быть стандартным или ранее объ-

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

простым, строковым, указателем или PChar.

->Начиная с версии TP 6.0, возможен вызов функции без присвое-

ния результата соответствующей переменной (так называемый

расширенный синтаксис). Для его реализации необходимо испо-

льзовать директиву компилятору {$X+}. Рекомендуется исполь-

зовать расширенный синтаксис в объектно-ориентированном про-

граммировании.

->Нельзя выйти из подпрограммы иначе, как через конец подпрог-

раммы, и нельзя войти в подпрограмму иначе, как через нача-

ло, т.е. нельзя по метке выйти наружу или войти внутрь.

->Идентификатор функции в теле подпрограммы может несколько

раз использоваться слева от оператора присваивания. Если не-

обходимо его подставить справа от знака :=, то следует ис-

пользовать идентификатор функции совместно со <списком пара-

метров>.

->Локальные переменные размещаются в сегменте стека.

Пример 37. {возведение в целочисленную степень}

X=1, N=0

X=1/Xn, N<0

X=Xn, N>0

Function Pow(X:Real;N:Integer):Real;

Begin

If N=0 Then Pow:=1.0

Else If N<0 Then Pow:=1/Pow(X,Abs(N))

Else Pow:=X*Pow(X,N-1);

End;

Приведенный в примере прием называется рекурсией, но о ней бу-

дет сказано позднее.

б)Расположения текста подпрограмм

=>В небольших программах текст подпрограмм обычно располагают

в секции описаний программ, как было сказано в 3.

=>При большом числе подпрограмм и в больших программах, текст

подпрограмм может быть размещен в отдельном файле, который подклю-

чается при компиляции, как сказано в 3, через {$I <имя файла>.Pas}.

=>Подпрограммы могут быть оформлены в виде модуля-блока и пре-

дварительно откомпилированы для получения файла с <имя файла>.Tpu,

который подключается в разделе описаний в секции Uses, но об этом

позднее.

=>Подпрограммы могут быть оформлены в виде модуля-блока, кото-

рый при компиляции подключается не к Exe файлу, а в виде Ovl-файла.

Для этого в программе надо указать {$O <имя файла>.Ovl}. Этот спо-

соб рассматривать не будем.

=>Подпрограммы могут быть написаны на другом языке, чаще всего

это ассемблер. Тогда они подключаются в виде Obj-кода с помощью ди-

рективы компилятору {$L <имя файла>.Obj}. В этом случае говорят о

внешних подпрограммах, и для их подключения используется зарезерви-

рованное слово External.

в)Вызов подпрограмм

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

ные.

Пример 38. {на основе примера 36}

Const Ic='d';

Var V:Byte;A,M:Integer;

B1:Byte;K1:ShorInt;

Begin

...

A:=10;

P1(A,-15,Sqr(4),Ic,B1,K1);

V:=F1(A,-15,A+4,Ic,K1);

...

End.

17.2.Объявление и передача параметров

Переменные, поступающие для обработки в подпрограмму, могут

передаваться в нее и обратно, а, следовательно, и описываться, тре-

мя различными способами.

а)Как глобальные переменные (плохой способ). При таком способе

переменные, которые передаются в подпрограмму и поступают из нее,

описываются в разделе описания головной программы. Если таким обра-

зом передаются все переменные, то в подпрограмме может вообще отсу-

тствовать <список формальных параметров>. Глобальные переменные ра-

змещаются в сегменте данных, размер которого не более 65520 байт.

Пример 39.

Procedure P2;

Var I:Byte; поступают извне

Begin │ │

For I:=1 To 10 Do WriteLn(I:4,X:4:2,St);

End;

Function F2:String;

Var S:String[15];

Begin

ReadLn(S);S:=S+St+' ';

F2:=S; └ поступает извне

End;

б)Как параметры-значения. Такие переменные только передаются в

подпрограмму. По окончании работы значения таких переменных не оп-

ределены и не могут быть использованы. В примере 36 к таким пере-

менным относятся: X,Y,Z,C.

в)Как параметры-переменные. Такие переменные не только переда-

ются в подпрограммы, но и сохраняют при выходе из нее те значения,

которые присваиваются им внутри подпрограммы. Описываются они с ис-

пользованием зарезервированного слова Var в <списке параметров> по-

дпрограммы. В примере 36 к таким переменным относятся B и K.

Примечания:

->Переменные, которые описаны в <списке параметров> при объяв-

лении подпрограммы, называются формальными. Они нужны лишь

для того, что бы показать: сколько переменных передается в

подпрограмму, какого они типа и как они обрабатываются внут-

ри подпрограммы.

->Если идентификаторы типов, констант, переменных, объявленных

в разделе описания подпрограммы, или идентификаторы перемен-

ных, объявленные в <списке формальных параметров>, совпадают

с какими-нибудь идентификаторами в головной программе, то

они имеют приоритет внутри подпрограммы. Для обращения к пе-

ременной из головной программы следует использовать состав-

ное имя: <имя программы>.<имя переменной>. Однако на началь-

ном этапе создания программ на ТР будем избегать этого.

->Параметры, которые подставляются вместо объявленных в <спис-

ке формальных параметров>, называются фактическими.

->Если параметры описаны в <списке формальных параметров>, как

параметры-значения, то вместо них можно подставлять как пере-

менные, описанные в головной программе, например, A вместо X

в программах P1 и F1, так и конкретные значения (-15) вместо

Y, или константы, как Ic вместо C, или выражения, Sqr(4) или

математическое выражение A+4 вместо Z.

->Если параметры описаны в <списке формальных параметров> как

параметры-переменные, то вместо них можно подставлять толь-

ко переменные, описанные в головной программе, например, B1

и K1 вместо B и K.

->Количество фактических параметров должно совпадать с объяв-

ленным, как и их типы и места расположения.

->Скобки для объявления формальных параметров круглые.

->Нельзя в скобках объявлять пользовательский т.е. ранее неиз-

вестный тип данных. Так нельзя объявить новый тип - массив:

Procedure P(X:Array[1..5] Of Real);

->В процедурах и функциях могут быть использованы нетипизиро-

ванные параметры-переменные со словом Var.

->В процедурах и функциях могут быть использованы открытые па-

раметры: строки и массивы различных размеров.

17.3.Особенности и виды подпрограмм, директивы подпрограмм

а)Рекурсия

Рекурсия - это такой способ организации вычислительного проце-

сса, при котором функция (реже процедура) в ходе выполнения состав-

ляющих ее операторов обращается сама к себе. При этом идентификатор

функции стоит справа от оператора присваивания и используется вмес-

те с формальными параметрами. Один из примеров рассмотрен нами в 36.

Пример 40.

->Function Fac(N:Byte):LongInt; {факториал N!}

Begin

If N=0 Then Fac:=1

Else Fac:=N*Fac(N-1);

End;

->Procedure Bin(N:Integer); {10-ое в 2-ое}

Begin

If N<2 Then Write(N) │2 {целочисленное}

Else Begin 19└── 2 {деление 19 Div 2}

Bin(N Div 2); │ 9 └── 2

Write(N Mod 2); │ │ 4 └── 2

End; │ │ │ 2 └── ответ

End; │ │ │ │ 1 0 0 1 1

помещаются в стек │ │ │ │

│ │ │ 2 Mod 2 │ │ │

│ │ 4 Mod 2 ───┘ │ │

9 Mod 2 ────────┘ │

19 Mod 2 ────────────┘

Рекурсия придает программам изящность, но пользоваться надо ос-

торожно, ибо программа выполняется медленнее и при большом числе

операций происходит переполнение сегмента данных и "зависание" ЭВМ.

б)Опережающее описание - директива

Хотя и редко, но бывают случаи, когда подпрограммы обращаются

друг к другу. Для того, чтобы обойти требование ТР, заключающееся в

том, что все используемые идентификаторы должны быть описаны ранее

их применения можно воспользоваться опережающим описанием: Forward.

Пример 41.

Procedure A(J:Byte);

...

Begin

...

B(J);

...

End;

Procedure B(I:Byte);

...

Begin

...

A(I);

...

End;

Достаточно перед описанием процедуры A записать:

Procedure B(I:Byte); Forward;

При описании же процедуры B в ее заголовке формальные парамет-

ры можно уже не указывать.

в)Процедура Inline (встроенная процедура) - директива

Procedure DeleteCursor; {удаление курсора с экрана}

Begin

Inline($B4/1/$B9/$2000/$CD/$10);

End; $0607 -{восстановление курсора на экране}

По существу это включение ассемблерного текста в программы на

ТР, но в виде кодов. В ТР версии 6.0 и выше можно уже непосредствен-

но включать текст на ассемблере. Ассемблерный текст в виде кодов

можно вставить в текст программы и непосредственно в виде Inline-

оператора.

Пример 42.

->Inline($B4/0/$CD/$16); - Стоп до нажатия любой клавиши.

->Inline($B8/$0600/$B7/$07/$B9/$0000/$BA/$184F/$CD/$10); - Очи-

стка окна заданным цветом.

$07 - Цвет фона (0) и цвет символов (7);

$0000 - Координаты левого верхнего угла окна (первые две циф-

ры - строка, вторые - столбец);

$184F - Координаты правого нижнего угла окна (первые две циф-

ры - строка, вторые - столбец).

г)External - внешняя процедура - директива

д)Interrupt - процедура прерывания - директива

е)Assembler - директива, позволяющая использовать язык assemb-

ler для написания кода подпрограмм.

ж)Export - директива, позволяющая сделать процедуры и функции

доступными для других модулей кода. Обязательно при

заимствовании процедур и функций для Windows-приме-

нений, при включении в библиотеки *.Dll.

з)В TP версии 7.0 в качестве параметров-переменных можно испо-

льзовать массивы и строки открытого типа (размеры не задаются). В

качестве фактического параметра в этом случае можно использовать

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

тех же компонент, что и объявленный. Фактический размер массива в

этом случае может быть определен с помощью функции High. Отметим,

что нумерация компонентов в открытом массиве всегда начинается с 0.

Для объявления открытой строки введен тип OpenString. Ее можно объ-

явить и через обычную строку типа String, указав опцию {$P+}.

Пример 43.

Function Max(Var Mas:Array Of Integer):Integer;

Var M:Integer;

I:Byte;

Begin

M:=Mas[0];

For I:=1 To High(Mas) Do If M < Mas[I] Then M:=Mas[I];

Max:=M;

End;

Procedure FillString(Var St:OpenString;C:Char);

Begin

St[0]:=Chr(High(St));

FillChar(St(1),High(St),C);

End;

18.ПРОЦЕДУРНЫЙ ТИП

В ТР, начиная с версии 5.0, допускается использовать процедуры

и функции как элементы языка, которые могут выступать в качестве

переменных, а также параметров-значений, передаваемых в подпрограм-

мы. Для этого введен процедурный тип.

Рассмотрим проблему использования переменных и параметров-зна-

чений процедурного типа на примере вычисления суммы F(K) членов ря-

да с номера L по номер N, где F(K)=1/K.

1.Для этого необходимо:

а)В секции Type описать пользовательский процедурный тип: про-

цедуру или/и функцию. Например:

Type Proc=Procedure(Var L,N:Integer); {процедурный тип}

Func=Function(K:Integer):Real;

По существу описывается целый класс (набор) процедур и функций

подобного типа.

б)В секции Var можно объявить переменные введенного типа фун-

кции или/и процедуры и другие необходимые переменные.

Var Fu1:Func; {объявлена переменная функция}

Pr1:Proc; {объявлена переменная процедура}

I,J,P:Byte;

R:Real;

в)Описать процедуру и/или функцию, передаваемую в качестве па-

раметра, в разделе описания с ключом-опцией: {$F+} - дальний вызов.

Пример 44.

{$F+}

Procedure Vvod(Var L,N:Integer);

Begin

Write('Укажите номер начального элемента ряда ');

ReadLn(L);

Write('Укажите номер последнего элемента ряда ');

ReadLn(N);

End;

Function S(K:Integer):Real;

Begin

S:=1/K;

End;

2.Как все это использовалось?

Если не использовать передачу функции и процедуры в качестве

параметра, то мы записали бы головную программу следующим образом:

Begin

R:=0;

Vvod(I,J);

For P:=I To J Do R:=R+S(P);

WriteLn('Сумма интересуемых членов ряда = ',R:5:2);

End.

Для того, чтобы передать функцию и процедуру в качестве пара-

метра, необходимо определить подпрограмму, в которую они передаются.

В нашем случае можем ввести такую процедуру:

┌──────┬─ процедура и функция -параметры-значения

Function Sum(P:Proc;F:Func):Real;

Var L,N,R:Integer;

Rv:Real;

Begin

Rv:=0;

P(L,N);

For R:=L To N Do Rv:=Rv+F(R);

Sum:=Rv;

End;

После этого в головной программе мы можем записать:

Begin

R:=Sum(VVod,S);

WriteLn('Сумма интересующих членов ряда = ',R:5:2);

End.

Можно также и через переменные процедуры и функции решить за-

дачу. Этот способ предпочтительнее в тех случаях, когда несколько

процедур и/или функции необходимо передавать.

Begin

Pr1:=Vvod; {в этих случаях Pr1 и Fu1 присваиваются адреса,}

Fu1:=S; {по которым размещаются подпрограммы Vvod и S}

R:=Sum(Pr1,Fu1);

WriteLn('Сумма интересуемых членов ряда = ',R:5:2);

End.

Примечания:

->Нельзя передавать в качестве параметра стандартные процедуры

и функции. Если это необходимо, то следует на их основе сде-

лать свою.

->Передаваемые процедуры и функции не могут быть встроенными в

другие процедуры и функции.

->Нельзя передавать подпрограммы, включающие прерывания.

->В памяти этот тип занимает 4 байта (двойное слово).

->Переменной процедурного типа можно присваивать значение Nil,

значение переменной процедурного типа или идентификатор под-

программы. Возможен оператор If @Pr1<>Nil Then Pr1(I,J);

->Процедурные типы являются совместимыми, если у них совпадает

число параметров и они имеют в одноименных позициях одинако-

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

->Могут быть объявлены константы-процедуры или функции, напри-

мер, Const ConstProc:Proc=Vvod;