Формальные и фактические параметры
Формальные параметры задаются при объявлении подпрограммы, фактические параметры указываются при выполнении расчетов, т.е. при вызове подпрограммы. Фактические параметры должны быть идентичных типов с формальными. Количество их должно быть равно количеству формальных параметров, должен совпадать и порядок следования фактических параметров с порядком записи формальных. Механизм передачи данных через формальные параметры реализуется, используя специальную область памяти – стек. По умолчанию размер стека установлен 16384 байта. Можно изменить объем стека в настройках среды Delphi.
ПАРАМЕТРЫ-ЗНАЧЕНИЯ
В этом случае для передаваемого фактического параметра создаётся копия в стеке. Синтаксис записи, например, таков: Function FF(a,b:Real; …):…; (пример подпрограммы выше содержит этот тип параметров). На месте параметра-значения при вызове подпрограммы может стоять выражение, совместимое по присваиванию с формальным параметром. Внутри подпрограммы значение такого параметра измениться не может. Входные параметры можно задавать как параметры-значения. Передавать в подпрограмму массивы в виде параметров-значений нецелесообразно, т.к. расходуется лишняя память - в стеке создаётся дополнительная копия массива.
ПАРАМЕТРЫ-ПЕРЕМЕННЫЕ
При использовании в подпрограммах параметров-переменных в стеке выделяются ячейки для размещения адресов фактических параметров. В отличие от параметров-значений, внутри подпрограммы значения параметров-переменных могут изменяться. Так как фактические параметры в этом случае передаются по адресу, любое изменение параметра-переменной внутри подпрограммы, таким образом, фиксируется в фактическом параметре. Параметр-переменная записывается, используя ключевое слово var, например: Procedure PP(var c:Integer; …); (пример процедуры выше содержит этот тип параметра). Выходные параметры задаются как параметры-переменные.
ПАРАМЕТРЫ-КОНСТАНТЫ
Параметры-константы синтаксически введены для того, чтобы ключевое слово var сохранить за выходным параметром и в то же время входной параметр мог передаваться по адресу. Синтаксис записи этих параметров таков: Procedure PP(const a:real; …); (пример процедуры выше содержит этот тип параметра). В данном случае простые переменные передаются как копии, а, например, массивы и строки – по адресу. Компилятор сам определяет, что передавать по адресу, а что как копию. Изменить параметры-константы внутри подпрограммы нельзя. Таким образом, входные параметры могут передаваться в подпрограмму как параметры-константы. Вместо параметров-констант можно подставлять выражения, как и для параметров-значений.
ПАРАМЕТРЫ БЕЗ ТИПА
Существуют параметры-переменные и параметры-константы без указания их типа. Передаются такие параметры по адресу. При использовании этих параметров внутри подпрограммы необходимо определить их тип и воспользоваться, например, преобразованием типов. Рассмотрим следующий пример: пусть требуется найти максимальный элемент для заданного одномерного массива. Напишем функцию поиска максимального элемента.
Function MMax(var a): Integer;
Type Vect = array of integer;
Var i : byte;
Begin
Result := Vect(a)[0];
For i := 1 to High(Vect(a)) do
If Result < Vect(a)[i] then Result := Vect(a)[i];
End;
В качестве фактического параметра в данном случае можно использовать любой одномерный динамический массив целых чисел, размерность этого массива может быть любая. Пусть требуется найти с помощью этой функции максимальный элемент для вектора B, состоящего из 20 элементов. Сначала объявим этот вектор и переменную Y, в которую запишем результат: Var B:array of integer; Y:integer;
Далее надо определить массив, предварительно выделив для него память: SetLength(B,20); . . . . .
Теперь запишем вызов функции Y:=Mmax(B);
МАССИВЫ ОТКРЫТОГО ТИПА
В подпрограммах нельзя объявлять формальный параметр как статический массив в виде array […] of …, так как он не будет идентичен ни одному фактическому параметру. Если всё же необходимо обмениваться с подпрограммой данными в виде статических массивов, то предварительно их надо типизировать, например, Type Vekt = array [1..20] of real;
Function sum(const V:Vekt; …
Чаще всего при вычислениях с векторами или матрицами формальные параметры в подпрограммах описывают как открытые массивы, используя тот же синтаксис и все правила, которые применяются при работе с динамическими массивами. Перепишем предыдущую функцию, для того чтобы можно было передавать одномерный массив любой размерности и не использовать преобразование типов внутри подпрограммы.
Function Mmax(const mas: Array of Integer): Integer;
Var I : Byte;
Begin
Result := Mas[0];
For i := 1 to High(mas) do
If Result < mas[i] then Result := Mas[i];
End;
Если формальный параметр представляет собой открытый массив, то в качестве фактического параметра можно использовать конструктор массива. Конструктор массива разрешается применять, если открытый массив задан в виде параметра-константы, как в предыдущей функции MMax. Конструктор открытого массива по синтаксису записи совпадает с конструктором множества. Пусть заданы три значения: a, 15, b + c, где a, b, c – переменные. Найти среди них максимум с помощью подпрограммы MMax и результат записать в Y.
Y := MMax([a, 15, b + c]);
Если необходим обмен данными с помощью массивов вариантного типа, то используется формальный параметр типа Array of const (открытый массив вариантного типа).
ПАРАМЕРЫ ПО УМОЛЧАНИЮ
Часто при вызове подпрограммы в неё нужно передавать параметры, имеющие некоторое заданное значение. Например, получить распределение случайных чисел, зависящее от многих параметров, но при заданном одном k = 5 или k = 9, где k – некоторая характеристика, остальные параметры изменяются одинаково. Заменить такие, как k, параметры на константы нельзя – всё же они иногда меняются. Эта проблема решается введением параметров по умолчанию. Например, запишем функцию для вычисления распределения Гаусса:
Здесь x – случайная величина, заданная в диапазоне от a до b с шагом h; m=(a+b)/2; s - параметр, по умолчанию равный 1 (но иногда требуется задать значение, например 0.5 или 2).
Function Gaussa(x, m: real; sigma: real=1.0): real;
Begin
Result:=exp(-sqr(x-m)/(2*sqr(sigma)))/
(sqrt(2*p)*sigma);
End;
При выполнении расчетов можно записать так:
Y:= Gaussa(x,(a+b)/2);, опуская параметр sigma,
или так:Y:= Gaussa(x,(a+b)/2,2.0);
Очень важно отметить следующее. Параметров по умолчанию может быть несколько. Но все они должны быть сосредоточены в конце списка параметров. Объяснение этому очень простое. Допустим, подпрограмма имеет 4 параметра. Из них первые два – параметры по умолчанию. В этом случае, если указаны при вызове подпрограммы 3 параметра, то, как определить, что это первый, третий и четвёртый или второй, третий и четвёртый. Поэтому параметры можно опускать, начиная с конца, например, для функции
Function MyFF(x:byte= 1; y:byte= 1; z:byte= 1):byte;
можно записать так:
A:=MyFF(2,2,2);илиA:=MyFF(2,2);илиA:=MyFF(2);
илиA:=MyFF;,а так записывать нельзя: A:=MyFF(, 2, 2); A:=MyFF(2, , 2);
Параметром по умолчанию может быть только константа или константное выражение, т.е. то, что можно определить на этапе компиляции.
ПРОЦЕДУРА EXIT
Эта процедура используется, если необходимо досрочно выйти из подпрограммы. Например, задан массив вещественных чисел, найти первый отрицательный элемент в этом массиве:
Function Minus(const M : Array of Real): Real;
Var I: Byte;
Begin
Minus := 0.0;
For I:=0 to High(M) do
If M[i]<0 then begin
Minus := M[i];
Exit;
End;
End;
ДИРЕКТИВЫ ПОДПРОГРАММЫ
Директивы подпрограммы дают компилятору дополнительную информацию по способу передачи данных, размещению данных в стеке и т.д. Директивы записываются в виде ключевых слов, идущие непосредственно за заголовком подпрограммы, отделяются они от заголовка “ ; ”.