Параметры. Глобальные и локальные описания

При введении в программу подпрограммы возникает разделение данных и их типов на глобальные и локальные.

Глобальными по отношению к данному блоку являются объекты верхнего уровня, описанные до появления данного блока.

Локальные объекты – объекты, существующие внутри данного блока. Объявлены либо в списке параметров (только переменные), либо в разделах CONST, VAR, TYPE, внутри подпрограммы.

Для программистов, использующих обращение к блоку, блок представляется как «черный ящик», в котором реализуется тот или иной алгоритм. В примере, рассмотренном нами, из основной программы можно обратиться к процедурам А, В, С, но нельзя вызвать А1, А2, В1, В2. Образно говоря, блок как бы окружен полупрозрачными стенками, снаружи не видно, что делается внутри, но попав в блок можно увидеть, что делается вне его, но только «сверху», а не «снизу». Так, из блока В21 можно обратиться к В2 , В1, В, а, к основной программе.

При совпадении глобальных и локальных имен сильнее оказывается локальное имя, и именно оно используется внутри подпрограммы. Существует неписанное правило: если блок содержит цикл FOR, то параметры должны быть описаны как локальные переменные. Это предотвратит неразбериху при циклическом вызове процедур.

Процедуры

Процедура состоит из заголовка и тела.

Заголовок: PROCEDURE (ИМЯ) [(список формальных параметров)]

(имя – имя процедуры (правильный идентификатор)

(список формальных параметров) - список формальных параметров (может отсутствовать)

Затем идут те же разделы, что и в основной программе. Завершается «;».

Пример. Процедура ввода N целых чисел.

Пусть в основной программе определен TYPE и VAR

TYPE

arr:=array[1…10]of integer;

VAR

m:arr;

k:integer;

Процедура может иметь вид:

{заголовок}

PROCEDURE INPINT (var mas :arr; n: integer);

Var

i:integer; (локальный параметр процедуры)

Begin

Writeln (‘Введите’, n:3,‘целых чисел’);

For i:=1 to n do

read (mas[i])

End;

Синтаксис вызова процедур прост: выполнение активизируется указанием ее имени и списком var или значений, подставляемых на место формальных параметров (фактические параметры):

<имя процедуры> (параметр 1, параметр 2,…….);

K:=40;

Inpint (m,k); или inpint (m,40);

Вызывается процедура input для ввода 40 целых чисел в массив М.

Параметры, описываемые в заголовке подпрограммы, являются по сути локальными переменными. Но, кроме того, они обеспечивают обмен значениями между вызывающими и вызываемыми программами. Описываемые в заголовке параметры называются формальными, а те которые подставляются на их место при вызове – фактическими, т.к. замещают все вхождения в подпрограмму своих формальных «двойников». Между формальными и фактическими параметрами должно быть полное соответствие:

- одинаковое количество;

- один и тот же порядок следования;

- тип фактических параметров должен совпадать с типом формальных параметров.

Пример. Программа подсчитывает количество точек (.) в первой вводимой с терминала строке, а во второй строке – количество букв «А».

Program A;

Const

Point=‘.’;

Var

S:=integer;

Procedure P (simb:char; var kol:integer);

Var

C:char;

begin

Kol:=0;

Writeln (‘Введите строку’);

Repeat

Read (c);

If c=simb then inc(kol);

Until eoln

end;

Begin

P(point,s);

Writeln (‘Количество точек=’,s:3);

P(‘A’,s);

Writeln (‘Количество букв «А»=’,s:3);

end.

Процедура имеет два формальных параметра:

· simb - входной параметр (параметр-значение), определяет символ, который подсчитывается в строке;

· kol – выходной параметр (параметр-переменная), через который передается в программу количество подсчитанных символов.

Таким образом мы столкнулись с двумя видами параметров:

· параметр-переменная;

· параметр-значение.

Параметры-значения – локальные переменные подпрограммы, стартовые значения которых задаются при вызове подпрограммы из внешних блоков. Параметры значения могут изменять свои значения, как и другие переменные, но эти изменения никак не передаются в вызывающую программу. Для того, чтобы подпрограмма изменяла значение переданной переменной, нужно объявлять соответствующие параметры, как параметры-переменные, вставляя слово var перед описанием в заголовке.

Рассмотрим внутренний механизм передачи параметров в подпрограмму.

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

По-другому организуются параметры-переменные. Вместо копий значения подпрограмма получает разрешение работать с тем местом, где постоянно (т.е. во время работы самого вызывающего блока ) хранится значение переменной, указанной в вызове. Все действия с параметром-переменной в подпрограмме на самом деле являются действиями над поставленной в вызове переменной. В этом заключается причина того, что на место параметров-значений можно подставлять непосредственно значения, а на местах параметров переменных могут быть только идентификаторы переменных.

Процедура Р может передавать результат своей работы через глобальную переменную S:

Procedure P(simb:char);

If c=simb then s:=s+1;

S:=0; P(point);

……………………………….

S:=0; P(‘A’);

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

Функции

Описание функции в основном аналогично описанию процедуры. Однако, имеются два отличия.

Первое - результатом работы функции является одно скалярное значение или одно значение ссылочного типа. Тип результата задается в заголовке функции.

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

Общий вид:

Function <имя> [(список фактических параметров)] :<тип>;

< тип> тип возвращаемого функцией результата.

Пример. Функция принимает любое число и возвращает его квадрат. Если значение квалрата больше 100, то оно считается равным 100. При этом устанавливается глобальный «флаг».

Var

glflag:boolen: {глобальный флаг}

Function getsqr (x:real):real;

Const

sqrmax=100; {локальная const}

begin

X:=x*x; {вычисление квадрата}

Glflag := (x>sqrmax); {результат сравнения в глобальный флаг]

If glflag then x:= sqrmax {ограничение x}

Getsqr :=x {возвращает значение}

end;

Begin {основной вызывающий блок}

Writeln (getsqr (6):7:2, ‘флаг:’, glflag)

End.

При объявлении формальных параметров в <списке формальных параметров>, тип любого параметра может быть только стандартным или ранее объявленным, потому, что нельзя объявить:

Procedure S(a:array[1…10] of real);

Проблема решается так:

Type

Atype = array [1..10] of real

Procedure S (a:atype)

В блок передается весь массив.

Процедура EXIT

GOTO нельзя использовать для досрочного выхода из подпрограммы. В Т-П для этой цели используется процедура EXIT.

Пример. Функция, определяющее первое отрицательное число в массиве.

Type

Arr_=array [1..100] of real;

Var

Ar:arr_

Function minus (var mas:arr_; N:integer):real;

Var

I:integer;

Begin

Minus :=0;

For i:=1 to n do

If mas[i]<0 then

Begin

Minus:=mas[i];

Exit

End;

End;

Begin

Writeln (‘Первое отрицательное число в массиве=’, minus(ar,50):7:2);

End.

Рекурсия

Использование рекурсии – преимущество Т-П. Под рекурсией понимается вызов функции (процедуры) из тела самой функции (процедуры)

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

В ряде случаев рекурсивное оформление более компактно и эффективно.

Пример. Вариант функции вычисляющей факториал числа N.

Function fact (n:integer):longint;

Begin

If n in[0..1] then fact:=1

else

fact :=n*fact (n-1)

End;

Если в функцию передается n>0, то происходит следующее:

· запоминаются известные значения членов выражения;

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

Так происходит до тех пор, пока выражение не станет полностью определенным (ветвь then). После чего алгоритм начинает «раскручиваться» в другую сторону, изымая из памяти «отложенные значения. При этом на каждом очередном шаге все члены выражения будут известны через n обратных шагов, получили результат.

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

Директивы подпрограмм

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

Директива FORWARD

Если одна подпрограмма использует другую, а та в свою очередь первую, то возникает проблема размещения таких подпрограмм в программе. Текст программы транслируется последовательно сверху вниз. При этом const, type, var должны быть определены до того, как начнутся их упоминания в операторах. В противном случае компилятор объявит их неизвестными. Проблема решается следующим образом:

Procedure <имя процедуры> (параметры); forward;

Function <имя функции> (параметры) : тип значения; forward;

Procedure <имя процедуры> ; {только имя}

{Тело процедуры}

Function <имя функции>; {только имя}

{Тело функции}

Открытые массивы

В Т-П имеется возможность передавать в подпрограмму массивы, размер которых не фиксируется в объявлении подпрограммы.

Function sum1 (var a:array of byte):byte;

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

Подпрограмма, содержащая открытый массив в списке своих формальных параметров, может быть вызвана с массивом любого размера (типы фактических параметров должны совпадать).

Наши рекомендации