Способы передачи параметров в подпрограммы 


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



ЗНАЕТЕ ЛИ ВЫ?

Способы передачи параметров в подпрограммы



Существует два способа передачи параметров в подпрограммы – передача по значению и передача по наименованию. Способ передачи указывается при объявлении параметра в списке формальных параметров.

По умолчанию предполагается, что параметры обычных типов, например, Real, Integer, String, передаются по значению, а параметры таких типов как визуальные компоненты, динамические массивы передаются по наименованию. Если возникает необходимость явно указать, что параметр передается по наименованию, то перед именем параметра, или перечнем имен одного типа, пишется слово var.

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

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

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

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

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

При передаче параметров по наименованию в подпрограмму передаются адреса фактических параметров. Поэтому такой способ передачи называется еще передачей параметров по адресу или по ссылке.

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

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

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

Выше, в пункте 3.1.1 уже рассматривался пример процедуры с передачей параметра по наименованию.

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

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

Procedure getKoef (var kA, kB, kC:Real);

Begin

kA:=strToFloat(frmSubroutine.edtA.Text);

kB:=strToFloat(frmSubroutine.edtB.Text);

kC:=strToFloat(frmSubroutine.edtC.Text);

end;

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

Обращение к этой процедуре происходит в другой процедуре, которая обрабатывает событие onClick кнопки «Расчет по формуле». Фрагмент этой процедуры приведен ниже.

До вызова процедуры значения переменных a, b, c были неопределенными (мусор). При вызове процедуры getKoef адреса этих переменных были переданы в качестве фактических параметров. При выполнении процедуры, по этим адресам были записаны результаты преобразования данных. В результате, после окончания работы процедуры getKoef переменные a, b, c приобрели новые значения, которые были вычислены в процедуре

procedure TfrmSubroutine.btnCalculateRootsClick(Sender: TObject);

var a, b, c:Real;

Begin

// До вызова процедуры getKoefKvUr

// значения переменных a,b,c не определены

getKoef(a,b,c);

// После вызова процедуры значения переменных

// a,b,c соответствуют содержиммому тектовых полей

end;

 

Расположение подпрограмм

Подпрограммы могут располагаться в самых разных местах. Место расположения программы не влияет на ее работу, но от этого зависит доступность (видимость) подпрограммы. Ниже рассматриваются варианты расположения подпрограмм и обсуждаются особенности их использования, зависящие от расположения подпрограммы.

3.1.3.1 Подпрограммы обработки событий класса формы

В ранее рассмотренных примерах мы уже имели дело с такими подпрограммами.

Подпрограммы, относящимися к классу формы, объявляются в описании класса в разделе interface, а располагаются в разделе implementation модуля.

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

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

Одна и та же процедура обработки события может быть связана с событиями нескольких объектов. В этих случаях, для того, чтобы получить доступ к объекту, вызвавшему процедуру, можно использовать ссылку на этот объект, которая передается в процедуру в виде параметра Sender. Чтобы получить доступ к объекту, нужно привести эту ссылку к соответствующему классу, например, таким образом – TButton(Sender).

3.1.3.2 Другие подпрограммы класса формы

Класс формы может содержать не только процедуры обработки событий, но и другие подпрограммы. Обычно эти подпрограммы как-то связаны с компонентами формы, и расположение подпрограммы в классе формы упрощает доступ к ее компонентам. Эти подпрограммы отличаются от процедур обработки событий только тем, что программист сам должен вводить объявления подпрограмм, кроме того, эти объявления могут располагаться только в разделах private или public описания класса формы. Сама же процедура будет размещаться в разделе implementation.

После объявления подпрограммы можно автоматически сформировать шаблон подпрограммы в разделе implementation модуля, нажав комбинацию клавиш <Ctrl+Shift+C>. Для перемещения между описанием и объявлением подпрограммы класса можно использовать комбинации клавиш <Ctrl+Shift+↑> и <Ctrl+Shift+↓>.

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

3.1.3.3 Размещение подпрограмм в модуле

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

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

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

Если в подпрограмме модуля, не принадлежащей к классу формы, приходится обращаться к компонентам формы, то при таких обращениях пред именем компонента следует указывать имя формы, например, Form1.Edit1.text.

3.1.3.4 Размещение подпрограмм в других модулях

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

Мы уже видели, что часто используемые алгебраические и тригонометрические функции описаны в модуле System, другие математические процедуры описаны в модуле Math.

Описания таких процедур располагаются в разделе реализации модуля (implementation), но для того, чтобы процедура была доступна в других модулях, необходимо объявить процедуру в разделе interface, продублировав там заголовок процедуры.

3.1.3.5 Размещение подпрограмм внутри других подпрограмм

Как уже упоминалось выше, в разделе описаний подпрограммы могут быть описаны другие подпрограммы. Такие подпрограммы называются внутренними по отношению к подпрограмме, в которой они описаны. Сама процедура, по отношению к внутренним подпрограммам называется внешней.

Область действия имен

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

Если имя константы, переменной, подпрограммы или другого элемента программы объявлено в интерфейсной части модуля, то оно доступно не только в данном модуле, но и во всех других модулях, которые в инструкции uses имеют ссылку на данный модуль.

Если имя объявлено в разделе implementation модуля, то оно доступно только процедурам и функциям данного модуля.

Если имя объявлено в разделе описаний некоторой процедуры, то это имя доступно только в пределах данной процедуры. Такие имена иногда называют локальными. Достоинство локальных объявлений в том, что в различных процедурах могут использоваться одинаковые имена, и эти имена не будут конфликтовать.

Рисунок 3.2 – Вложенные процедуры

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

На рисунке 3.2 схематично показаны три процедуры. Процедура «с» описана в процедуре «b», которая, в свою очередь, описана в процедуре «а». Переменная «i», объявленная в процедуре «b», доступна и в процедуре «c», но недоступна (невидима) в процедуре «a».

3.2 Реализация проекта «Процедуры и функции»

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

Откройте новый проект. Удалите появившуюся форму и загрузите в проект модуль формы из проекта для предыдущей работы. Переименуйте модуль, дав ему имя, например UnitSubroutine. Слово Subroutine переводится с английского языка как подпрограмма. Теперь можно работать с этим модулем как с новым.

Форму переименуйте и назовите frmSubroutine. В заголовке напишите текст «Процедуры и функции».

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

Рисунок 3.3 – Интерфейс проекта «Процедуры и функции»

Создание процедур и функций

3.2.1.1 Процедуры инициализации

Процедуру очистки протокола можно оставить такой же, как в предыдущей работе, а так как модуль формы скопирован, то она у нас есть. В любом случае процедура будет соответствовать рисунку 3.4.

Рисунок 3.4 – Процедура очистки протокола

Что касается процедуры инициализации формы, то мы ее переделаем,

Прежде всего, создадим процедуру setKoef(), которая обеспечит установку начальных значений в поля ввода для переменных «а», «x» и «n», входящих в формулу. Параметрами, передаваемыми в процедуру, будут числовые значения этих переменных. В процедуре числа будут преобразовываться в строки, и заноситься в соответствующие компоненты TEdit. Такое преобразование целесообразно, так как в этом случае десятичный разделитель для дробных чисел будет установлен правильно при любой настройке системы.

Так как в этой процедуре мы будем обращаться к компонентам формы edtA, edtB, edtC, а процедура не принадлежит классу формы, то в ней перед именами компонент обязательно следует указывать имя формы, разделяя эти имена точкой.

Другой способ решения этой проблемы состоит в использовании конструкции with … do, с помощью которой имя формы выносится как бы за операторные скобки begin … end. Именно эта конструкция используется в процедуре setKoef(), показанной на рисунке 3.5.

Рисунок 3.5 – Процедура для инициализации полей ввода значений переменных, входящих в формулу

Теперь можно создать процедуру инициализации формы, связанную с событием onCreate. С помощью этой процедуры мы обеспечим очистку поля Memo и заполнение текстовых полей корректными исходными данными. Это ускорит отладку и проверку работоспособности программы.

В этой процедуре, представленной на рисунке 3.6, вначале имитируется нажатие кнопки «Очистить протокол», что приводит к вызову соответствующей процедуры.

Вторая строка тела процедуры вызывает процедуру setKoef(), в которую передаются значения переменных. Эти значения появятся в полях edtA, edtB, edtC.

Рисунок 3.6 – Процедура инициализации формы

3.2.1.2 Процедура считывания коэффициентов уравнения

Для расчета по формуле необходимо прочитать значения переменных из компонентов TEdit и преобразовать их в вещественные числа.

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

Рисунок 3.7 – Процедура считывания значений коэффициентов уравнения

3.2.1.3 Функция для расчета по формуле

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

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

Кроме того, расчет по этой формуле может понадобиться и в других приложениях.

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

Поэтому, для расчетов по формуле мы напишем функцию, которая не будет иметь отношения к форме.

Исходными данными для расчета по формуле являются вещественные числа a, x, n. Результатом – тоже вещественное число.

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

function myFormula1(a, x, n:real): real;

var ch, q, zn,

Begin

ch:=exp(x*ln(a))+sqr(sin(x)); //числитель формулы

q:=x*(n*a+a)/n/a; //подкоренное выражение

zn:= exp(ln(q)/n); //знаменатель формулы

result:= ch/zn;

end;

Эту функцию для расчета по формуле поместим в отдельном модуле.

Добавьте новый модуль в проект, воспользовавшись функцией главного меню File→New→Unit.

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

Сохраните модуль в той же папке, что и модуль формы проекта (хотя это и не обязательно), присвоив ему имя UnitDop.

Откомпилируйте модуль, вызвав функцию главного меню Project→CompilePtoject.

Посмотрите содержимое папки, где вы сохранили модуль. Там должен появиться файл UnitDop.dcu, который содержит откомпилированный модуль. Если это так, то модуль готов к употреблению.

Рисунок 3.8 – Функция расчета по формуле в дополнительном модуле

3.2.1.4 Использование дополнительного модуля

Для того, чтобы в основном модуле можно было воспользоваться функцией расположенной в дополнительном модуле, следует, прежде всего, дополнить инструкцию uses основного модуля, добавив туда ссылку на модуль UnitDop.

Обрабатывая инструкцию uses, компилятор дойдет до ссылки на модуль UnitDop и начнет искать файл UnitDop.dcu. Прежде всего, поиск будет производиться в папке, где расположен проект и форма, но если там модуля нет, то компилятору необходимо подсказать, где искать этот файл.

В этом случае ызовите диалог настройки путей, вызвав функцию главного меню Project→Options, откройте в нем закладку Directories/Conditionals, и в строке Search Path укажите путь к папке, где расположен модуль.

3.2.1.5 Завершение работы над проектом

Для проверки работоспособности процедуры ввода коэффициентов и функции расчета по формуле, описанной в дополнительном модуле, напишем процедуру обработки события onClick для кнопки «Выполнить расчет. Процедура представлена на рисунке 3.9.

Рисунок 3.9 – Главная процедура с вызовом вспомогательной процедуры и функции

3.3 Исследование созданного приложения



Поделиться:


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

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