Передача параметров по имени и по значению 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Передача параметров по имени и по значению



Когда происходит обращение к подпрограмме, переменным, указанным в списке

параметров в описании (формальные параметры), присваиваются значения, ука-

занные в списке параметров в момент вызова (фактические параметры), после чего

5 О Урок 1. Язык Delphi (Object Pascal] и его использование

выполняются необходимые вычисления. Это называется передачей параметров по

значению: в подпрограмму передаются значения нужных типов. Формальные пере-

менные играют роль локальных переменных.

В списке параметров перед любой переменной разрешается указывать ключевое

слово var. Тогда считается, что данный параметр будет передаваться по имени: то

есть копирования значения не происходит, а вместо формального параметра под-

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

качестве фактических параметров, подставляемых вместо формальных параметров

с ключевым словом var, можно применять только имена переменных.)

Например:

procedure MyProc(X: Byte; var Y: Byte);

Параметр X будет передаваться по значению, параметр Y — по имени. При вызове

МуРгос(2+2, N);

операторы в теле процедуры MyProc будут обрабатывать локальную переменную X,

имеющую значение 4 (2+2), и переменную Y, которая на самом деле является пере-

менной N из другой части программы. На ≪физическом≫ уровне произойдет просто

подстановка адреса переменной N. Использование слова var в списке параметров

по способу действия аналогично использованию указателя.

При этом, если в теле процедуры значение переменной X будет меняться, то по

окончании работы MyProc эта локальная переменная будет удалена из памяти (до

следующего вызова процедуры), а вот если произойдет изменение значения пере-

менной Y, то изменится и значение переменной N.

Это потенциально чревато ошибками, так как разработчик может не рассчитывать

на то. что во время работы подпрограммы произойдет изменение значения одного

из ее парамегров. В данном случае переменная Y является не чем иным, как

указателем на переменную N, только описан он немного иначе: не с помощью опера-

ции Л, а как обычная переменная.

Следует избегать передачи параметров по имени за исключением случая, когда тре-

буется передать в подпрограмму данные большого объема. Например, если описан тип'

type TBigArray = array [1..100000] of string[50];

то передавать переменную этого типа по значению очень неэффективно, особенно

если вызов подпрограммы происходит часто, потому что при этом требуется копи-

ровать большие объемы данных. То есть описание

procedure Sum(A: TBigArray);

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

нить передачу параметра по имени в процессе автоматической оптимизации кода).

Правильнее написать так:

procedure Sum(var A: TBigArray);

При этом надо проследить, чтобы изменения элементов массива А внутри проце-

дуры Sum не происходило (если этого не требует логика ее работы).

Подпрограммы 57

Параметры-константы

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

считывания данных (фактически, как константа), лучше не рассчитывать на воз-

можности компилятора, а подсказать ему об этом явно. В этом случае присваива-

ние данному параметру нового значения станет недопустимым.

Подобная ≪подсказка≫ осуществляется указанием зарезервированного слова const

в списке параметров, что позволяет организовать эффективную обработку соот-

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

procedure Sum(const A; TBigArray),-

Менять значение элементов переменной А в теле процедуры Sum теперь нельзя:

компилятор сообщит об ошибке.

Параметры-результаты

В Паскале имеется еще одна возможность передачи параметра по имени — с помо-

щью зарезервированного слова out. Такой параметр может использоваться внутри

тела подпрограммы только для присваивания значения (но не для считывания дан-

ных). По смыслу использование слова out противоположно использованию слова

Const.

Если заголовок процедуры описан так:

procedure Sum(out A: TBigArray);

то в теле процедуры Sum можно указывать операторы присваивания

А[10000]:= 'rmml72855';

но нельзя считывать значения элементов массива А:

х:= А [ 2 ] * 2; // нельзя!

ПОДСКАЗКА Для получения результатов от подпрограммы всегда правильнее

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

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

этого не обойтись (например, параметры-результаты требуются

при создании приложений СОМ и CORBA),

Преобразования сложных типов

Ранее рассматривалась возможность явного преобразования типов путем использо-

вания названия нужного типа как функции (Byte(300)). Паскаль допускает подоб-

ный способ преобразования не только для базовых, но и для любых других типов,

определенных разработчиком.

ЗАМЕЧАНИЕ В Паскале не делается различий между базовыми типами, исходно

существующими в языке, и типами, созданными программистами.

58 ' Урок 1. Язык Delphi (Object Pascal] и его использование

Потребность в этом хоть и редко, но все же возникает. Например:

type T1 = аггау[1..2] of Byte;

var Al: Tl;

A2: array[1..2] of Byte;

Переменные _____Al и. A2 относятся к рачным типам, хотя физически (в оперативной

памяти) они представлены одииаково. Поэтому переменную А2, обычный массив,

можно преобразовать (привести) к типу Т1:

Т1(А2)

Такая запись аналогична простому обращению к имени массива А2, только при

этом считается, что он имеет новый тип Tl. К элементам массива нового типа можно

обращаться, как и раньше, с помощью квадратных скобок:

Т1(А2)[1]

Параметры без типов

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

с предшествующим словом const, var или out).

procedure Surn(const A);

Переменная А в таком случае считается не имеющей никакого типа, и ее нельзя

использовать ни в каких выражениях или операторах, не выполнив предварительно

преобразование — приведение к нужному типу.

Например, в теле процедуры Sum переменную А можно использовать так:

X:= Т1 (А) [5] * 2,-

-

Передача строк фиксированной длины

Строки можно описывать, как уже говорилось ранее, двумя способами: просто как

тип string, или как тип string с конкретной длиной строки в квадратных скобках.

Однако указывать строки фиксированной длины в качестве параметров подпро-

грамм нельзя. Их сначала надо описать как новый тип.

procedure Sum(S: string[50]); // неверно!

Правильно написать так:

type stringSO = string[50];

procedure Sum(S: stringSO };

Передача массивов в качестве параметров

Стандартный прием Паскаля состоит в описании массива как типа данных и ука-

зании этого типа для параметра подпрограммы. Однако таким способом удается

обрабатывать только динамические массивы и статические массивы заранее задан-

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

размерами массива. Например, функция, вычисляющая сумму всех элементов мас-

сива, должна уметь получать в качестве параметра массив любой длины. Динами-

Подпрограммы 59

ческие массивы использовать не всегда удобно и не всегда правильно, так как они

ухудшают эффективность работы программы.

В Паскале разрешается указывать в качестве параметров массив с неопределенными

границами.

procedure Sum(A: array of Byte);

ВНИМАНИЕ Данное описание похоже но описание динамического массива, но

не является токовым. Это просто форма записи параметра подпро-

граммы для передачи статического массива заранее не известной

длины.

Теперь массив, описанный как

var Ar: array [1..25] of Byte;

можно без проблем передавать в процедуру Sum:

Sum(Ar];

При этом внутри тела подпрограммы действуют следующие правила:

О Нумерация элементов массива начинается с нуля (число элементов можно

определить с помощью стандартной функции SizeOf);

О Функция High возвращает верхнюю границу массива (равную SizeOf()-l);

О Копирование массива одним оператором присваивания не разрешается;

О Вместо массива в подпрограмму может быть передана обычная переменная

соответствующего типа. Внутри подпрограммы она будет представлена в

виде массива из одного элемента (с индексом 0).

Передача значений как массива

Вместо указания в параметрах при обращении к подпрограмме имени переменной-

массива можно указать непосредственно содержимое этого массива: список значе-

ний через запятую в квадратных скобках.

Sum([1, 5, X, а+Ь'2]);

Передача массива вариантного типа

-

Массив, описанный как

array [L.MaxNum] of Variant;

может быть передан в качестве параметра в подпро]рамму, если этот параметр опи-

сан как array of const:

procedure Sum(A; array of const };

Внутри тела подпрограммы надо анализировать перед обработкой тип каждого эле-

мента этого массива.

60 Урок 1. Язык Delphi [Object Pascal) и его использование

Способы вызова подпрограмм

•Подпрограммы с точки зрения прикладного программиста вызываются всегда оди-

наково, но машинный код, который создается компилятором, для разных подпро-

грамм может отличаться. Это зависит от целей применения конкретной подпро-

граммы. Она может использоваться:

О в рамках разрабатываемой прикладной программы;

О как функция, доступная из динамической библиотеки.DLL;

О как процедура, вызываемая из внешних программ или из Windows и т. д.

Для каждого из таких нестандартных случаев вслед за заголовком подпрограммы

(за точкой с запятой) должно следовать одно из ключевых слов.

Таблица 1.10. Ключевые слова в заголовке подпрограмм

Ключевое слово Способ передачи параметров

pascal Стандартный (параметры помещаются в стек)

register Способ, применяемый по умолчанию. Аналогичен использованию ключевого

слова pascal, но параметры передаются с помощью трех регистров

процессора, а не помещаются в стек (область оперативной памяти),

что обычно приводит к повышению быстродействия программы

cdecL В соответствии с соглашениями компиляторов для языков программирования

С и C++. Применяется, когда происходит обращение к динамическим

библиотекам DLL, написанным на этих языках

stdcall В соответствии с соглашениями Windows

safecall Используется при работе с компонентными технологиями

При использовании ключевых слов register и pascal вычисление параметров выпол-

няется слева направо и располагаются они в оперативной памяти перед вызовом

подпрограммы в таком же порядке. При использовании ключевых слов cdecL, stdcall

и safecall параметры располагаются в обратном порядке (справа налево).

procedure Sum(A: array of const ); stdcall;

Существует еще одно зарезервированное слово Паскаля, forward, которое, при ука-

зании вслед за заголовком, говорит компилятору о том, что в данном месте распо-

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

тексте далее. Такое описание обычно применяют, если в тексте имеется несколько

подпрограмм, которые вызывают друг друга по кругу. Например, из процедуры Р1

вызывается процедура Р2, а из процедуры Р2 — процедура Р1.

Паскаль требует, чтобы любой идентификатор, будь то переменная или подпро-

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

говом процессе (пример условный, потому что приведенная схема может приве-

сти к бесконечной цепочке вызовов) процедура Р2, вызываемая в теле процедуры Р1,

расположенной выше в исходном тексте, еще не описана, следовательно, обращаться

к ней нельзя и компилятор сообщит, что обнаружен неопределенный идентифи-

катор.

Подпрограммы 61

Неправильно:

procedure PI;

Begin

P2;

end;

procedure P2;

Begin

PI;

end,-

Правильно:

procedure P2; forward;

procedure PI;

begin

P2;

end;

procedure P2;

Begin

PI;

end,-

Теперь компилятор знает, как выглядит заголовок процедуры Р2, и может корректно

сгенерировать машинный код для обращения к ней.

'1 ПОДСКАЗКА Без таких запутанных круговых ссылок и ключевого слова forward

всегда можно обойтись. Лучше не усложнять структуру программы

его использованием.

Перегружаемые подпрограммы

Хотя в Паскале не допускается использование одинаковых названий для пере-

менных, констант и других идентификаторов, для локальных переменных и под-

программ делается исключение. Так как в Паскале предъявляются строгие требова-

ния к типам данных, обращаться к подпрограмме, формальные параметры которой

имеют тип Integer, с фактическими параметрами, имеющими тип Real, нельзя. Однако

при решении задачи подчас бывает необходимо, чтобы подпрограмма с одним и

тем же именем работала с разными типами данных.

Здесь есть два способа действий: либо использовать данные типа Variant (что чре-

вато ошибками преобразования, снижает общую эффективность программы и тре-

бует от разработчика повышенной бдительности), либо применить перегружае-

мые подпрограммы. Они отличаются от обычных подпрограмм тем, что имеют

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

пилятору, что конкретная подпрограмма — перегружаемая, надо вслед за ее заго-

ловком указать зарезервированное слово overload.

62 Урок 1. Язык Delphi (Object Pascalj и его использование

При вызове такой подпрограммы компилятор по типам параметров автоматически

определит, какую же подпрограмму конкретно надо использовать в данном месте.

procedure Ovl (X: Real),- overload;

begin

end;

procedure Ovl (X: Byte),- overload;

Begin

and;

Ovlf 1); // вызывается процедура Ovl(X: Byte)

Ovl(1.0); // вызывается процедура Ovlf X: Real)

Необходимое требование к перегружаемым процедурам состоит в том, чтобы списки

параметров совпадали во всем, за исключением типов переменных.

Надо особенно осторожно использовать перегружаемые подпрограммы с парамет-

рами по умолчанию. Например:

procedure Ovl(X: Byte; Y: Real - 1); overload;

Begin

.

end;

procedure Ovl (X: Byte),- overload;

Begin

end;

При вызове

Ovl(1)

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

об ошибке.

Локальное описание

Сразу за заголовком подпрограммы следует локальное описание типов, переменных и

констант, локальных для данной подпрограммы и существующих только в ее грани-

цах. Такое описание подчиняется обычным правилам Паскаля. В нем разрешается

использовать слова type, var и const. Локальное описание может быть опущено.

Вложенные подпрограммы

Помимо обычных описаний, внутри подпрограммы допускается объявлять также

локальные подпрограммы, к которым можно обращаться (вызывать) только из тела

≪родительской≫ подпрограммы. При этом локальная подпрограмма может свободно

Подпрограммы 63

обращаться к любым локальным описаниям (переменным, типам), которые рас-

положены до описания данной подпрограммы.

Такая возможность полезна, когда во время кодирования подпрограмма начинает

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

которые в то же время желательно не выносить за пределы текущей подпрограммы,

чтобы иметь возможность пользоваться ранее сделанными локальными описаниями.

Например:

procedure Demo;

type Tl = array [1..2] of Real;

var D, Dl: Tl;

S: Real;

procedure InDemo;

begin

Dl:= D;

S:= Dl[l] + Dl[2]

end;

Begin

end;

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

Тело подпрограммы

Тело подпрограммы заключается в логические скобки begin/end. В них располага-

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

Возврат значений из функции

Если описывается функция, то в ее теле надо определить, как значение будет воз-

вращено в вызываемую программу. Для этого есть два способа.

1. Соответствующее значение присваивается переменной, имя которой совпадает

с названием функции.

function Sum(А, В: Integer): Integer;

begin

Sum:= A + В

end;

Имя функции для возврата значения разрешается указывать только в левой

части оператора присваивания.

2. Соответствующее значение присваивается специальной локальной перемен-

ной Result (эту переменную описывать не надо).

64 Урок 1. Язык Delphi (Object Pascal) и его использование

function Sumf А, В: Integer): Integer;

begin

Result:= A + В

end,-

Вызов подпрограммы

Когда в тексте программы указывается имя ранее описанной подпрограммы с фак-

тическими параметрами, то выполнение основной части программы останавлива-

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

достигнут ее конец (зарезервированное слово end). После этого управление пере-

дается обратно в программу (или другую подпрограмму), вызывавшую данную

подпрограмму.

Параметры должны следовать в "строгом соогветствии с порядком их описания в

заголовке подпрограммы. Типы их так же должны точно совпадать с указанными.

Если параметров у подпрограммы нет, то записывается только название подпро-

граммы и следующая за ней точка с запятой.

Demo;

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

Например, описанную выше функцию Sum можно вызывать так:

X:= Sumf 2,2);

а можно и так:

Sum(2,2);

Б последнем случае значение, возвращаемое функцией, просто теряется.__

17. Процедурные типы данных.(указатель на код)



Поделиться:


Последнее изменение этой страницы: 2017-02-21; просмотров: 252; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.141.30.162 (0.153 с.)