- •Процедуры и функции
- •Процедуры
- •Пример Вызов процедуры InpInt для ввода k целых чисел в массив m.
- •Функции
- •Формальные и фактические параметры
- •Параметры-значения Параметры-значения передаются основной программой в подпрограмму через стек в виде их копий. Сам параметр программы подпрограммой измениться не может.
- •Параметры-переменные
- •Этот вариант лучше предыдущего, так как в стеке не создается копия исходного массива, что улучшает быстродействие и экономит память.
- •Локализация имен
- •Пример Структура вложенной программы.
- •Основное правило Паскаля
- •Допустимые вызовы процедуры
- •Совместимость и преобразование типов данных
- •Параметры-массивы и строки открытого типа
- •Процедурные типы
- •Проблема совместимости
- •Рекурсия
- •Побочный эффект
- •Рекурсивная функция
- •Стеки для локальных переменных и параметров
- •Реализация стеков параметров в Паскале
Проблема совместимости
По присваиванию - частный случай. Процедурные типы должны иметь одинаковое количество формальных параметров. Параметры на соответствующих позициях должны быть одного типа. Имена параметров никакого значения не имеют.
Аналогичным образом должны совпадать типы возвращаемых значений в случае функций.
Механизм процедурных типов предоставляет программисту весьма широкие и удобные возможности при разработке программ. Корректная работа требует соблюдения следующих правил.
-
Подпрограмма, присваиваемая процедурной переменной, должна быть оттранслирована в режиме «дальнего типа вызовов». Для достижения эффекта необходимо перед подпрограммой или группой подпрограмм расположить директиву компилятора $F со знаком +, а в конце группы со знаком -.
Пример
{$F+}
function Add (a,b: real):real;
begin
Add:=a+b
end;
function Sub (a,b: real):real;
begin
Sub:=a-b
end;
{$F-}
Если необходимо распространить действие этой директивы на всю программу, то достаточно одну {$F+} поместить в самом начале текста.
Эквивалентом директивы компилятора {$F+} является служебное слово far, которое должно быть записано перед блоком подпрограммы. (другой - «близкий» тип вызова задаётся служебным словом near).
function add (a,b: real):real; far;
begin
Add:=a+b
end;
-
Подпрограмма, присваиваемая процедурной переменной, не должна быть стандартной процедурой или функцией. Это ограничение при необходимости можно легко обойти, заключив вызов стандартной подпрограммы в «оболочку», после чего её можно использовать в качестве присваивания.
Пример
var
Func: function (s: string): byte;
….......
function Mylength (s: string): byte; far;
begin
Mylength:=length(s)
end;
………
Func:= Mylength;
-
Важное ограничение – обсуждаемые подпрограммы не могут быть вложенными в другие подпрограммы.
-
Подпрограммы, присваиваемые процедурным переменным, не могут быть подпрограммами специального вида, содержащими спецификации interrupt и конструкцию inline.
Можно описывать процедуры и функции, параметрами которых являются процедурные переменные.
Можно организовать подпрограмму, которая будет выполнять некоторые общие действия для различных подпрограмм – параметров.
Пример
program Tables;
type
func= function(x, y: integer): integer;
function Add(a, b: integer):integer; far;
begin
Add:=a+b;
end;
function Mult(a, b: integer): integer; far;
begin
Mult:=a+b;
end;
procedure MakeTable(w, h:integer; operation: func);
var
i, j:integer;
begin
write(‘ ‘);
for i:=1 to w do write(‘_ _ _ _ _ ‘);
writeln;
for i:=1 to h do begin
write(i: 5,’ | ‘);
for j:=1 to w do
write(operation(j, i): 5);
writeln;
end;
writeln; end;
begin
Make_table(10,10, Add);
Make_table(10,10, Mult);
end.
Два вызова процедуры MakeTable, которая строит таблицы, используя для вычисления в первом случае функцию Add, во втором – Mult.
Переменные процедурных типов можно передавать в качестве параметров подпрограммы.
Функции, возвращающие значения процедурных типов, не допускаются.
В общем случае использование процедурной переменной в операторе или выражении означает вызов присвоенной данной переменной процедуры или функции.
Одно исключение: если в левой части оператора присваивания стоит процедурная переменная, то правая часть должна быть идентификатором другой процедурной переменной или идентификатором подпрограммы.
Пример
type
IntFunc= function: integer;
var
f: IntFunc;
n: integer;
function ReadInt: integer; far;
var
i: integer;
begin
read(i);
ReadInt:=i;
end;
begin
f:= ReadInt; {присваивание значения процедуры}
n:= Readint; { присваивание результата функции}
end.
Первый оператор в основной программе присваивает значение процедуры Readint (её адрес) процедурной переменной F, второй вызывает функцию Readint и присваивает полученное значение переменной n. Полученные значения процедуры или вызов функции различаются по типу присваиваемой переменной(f или n).
Дополнение Директивы подпрограмм дают информацию о размещении подпрограмм.
-
FORWARD- директива заголовка подпрограммы описанной дальше по тексту.
-
FAR, NEAR- директивы формирования «дальнего» адреса и «ближнего» адреса.
-
EXTERNAL- директива внешней подпрограммы.
-
ASSEMBLER- директива подпрограммы, написанной на ассемблере.
-
INLINE- директива, позволяющая включить в программу часть, написанную на ассемблере.
-
INTERRUPT – директива процедуры обработки прерываний.
(См. пункт 10.5.
Епанишников А.М., Епанешников В.А. Программирование в среде Turbo -Pascal 7.0. М.: Диалог- МИФИ. 2001. -288 с.)