Итак, начнем исследование подпрограммы с процедур. Как уже было отмечено, процедуру надо описать. Описание процедуры состоит из заголовка и тела процедуры.
Заголовок состоит из ключевого слова procedure, за которым следует имя процедуры и, при необходимости, список параметров, заключенных в круглые скобки:
procedure <Имя> [(параметры)];
Вслед за заголовком может следовать блок объявления локальных меток, типов и переменных. Локальными они называются потому, что предназначены исключительно для этой процедуры.
ПРИМЕЧАНИЕ Вопросы локальных и глобальных переменных, и вообще видимости в программах, будет рассмотрен позже в этой главе.
После заголовочной части следует тело процедуры, заключаемое в begin и end. Таким образом, исходный код процедуры может выглядеть примерно таким образом:
procedure TriplePrint(str: string); var i: integer; begin for i := 1 to 3 do begin writeln('"'+str+'"'); end; // конец цикла for end; // конец процедуры TriplePrint
Здесь мы определили процедуру TriplePrint, которая будет трижды выводить переданную ей в качестве аргумента строку, заключенную в двойные кавычки. Как видно, данная процедура имеет все составные части: ключевое слово procedure, имя, список параметров (в данном случае он всего один - строковая переменная str), блок объявления собственных переменных (целочисленная переменная i), и собственное тело, состоящее из оператора цикла for.
Для использования данной процедуры в любом месте программы достаточно написать инструкцию вызова процедуры, состоящую из имени процедуры и списка аргументов, например:
TriplePrint('Hello!!!');
Отметим так же, что рассмотренная нами процедура сама содержит вызов другой процедуры - writeln. Процедуры могут быть встроенными. Иначе говоря, объявление одной процедуры можно помещать в заголовочную часть другой. Например, наша процедура TriplePrint может иметь вспомогательную процедуру, которая будет "подготавливать" строку к выводу. Для этого перед объявлением переменной i, разместим объявление еще одной процедуры. Назовем ее PrepareStr:
procedure PrepareStr; begin str := '"'+str+'"'; end;
Отметим, что переменная str, хотя и не передается этой процедуре в качестве параметра, тем не менее может в ней использоваться, поскольку данная процедура является составной частью процедуры TriplePrint, внутри которой данная переменная доступна для использования.
Таким образом, мы получаем две процедуры, одна из которых (TriplePrint) может использоваться во всей программе, а другая (PrepareStr) - только внутри процедуры TriplePrint. Чтобы преимущество использования процедур было очевидно, рассмотрим их на примере программы, которая будет использовать ее неоднократно, для чего обратимся к листингу 6.1 (см. так же пример в Demo\Part1\Procs).
Листинг 6.1. Использование процедур
program procs; {$APPTYPE CONSOLE} procedure TriplePrint(str: string); procedure PrepareStr; begin str := '"'+str+'"'; end; var i: integer; begin PrepareStr; for i := 1 to 3 do begin writeln(str); end; end; // конец процедуры TriplePrint begin // начало тела основной программы TriplePrint('Hello!!!'); // первый вызов TriplePrint TriplePrint('How are you???'); // 2-й вызов TriplePrint('Bye...'); // 3-й readln; end.
Очевидно, что если бы не процедура, то нам трижды пришлось бы писать цикл, свой для каждого слова. Таким образом, процедуры позволяют использовать единожды написанный код многократно, что существенно облегчает написание программ.
Параметры формальные и неформальные
Формальные и фактические параметры
Параметры, указываемые при описании подпрограммы, называются формальными, а параметры, указываемые при вызове подпрограммы, – фактическими.
Список фактических параметров подпрограммы должен совпадать по количеству и типам со списком формальных параметров. Список формальных параметров необязателен и может отсутствовать (в этом случае будут отсутствовать и фактические параметры). При описании и вызове подпрограммы без параметров круглые скобки не указываются. Следующие подряд однотипные параметры можно объединять в подчиненные списки. Другими словами, можно указывать их через запятую, а за последним параметром – их тип. Параметры подпрограммы могут быть значениями, переменными, константами.
Параметры-значения передаются в подпрограмму через стек в виде их копий. Поэтому любые изменения таких параметров в теле процедуры ни как не отражаются на значениях внешних переменных. Параметры-значения используются для передачи в подпрограмму исходных данных, используемых для расчета. Такие параметры при описании подпрограммы не предваряются никакими зарезервированными словами. Для каждой из них указывается соответствующий тип данных.
Параметры-переменные указываются в описании подпрограммы после зарезервированного слова var. Действие зарезервированного слова var имеет силу до ближайшей точки с запятой. При вызове подпрограммы на месте параметра-переменной в качестве фактического параметра указывается переменная того же типа. При использовании параметра-переменной в подпрограмму передается сама переменная. Это позволяет вернуть в точку вызова подпрограммы измененные значения внешних переменных, которые были указаны в качестве параметров. Иными словами, изменения значений параметров-переменных в теле подпрограммы приводит также к изменению значений внешних переменных, указанных в качестве параметров при вызове подпрограммы.
Параметры-константы используются в подпрограммах. Если подпрограмма не должна менять передаваемое значение. В этом случае параметр передается в виде адреса той области памяти, в которой располагается константа. При передаче параметра-константы как параметра-значения (что, в принципе, возможно) быстродействие программы уменьшается. Перед именем параметра-константы указывается зарезервированное слово const, действие которого также распространяется до ближайшей точки с запятой.