Передаваемым параметром может быть также параметр-процедура или параметр-функция, т. е. параметр процедурного типа. Фактически этот параметр является параметром-значением, т. к. записывается без зарезервированного слова var.
В качестве фактического параметра в этом случае используется соответствующая процедура или функция, имеющая необходимое количество параметров требуемых типов.
Для параметров-процедур и параметров-функций существуют те же правила, что и для других переменных процедурного типа: подпрограммы должны компилироваться с ключом {$F+) или иметь директиву far, не должны быть стандартными подпрограммами, не должны объявляться внутри других подпрограмм, не иметь директив inline или interrupt.
Пример. Программа, печатающая таблицы сложения и умножения двух целых чисел в заданном диапазоне.
program EXAMPLE15;
type
Func = function(X, Y: Integer): Integer;
($F+)
function Add(X, Y: Integer): Integer;
begin
Add := X + Y
end;
function Multiply(X, Y: Integer):
Integer;
begin
Multiply := X * Y
end;
{$F-}
procedure PrintTable(A, B: Integer;Operation: Func);
{процедура печати таблицы}
var
i, j: Integer;
begin
for i := 1 to A do
begin
for j := 1 to В do
Write(Operation(i, j): 5);
WriteLn
end;
WriteLn
end;
begin {начало основной программы}
PrintTable(10, 10, Add);
PrintTable(10, 10, Multiply)
end.
ОБЛАСТЬ ДЕЙСТВИЯ ПАРАМЕТРОВ
При создании программ, использующих процедуры, следует учитывать, что все объекты (метки, константы, типы, переменные, процедуры и функции), которые описывались после заголовка процедуры, называются локальными объектами и доступны только в пределах этой процедуры, но недоступны вызывающей программе. Все эти объекты создаются при входе в процедуру и уничтожаются при выходе из нее. Если одно и тоже имя определено в нескольких процедурах, вызываемых одной и той же программой, то в каждой процедуре этому имени соответствует свой локальный объект.
Все объекты, описанные в вызывающей программе, называются глобальными и являются доступными внутри процедур, вызываемых этой программой. Поэтому обмен данными между программою и вызываемой ею процедурой может производиться и через глобальные переменные. Если одно и тоже имя определено и в программе, и в вызываемой ею процедуре, то ему соответствует глобальный объект, но внутри процедуры глобальный объект недоступен, он как бы экранируется локальным объектом с таким же именем.
В Turbo Pascal допускается любой уровень вложенности процедур и функций. Процедура, описанная в основной программе, в свою очередь, может, может иметь описания внутренних процедур и функций и т.д. При этом объекты, описанные в вызывающей процедуре, являются глобальными по отношению к вызываемой процедуре.
Можно схематически изобразить структуру блоков некоторой программы, как показано на рис.1.
Для доступа к объектам, описанным в различных блоках, требуется соблюдать следующие правила:
1. Имена объектов, описанных в некотором блоке, считаются известными в пределах данного блока, включая и все вложенные блоки.
2. Имена объектов описанных в блоке, должны быть уникальны в пределах данного блока и могут совпадать с именами объектов из других блоков.
3. Если в некотором блоке описан объект, имя которого совпадает с именем объекта, описанного в объемлющем блоке, то это последнее имя становится недоступным в данном блоке (оно как бы экранируется одноименным объектом данного блока).
Если применить эти правила к предыдущей схеме то можно сказать, что объекты, описанные в блоке В, известны кроме самого блока В еще и в блоках С и D, но невидимы в блоке А. Объекты, описанные в блоке F, известны в пределах только этого блока.
Иногда при вызове подпрограмм-функций возникают побочные эффекты, выражающиеся в том, что вносятся нежелательные изменения в значениях глобальных переменных. Поэтому необходимо внимательно подходить к описанию параметров-переменных, при выборе имен нужно учитывать наличие глобальных объектов с такими же именами.
В качестве примера с вложенными подпрограммами рассмотрим пример программы, определяющей количество сверхпростых чисел в натуральном ряду чисел, не превышающих 1000. Сверхпростым называется число, если оно простое и число, полученное из исходного числа, при записи цифр исходного числа в обратном порядке (перевертыш) тоже будет простым. Например, 13 и 31 —сверхпростые числа.
Program Prim7_3;
var X, К : integer; {Описание глобальных переменных X, К}
{Функция проверки числа Х на простое число}
function Prost(Y : integer):boolean;
var
D, I : integer;
Flag : boolean;
begin
D:=0; Flag:=False;
for I:=2 to Y-l do if Y mod 1=0 then D:=D+1;
if D=0 then Flag:=True;
Prost:=Flag;
end;
{Перевертыш простого числа}
function Povorot(Y:integer):integer ;
var
S:integer; {Описание локальной переменной 3}
begin
if Y<10 then S:=Y;
if (Y>10) and (Y<100) then S:=Y mod 10*10+Y div 10;
if (Y>=100) and (Y<1000)
then
S:=Y mod 10*100+Y mod 100 div 10*10+Y div 100;
Povorot:=S;
end;
begin {Начало главной программы}
Writeln(‘ ’:20,’Сверхпростые числа’);
К:=2; {2 и 3 — простые числа}
for X:=4 to 999 do
begin
if Prost(X) then {Вызов функции определения простого числа х}
if Prost(Povorot(X)) then
{Вызов функции определения простого числа для числа-перевертыша полученного вычислением функции Povorot(х) от простого числа}
begin
Writeln(X); {Печать сверхпростого числа}
К:=К+1;
end;
end;
Writein(‘Всего найдено‘,К,’сверхпростых чисел < 1000 ‘);
end.
РЕКУРСИЯ
Рекурсия - это такой способ организации вычислительного процесса, при котором процедура или функция в ходе выполнения составляющих ее операторов обращается сама к себе.
Примером программы с использованием рекурсии может быть программа вычисления факториала числа.
Program Prim7_4;
var N:integer;
F:longint;
function Fact(N:integer):longint;
begin
if N=1 then Fact:=1 else Fact:=N*Fact(N-1);
end;
begin {Начало главной программы}
Write('Введите число N ');
Readln(N);
F:=Fact(N);
Writeln('Для числа ',N,' значение факториала = ',F);
Readln
end.
После считывания числа N, в выражении N:=Fact(N); вызывается функция Fact с параметром-значением N. В подпрограмме функции Fact вычисления факториала проверяется условие N=1. Если оно выполняется, то функции Fact присваивается значение 1, на этом выполнение функции завершается. Если условие N=1 не соблюдается, то выполняется вычисление произведения N*Fact(N-1).Вычисление
произведения носит рекурсивный характер, так как при этом осуществляется вызов функции Fact(N-1), значение которой вычисляется, в свою очередь, через вызов функции Fact и так до тех пор, пока значение параметра N=1.
Таким образом, при выполнении рекурсивной подпрограммы осуществляется многократный переход от некоторого текущего уровня организации алгоритма к нижнему уровню последовательно до тех пор, пока, наконец, не будет получено тривиальное решение поставленной задачи. В нашем примере решение при N=1 тривиально, т.к. Fact=1. Затем осуществляется возврат на верхний уровень с последовательным вычислением функции Fact.
Следует учитывать, что использование рекурсивной формы организации алгоритма обычно выглядит изящнее итерационной и дает более компактный текст программы, но при этом выполняется медленнее и может вызвать переполнение стека. Это объясняется тем, что при каждом входе в подпрограмму ее локальные переменные размещаются в особым образом организованной области памяти, называемой программным стеком.
Дата: 2019-05-28, просмотров: 199.