Типом любого параметра в списке формальных параметров может быть только стандартный или ранее объявленный тип.
Нельзя, например, объявить следующую процедуру:
Procedure S(a: Array[1..10] of Real);
Правильно будет так:
Type Vector= Array[1..10] of Real;
Procedure S (a: Vector);
Или можно использовать открытые параметры-массивы.
В заголовке процедуры открытые параметры-массивы описываются следующим образом: <имя параметра-массива>: Array of <базовый тип>.
Открытый параметр-массив может быть параметром-значением, параметром-переменной или параметром-константой.
Передаваемые фактические параметры должны по типу совпадать с описанным базовым типом. Истинный диапазон изменения индекса фактического параметра-массива отображается в диапазон изменения индекса от 0 до N-1, где N – число элементов в фактическом параметре-массиве.
Приведем процедуру Summa из примера 1 c использованием открытых параметров-массивов.
Procedure Summa(vec: Array of Real; len: Integer);
Var i: Integer; s: Real;
Begin
s := 0;
For i := 0 to len-1 do s := s + vec[i];
Writeln(‘Сумма =’, s:7:2);
End;
Рекурсия – это такой способ организации вычислительного процесса, при котором подпрограмма в ходе выполнения составляющих ее операторов обращается сама к себе.
Пример – вычисление факториала.
{Вычисление с помощью итеративной конструкции – n! = 1*2*…*n}
Var Fact: Longint;
n, i: Integer;
Begin
Write(‘Введите число n: ’);
Readln(n);
Fact := 1;
For i := 1 to n do Fact := Fact*i;
Writeln(‘n! = ’, Fact);
Readln;
End.
{Вычисление с помощью рекурсивной функции Fact, в основу которой положена рекуррентная формула: 0! = 1, а для любого n > 0 n! = n*(n-1)!}
Var n: Integer;
Function Fact(n: Integer): Longint;
Var F: Longint;
Begin
If n<0 Then Writeln(‘Ошибка в задании n’)
Else
If n = 0 Then Fact := 1
Else Begin F := Fact(n-1);
Fact := n*F; End;
End;
Begin
Readln(n);
Writeln(‘n! = ’, Fact(n));
Readln;
End.
Для создания рекурсивных алгоритмов необходимо и достаточно наличие понятия процедуры или функции. Это вытекает из того, что процедуры и функции позволяют дать любой последовательности действий (операторов) имя, с помощью которого можно будет эту последовательность действий вызывать.
Главное требование к рекурсивным процедурам заключается в том, что вызов рекурсивной процедуры должен выполняться по условию, которое на каком-то уровне рекурсии станет ложным. Если условие истинно, то рекурсивный спуск (т.е. переход от некоторого текущего уровня организации алгоритма к нижнему уровню) продолжается. Когда оно становится ложным, то спуск заканчивается и начинается поочередный рекурсивный возврат из всех вызванных на данный момент копий рекурсивной процедуры. В приведенном примере для остановки рекурсивного спуска используется решение при n = 0.
Программы, в которых используются рекурсивные процедуры, отличаются простотой, наглядностью и компактностью текста. Но при выполнении рекурсивная форма организации алгоритма, как правило, медленнее и может вызвать переполнение стека (особым образом организованной области памяти для размещения локальных переменных подпрограммы), так как при каждом рекурсивном вызове для локальных переменных, а также для параметров подпрограммы, выделяются новые ячейки памяти.
Рекурсивный вызов может быть косвенным. В этом случае подпрограмма обращается к себе путем вызова другой подпрограммы, в которой содержится обращение к первой (взаимная рекурсия). Для того чтобы стал возможен вызов процедуры, которая еще не описана (каждый идентификатор перед употреблением должен быть описан), вводится опережающее описание, т.е. объявляется лишь заголовок процедуры, а ее тело заменяется стандартной директивой Forward, например:
Procedure Rec1(i: Byte); Forward;
Procedure Rec2(i: Byte);
Begin
Writeln(‘рекурсия’);
Rec1(i);
End;
Procedure Rec1; {не указываются описанные ранее формальные параметры}
Begin
If i > 0 Then Begin
Write(‘Взаимная ’);
Rec2(i-1);
End;
End;
Begin
Rec1(5);
Readln;
End.
В результате на экран пять раз выведется строка ‘Взаимная рекурсия’.