Рассмотрим более подробно вопросы взаимодействия формальных и фактических параметров.
Определения формальных и фактических параметров являются исключительно важными для понимания механизма их взаимодействия в подпрограммах. Поэтому на этом вопросе следует остановиться подробнее.
Формальные параметры подпрограммы указывают, с какими параметрами следует обращаться к этой подпрограмме (количество параметров, их последовательность, типы). Они задаются в заголовке подпрограммы в виде списка формальных параметров, разбитого на группы, разделенные точками с запятыми. В группу формальных параметров включаются однотипные параметры одной категории.
Все формальные параметры можно разбить на четыре категории:
- параметры-значения (эти параметры подпрограмма может изменить в основной подпрограмме);
- параметры-переменные (эти параметры подпрограмма может изменить в основной программе);
- параметры-константы (только в версии 7.0);
- параметры-процедуры и параметры-функции (т.е. процедурного типа).
Для каждого формального параметра следует указать имя и, как правило, тип, а в случае параметра-переменной или параметра-константы - категорию. Имена параметров могут быть любыми, в том числе и совпадать с именами объектов программы. Необходимо лишь помнить, что в этом случае параметр основной программы с таким именем становится недоступным для непосредственного использования подпрограммой. Тип формального параметра может быть практически любым, однако в заголовке подпрограммы нельзя вводить новый тип.
Например, нельзя писать
Function SUMM (A: array[1..100] of Real): Real;
Чтобы правильно записать этот заголовок, следует в основной программе ввести тип-массив, а затем использовать его в заголовке:
Type aArr = array[1..100] of real;
Function SUMM (A: aArr): Real;
При обращении к подпрограмме формальные параметры заменяются на соответствующие фактические вызывающей программы или подпрограммы.
Параметры-значения
Параметры-значения передаются основной программой в подпрограмму через стек (специальный канал передачи данных) в виде их копий и, следовательно, собственный параметр программы подпрограммой измениться не может.
Параметр-значение указывается в заголовке подпрограммы своим именем и через двоеточие - типом. Тип параметра-значения может быть любым, за исключением файлового.
Если параметров-значений одного типа несколько, их можно объединить в одну группу, перечислив их имена через запятую, а затем уже указать общий тип. Как было отмечено выше, отдельные группы параметров отделяются друг от друга точкой с запятой.
Пример 2.5.
Procedure MIN_MAX(Max,Min: Real; n: Word);
Function Tabulir(X,Y: Integer): Real;
В качестве фактического параметра на месте параметра-значения при вызове подпрограммы может выступать любое выражение совместимого для присваивания типа, не содержащее файловую компоненту, например:
Prl(Sqr(X),Sqr(Y),A*A);
Пример 2.6. Использовать функцию для вычисления максимального элемента в массиве.
Определим в основной программе тип-массив.
Type
aArr = Array[1..] of Integer;
Var Massiv: aArr; Maxim: Integer;
Функция в этом случае может иметь следующий вид.
Пример 2.7.
Function Max(Mas: aArr; N: Byte): Integer;
Var Ma: Integer; i: Byte;
Begin
Ma:= Mas[1];
For i:= 2 to N Do
If Ma < Mas[i] then Ma: = Mas[i];
Max:= Ma {Присваивание вычисл. значения имени функции}
End;
Пусть надо определить максимальное число из первых 35 чисел массива. Это можно сделать с помощью оператора, использующего обращение к функции: Maxim:= Max(Massiv,35);
Примечание. Данная программа может работать только с массивами типа аАrr. Для массивов другого типа надо создавать другую аналогичную подпрограмму. Данная программа создает в стеке копию исходного массива, поэтому она работает медленно.
Параметры-переменные
Параметр-переменная указывается в заголовке подпрограммы аналогично параметру-значению, но только перед именем параметра записывается зарезервированное слово VAR. Действие слова VAR распространяется до ближайшей точки с запятой, т.е. в пределах одной группы.
Пример 2.8. Procedure MaxMin(A: аАrr; Var Max, Min: Real; N: Word);
Здесь Max, Min- параметры-переменные, а переменные А и N - параметры-значения.
Тип параметров-переменных может быть любым, включая и файловый. При вызове подпрограммы на месте параметра-переменной в качестве фактического параметра должна использоваться переменная идентичного типа. Так, если формальный параметр имеет тип, определенный следующим образом:
Type аАrr = array [1.. 100] of Integer;
то и фактический параметр должен быть переменной или типизированной константой типа аАrr.
Пример 2.9.
Использовать функцию для вычисления максимального элемента в массиве.
В основной программе определяется тип-массив.
Type аАrr = Array [1.. 50] of Integer;
Var Massiv: аАrr; Maxim: Integer;
Функция в этом случае может иметь вид:
Function Max(Var Mas: аАгг; N: Byte): Integer;
Var Ma: Integer; i: Byte;
Begin Ma:=Mas[1];
For i:= 2 to N Do
If Ma < Mas[i] then Ma: = Mas[i];
Max:= Ma
End;
Пусть надо определить максимальное число из первых 35 чисел массива Это можно сделать с помощью оператора:
Maxim:= Max(Massiv,35);
Примечание. Эта программа лучше предыдущей тем, что в данном случае в стеке не создается копия исходного массива, что улучшает быстродействие и экономит память. Однако при такой передаче параметра возможно его нежелательное изменение (этот вариант передачи параметра допустим только в таких небольших подпрограммах, как в данном случае, когда программист может проконтролировать несанкционированное изменение параметра). Недостатком этой программы, как и ранее описанной, является то, что она может работать только с одним типом массива.
Параметры-константы
Часто в качестве параметра в подпрограмму следует передать ту или иную переменную, но изменять ее подпрограмма не должна. В этом случае нежелательно передавать этот параметр как параметр-переменную. Можно его передать как параметр-значение, однако если эта переменная имеет больший размер (массив, запись и т.д.), то копия этого параметра займет большую часть стека и даже может его переполнить. Это приводит также к уменьшению быстродействия программы. В этой ситуации параметр лучше передать как параметр-константу. Такой параметр, если он структурированного типа, передается своим адресом, но предусматривается защита от его изменения. Использовать параметр-константу можно только в версии Турбо Паскаля 7.0.
Параметр-константа указывается в заголовке подпрограммы аналогично параметру-значению, но перед именем параметра записывается зарезервированное слово Const. Действие слова Const распространяется до ближайшей точки с запятой, т.е. в пределах одной группы.
Пример 2.10. Function NewString(Const S: String): String;
Тип параметра-значения может быть любым, за исключением файлового. При вызове подпрограммы на месте параметра-переменной в качестве фактического параметра можно использовать любое выражение совместимого для присваивания типа, не содержащего файловую компоненту.
Параметр-константу нельзя передавать в другую подпрограмму в качестве фактического параметра.
Пример 2.11.
Функция вычисления максимального элемента в массиве, и в качестве первого параметра – параметр-константа.
Function Max(Const Mas: аАrr; N: Byte): Integer;
Var Ma: Integer; i: Byte;
Begin
Ma:= Mas[1];
For i:= 2 to N Do
If Ma < Mas[i] then Ma:= Mas[i];
Max:= Ma
End;
Параметры без типа
В Турбо Паскале можно использовать параметры-переменные и параметры-константы без указания типа. В этом случае фактический параметр может быть переменной любого типа,а ответственность за правильное использование того или иного параметра возлагается на программиста.
Пример 2.12. Function Tqual(Var Param1, Param2; Len: Word):Boolean;
Здесь Param1, Param2 - параметры-переменные без типа (вместо них можно использовать, например, любые переменные простого типа, типа-массив, типа-запись и т.д.); Len - параметр-значение.
Следует иметь в виду, что параметр “без типа” внутри подпрограммы типа не имеет и его перед использованием следует преобразовать к конкретному типу, применяя идентификатор соответствующего типа так, как ранее указывалось, при этом полученный результат может быть любого размера.
Пример 2.13. Функция вычисления максимального элемента в массиве. При этом в качестве первого параметра используется параметр-переменная без типа:
Function Max(Var Masr; N: Byte): Integer;
Type aArray = array[Maxint] of Integer; {тип массива максимального размера}
Var Ма: Integer; i: Byte;
Begin Ма:= aArray(Mas)[1];
For i:= 2 to N Do
If Ма < aArray(Mas)[i] then Ма := aArray(Mas)[i];
Max: = Ма
End;
В этом случае в качестве первого передаваемого параметра можно использовать любой массив (и не только массив), так что подпрограмма становится более универсальной. Тем не менее здесь необходимо передавать в качестве второго параметра фактический размер информации, что не очень удобно.