Программа на Delphi

В нижней части программы дан фрагмент текста головной программы, содержащей вызов процедуры Prim.

Опишем механизм вычислений, который запускается приведенной программой. Сначала будет выполнена процедура Prim (обращение к ней содержится в самой нижней части текста примера). Эта процедура без параметров, поэтому управление будет сразу передано в тело процедуры, где начнется последовательное выполнение содержащихся в нем операторов. Сначала будут выполнены два вложенных цикла For, где элементы матриц Q1, Q2 будут заполнены значениями (например Q1[1, 1] = 2, Q2[1, 1] = 0 и т. д.). Далее уже внутри Prim произойдет обращение к процедуре MatrMult. При этом сначала произойдет подстановка фактических параметров Q1, Q2, Q3 на место соответствующих формальных параметров M1, M2, M3. Далее управление будет передано внутрь процедуры MatrMult, где аналогично последовательным выполнением ее операторов произойдет перемножение матриц. После выполнения процедуры MatrMult управление будет передано в ту же точку, с которой производился ее вызов. Поскольку вызов MatrMult производился из Prim, то управление будет вновь возвращено в процедуру Prim к оператору, расположенному вслед за оператором вызова MatrMult. Поскольку в Prim больше нет невыполненных операторов, то она также заканчивает свою работу и управление передается в ту алгоритмическую единицу, которая и вызывала Prim, а именно в головную программу, к оператору Q3[2, 3] := 1.

15.2. Функции

В отличие от процедуры функция предназначена для вычисления одного значения любого типа. Тип функции указывается в конце ее заголовка. Тип возвращаемого значения отделяется от списка формальных параметров символом ":" (двоеточие). Кроме того, в теле функции, по крайней мере, один раз должно быть определено значение функции. Это значение присваивается имени функции или переменной Result.

Синтаксис функции имеет вид

function functionName(parameterList): returnType; directives;

localDeclarations;

begin

statements;

end;

Здесь functionName – имя функции; ParameterList, directives, localDeclarations, statements имеют тот же смысл, что и в процедуре; ReturnType – тип возвращаемого результата.

Пример.

Function Fact(n: Word): LongInt; {заголовок функции Fact}

Var i: Word; j: LongInt;

Begin

j:=1;

if (n > 1) then

For i:= 2 to n do j:= j * i;

Result:= j;

End; {конец описания функции Fact }

… {текст головной программы}

Var r: Real;

r:= 3.4 * Fact(3) / 2.5 / (122 - Fact(5)); {обращение к функции Fact}

В этом примере описана функция с именем Fact вычисления факториала n! неотрицательного целого числа. Тип функции определен как LongInt. В теле функции размещен оператор Result:= j, который определяет возвращаемый функцией результат. Способ обращения к функции демонстрирует последний оператор примера. Видно, что способ обращения к функции имеет существенное отличие от способа обращения к процедуре. Так, в этом операторе обращение к функции Fact производится дважды – один раз с фактическим параметром 3, другой – с параметром 5. Далее возвращенные результаты (соответственно, 6 и 120) будут подставлены в выражение правой части оператора, после чего последний будет вычислен и переменная r получит вещественное (Real) значение 4.08.

15.3. Параметры без типа

Это особый вид параметров, который может быть использован только в заголовках имен процедур и функций. Каждый параметр без типа должен быть описан как var, const или out-параметр. Например:

procedure TakeAnything(const C);

описывает С как константу без типа.

Параметр без типа компилятор расценивает как параметр потенциально любого типа. Это означает, что в тело подпрограммы передается только адрес параметра и компилятор не контролирует правильность выполнения операций над таким параметром.

Однако имеется одно исключение: при обращении к подпрограммам, содержащим параметры без типа, нельзя использовать числовые значения или нетипизированные числовые константы.

Следующий пример использует параметры без типа в функции Compare, которая сравнивает размеры двух переменных V1 и V2 и возвращает ответ в виде константы –1, если размер V1 меньше размера V2, нуль – если размеры одинаковы, 1 – если размер V1 меньше размера V2.

function Compare(var V1, V2): ShortInt;

Var i, j: LongInt;

Begin

I:=SizeOf(V1);

J:=SizeOf(V2);

If (I < J) then Result:= -1

Else

If (I > J) then Result:= 1

Else Result:= 0;

End;

Примеры обращений к функции Compare:

type

TVector = array[1 10] of Integer;

TPoint = record

X, Y: Integer;

end;

var

Vec1, Vec2: TVector;

N,i: Integer;

P: TPoint;

i:= Compare(Vec1, Vec2) ; {0, размеры одинаковы}

Vec[1]:= Compare(i, Vec1); {-1, размер i меньше размера Vec1}

P.X:= Compare(Vec1, P); {1, размер Vec1 больше размера P}

P.Y:= Compare(i, P); {-1, размер i меньше размера P}

Vec2[8]:= Compare(i, P.X); {0, размеры i и поля P.X одинаковы}

15.4. Декларации процедур и функций

Заголовок процедуры или функции может содержать декларацию. Декларация указывается сразу вслед за списком параметров в процедуре или за типом возвращаемого результата в функции.

1. Декларации о вызове по соглашению (calling convention). К их числу относятся декларации register, pascal, cdecl, stdcall и safecall, например:

function MyFunction(X, Y: Real): Real; cdecl;

Этот вид деклараций предназначен для задания способа передачи параметров в процедуру. Декларации register, pascal передают параметры слева направо, cdecl, stdcall и safecall – наоборот, справа налево.

Директивы near, far и export предназначены для разграничения способов обращения в 16-разрядных приложениях. Для современных 32-разрядных приложений они не имеют значения.

Отметим, что упомянутые декларации используются в сложных, весьма тонких ситуациях и для начинающего программиста не представляют большого интереса.

2. Директива Forward указывает на то, что заголовок процедуры или функции объявлен раньше, чем описана сама подпрограмма, например:

function Calculate(X, Y: Integer): Real; forward;

function Calculate;

.

begin

.

end;

3. Директива External указывает на то, что текст процедуры содержится в отдельном объектном (откомпилированном) модуле. Такой способ позволяет присоединить объектный код к компилируемой программе из указанного модуля. Для этого необходимо указать директиву компилятора со ссылкой на модуль, в котором содержится объектный код декларируемой процедуры, например:

{$L BLOCK.OBJ}

procedure MoveWord(var Source, Dest; Count: Integer); external;

procedure FillWord(var Dest; Data: Integer; Count: Integer); external;


Страница: