Ситкин. Информатика. Программирование в DELPHI
.pdfдля формальных параметров. Важно запомнить: списки фактических и формальных параметров должны быть согласованы между собой по числу, порядку следования и типу значений.
Параметры подпрограмм можно разделить на входные, которые передают значения в подпрограмму и выходные, которые передают результаты её работы обратно в вызывающий блок. Входные пара-
метры это параметры-значения. По умолчанию все параметры па-
раметры-значения. Они передают значения в подпрограмму, могут там изменяться, но обратно в вызывающий блок изменения не пере-
даются. Выходные параметры это параметры-переменные. Они мо-
гут передавать значения в подпрограмму, могут там изменяться и мо-
гут передавать изменения обратно в вызывающий блок. Перед соот-
ветствующим формальным параметром в заголовке подпрограммы нужно поставить слово var, например,
procedure My_Procedure(x, y: real; var z: real);
здесь x и y параметры-значения, а z параметр-переменная, или procedure My_Procedure(var x, y: real; z: real);
здесь уже x и y параметры-переменные, а z параметр-значение.
Поскольку параметр-переменная способен передавать значения в обе стороны, возникает соблазн во избежание путаницы «что куда передаёт» все формальные параметры сделать таковыми
procedure My_Procedure(var x, y, z: real);
но параметр-переменная (в отличие от параметра-значения) не может передать в подпрограмму выражение или константу, а только отдель-
ную переменную. Кроме того, передавая значение в подпрограмму через параметр-переменную, и возвращая значение обратно через не-
го же, следует помнить, что старое значение будет потеряно.
41
Функция возвращает значение в вызывающий блок через своё имя, поэтому в описании функции параметры-переменные не вводят
(исключения составляют случаи, когда функция должна вернуть бо-
лее одного значения, т.к. к её имени можно привязать только одно).
Имя процедуры не является носителем значения, поэтому, если про-
цедура должны вернуть в вызывающий блок значение, то вводят па-
раметр-переменную, если должна вернуть два значения, то вводят два параметра-переменных и т.д. Также значение в вызывающий блок можно вернуть из подпрограммы через глобальную переменную.
Пример 3.1
Разработаем проекты для вычисления значения выражения
z a |
x2 |
5 |
a2 |
y2 5 |
|
( y 2) |
2 5 |
, |
|||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||
|
|
x |
|
5 |
|
|
y |
|
5 |
|
|
y 2 |
|
5 |
|||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
где x и y переменные, a константа с использованием подпрограмм.
В выражении видны повторяющиеся действия, выполняемые в дробях: в первой дроби над переменной x, во второй над перемен-
ной y и в третьей над выражением y 2. Чтобы многократно не про-
писывать в программном коде одни и те же действия, но для разных величин, целесообразно разработать подпрограмму. Она будет вы-
полнять типовое для данного выражения действие, а именно вычис-
лять значение дроби вида (t2+5)/( t +5), где t некоторый формаль-
ный (абстрактный) параметр, который показывает, что должно быть выполнено над подставленным в подпрограмму реальным, т.е. факти-
ческим параметром. Трижды вызвав подпрограмму с фактическими параметрами x, затем y, затем y 2, вычислим значения трёх дробей.
42
На рис. 3.1 и 3.2 представлены блок-схемы алгоритмов выпол-
нения типового действия и основного вычисления соответственно.
начало |
начало |
1 |
|||||||
|
|
|
|
|
|
|
a=3 |
|
|
c = 5 |
|
z=az1+a2z2 +z3 |
|||||||
|
|
|
|
|
|
|
ввод x, y |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
t1 = t2+c |
|
вычисление |
|
вывод z |
|||||
|
значения z1 |
|
|||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
конец |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
c |
|
вычисление |
|
|
t2 = |
|
t |
|
|
|
||||
|
|
|
|
||||||
|
|
|
значения z2 |
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
d=t1/t2 |
|
вычисление |
|
|
|||||
|
значения z3 |
|
|
||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
конец |
1 |
|
|
||||||
Рис. 3.1 |
|
Рис. 3.2 |
Реализуем разработанные алгоритмы в проекте. Форму с компо-
нентами и событие, связанное с расчётом, оставим теми же, как и в предыдущей работе. Оформим нашу пользовательскую подпрограмму сначала как функцию, прописав её в модуле проекта после слова implementation, но до процедуры обработки события. А в этой про-
цедуре процессы вычисления трёх дробей опишем не как в предыду-
щей работе, а трижды вызвав функцию. Назовем её, например, «drob». Значение дроби, которое будет вычислять функция, относится к вещественному типу, как и формальный параметр t, поэтому в заго-
ловке функции укажем вещественный тип для t и для значения, выра-
батываемого функцией (в конце заголовка), например, «real».
43
implementation
{$R *.dfm}
function drob(t:real):real; //заголовок пользовательской функции const c=5; //объявление локальной константы
var t1, t2:real; //объявление локальных переменных
begin //начало раздела операторов пользовательской функции t1:=sqr(t)+c; //промежуточные расчёты внутри функции t2:=sqrt(abs(t))+c; //промежуточные расчёты внутри функции drob:=t1/t2; //присвоение имени функции значения (результата)
end; //конец пользовательской функции
procedure TForm1.Button1Click(Sender: TObject);
const a=3;
var x, y, z, z1, z2, z3:real;
begin
x:=StrToFloat(Edit1.Text); // считывание значения x из Edit1
y:=StrToFloat(Edit2.Text); //считывание значения y из Edit2
z1:=drob(x); //вызовы функции и
z2:=drob(y); |
//присвоение её значений |
z3:=drob(y-2); //промежуточным переменным
z:=a*z1+sqr(a)*z2+z3; //итоговые вычисления
Label3.Caption:='z='+ FloatToStr(z); //вывод значения z в Label3
end; //конец процедуры обработки события
end. //конец модуля проекта
Имя функции носитель значения, в данном случае это число. Умно-
жить одно число на другое или сложить их допустимо, поэтому мож-
но было сразу записать z:=a*drob(x)+sqr(a)*drob(y)+drob(y-2);.
Оформим теперь нашу подпрограмму как процедуру.
44
implementation
{$R *.dfm}
procedure drob(t:real; var d:real); //добавлен параметр-переменная d
const c=5;
var t1, t2:real;
begin
t1:=sqr(t)+c;
t2:=sqrt(abs(t))+c;
d:=t1/t2; //результат присваивается теперь параметру-переменной d
end;
procedure TForm1.Button1Click(Sender: TObject); const a=3;
var x, y, z, z1, z2, z3:real;
begin
x:=StrToFloat(Edit1.Text);
y:=StrToFloat(Edit2.Text);
drob(x, z1); //вызовы процедуры отдельными операторами drob(y, z2); //без операторов присвоения, т.к. имя процедуры drob(y-2, z3); //не несёт в себе значения (в данном случае числа)
z:=a*z1+sqr(a)*z2+z3; Label3.Caption:='z='+ FloatToStr(z);
end;
end.
Отметим отличия в описаниях, все они вытекают из главного отличия процедуры от функции: с именем процедуры не связывается значение, её имя не является носителем значения. Во-первых, в заго-
ловке нашей подпрограммы не указан тип значения, вырабатываемого
45
процедурой. Введён второй формальный параметр d как параметр-
переменная (перед ним стоит var) для передачи результатов работы процедуры в вызывающий блок, т.к. через имя процедуры его не пе-
редать (результат присвоен параметру d, а не drob). Во-вторых, вызов drob осуществляется отдельным оператором без присвоений значений промежуточным переменным. Фактических параметров стало два, как стало и формальных. Теперь результат работы подпрограммы (число)
содержится не в имени drob (как было с функцией), а в параметре zi.
Запись вида «z:=a*drob(x, z1) + sqr(a)*drob(y, z2) + drob(y-2, z3);» или
«z1:=drob(x);» теперь будут ошибками.
Задание
Разработать два проекта для вычисления значения выражения предыдущей лабораторной работы с использованием функции и с ис-
пользованием процедуры.
Содержание отчёта
цель работы и задание (с исходным выражением);
блок-схемы алгоритмов вычисления значения типового выра-
жения и основного вычисления;
тексты модулей проектов
пример работы приложений с указанием компонентов формы;
выводы по работе.
Контрольные вопросы
1.С какой целью в программировании используют подпрограммы?
2.Что такое подпрограмма, какова их классификация?
3.В чём отличие процедуры от функции, в т.ч. в их структуре?
46
4.В чём отличие параметра-значения от параметра-переменной?
5.Вызов функции можно записывать непосредственно в выражениях,
а вызов процедуры нельзя, только отдельным оператором. Почему?
6.В каких случаях пользовательскую подпрограмму целесообразнее оформить как функцию, в каких как процедуру?
7.В представленных описаниях подпрограмм и фрагментах вызыва-
ющих блоков ответьте на поставленные вопросы
Пользовательская подпрограмма |
Блок, вызывающий подпрограмму |
|
|
|
|
Procedure pr(m,n:byte; var k:byte); |
var x, y, s, t:byte; z:real; |
|
begin |
begin |
|
k:=m+n; |
x:=2; y:=3; z:=2.5; |
|
end; |
pr(x, y); |
pr(x, y+1, 2*s); |
|
pr(x, z, s); |
pr(x, sqr(y), s); |
|
pr(2*x, y, s); |
t:= 5+pr(x, y, s); |
|
какие вызовы неверны и почему? |
|
|
|
|
Procedure pr2(m, n, k:byte); |
var x, y, s1, s2:byte; |
|
begin |
begin |
|
k:=m+n; |
x:=2; y:=3; s1:=0; s2:=0; |
|
end; |
pr(x, y, s1); pr2(x, y, s2); |
|
|
каковы значения s1 и s2 теперь? |
|
|
|
|
Function fun(u,v:byte):integer; |
var x, y:byte; |
w1, w2:integer; |
begin |
begin |
|
fun:=u v; |
x:=2; y:=3; |
|
end; |
w1:=fun(x, y); |
|
можно ли изменить тип integer |
w2:=fun(y, x); |
|
на тип byte в описании функции? |
каковы значения w1 и w2? |
|
|
|
|
47
Лабораторная работа № 4
МОДУЛИ
Цель работы приобретение умений разработки модулей. Разработанные пользовательские подпрограммы предыдущей
работы могли использоваться только в тех проектах, в которых они были описаны. Однако часто возникает необходимость выполнения типовых действий в разных проектах. Чтобы не описывать их в каждом таком проекте целесообразно эти действия однократно оформить в виде подпрограмм и поместить в собственный модуль, а затем, подключая его к различным проектам, использовать ресурсы этого модуля. Кроме того, проекты с большими объёмами программного кода удобно разбить на несколько файлов. Выносимые части кода из проекта можно также разместить в собственном модуле.
Модуль отдельно создаваемая компилируемая программная единица с именем, предназначенная для создания библиотек подпрограмм, которая также может содержать описание констант, типов, переменных. Описанные в модуле средства можно использовать в проектах и других модулях без повторного описания, ссылаясь на имя данного модуля. Сам модуль сохраняется в виде отдельного файла.
Модули делятся на стандартные, пользовательские и модули описания форм. Стандартные поставляются вместе с системой программирования и содержат библиотеки стандартных подпрограмм. Пользовательские разрабатывает сам программист для создания библиотек пользовательских (своих) подпрограмм. Модуль описания формы (модуль проекта), с которым мы уже знакомы, предназначен для описания формы и размещения процедур обработки событий.
48
Структура модуля
В общем случае модуль имеет следующую структуру
UNIT имя_модуля //заголовок
INTERFACE //раздел описаний («видимая часть») uses //список модулей, подключаемых к данному const //объявление глобальных констант
type //объявление глобальных типов
var //объявление глобальных переменных procedure //заголовки глобальных процедур function //заголовки глобальных функций
IMPLEMENTATION // раздел реализации (невидимая часть)
uses //список модулей, используемых только внутри данного модуля const //объявление локальных для данного модуля констант
type //объявление локальных для данного модуля типов
var //объявление локальных для данного модуля переменных procedure //полное описание локальных процедур
function //полное описание локальных функций procedure //полное описание глобальных процедур function //полное описание глобальных функций
INITIALIZATION //раздел инициализации
FINALIZATION //заключительный раздел
END. //конец модуля
Первая строка модуля его заголовок. Он начинается со слу-
жебного слова unit, за которым указывается имя модуля. Далее сле-
дует раздел описаний, начинающийся со служебного слова interface.
Всё, что описано в разделе описаний, будет доступно подключившим к себе этот модуль программным единицам (проект, другой модуль,
49
подпрограмма). Константы, типы, переменные здесь описываются обычным образом, а для подпрограмм выносятся только заголовки.
Со служебного слова implementation начинается раздел реали-
зации. Здесь приводят описание констант, типов, переменных и под-
программ, которые являются локальными для данного модуля. Т.е.
могут использоваться только внутри модуля, они «не видны» извне. И
здесь же приводят уже полное описание глобальных подпрограмм (их заголовки продублированы в разделе описаний модуля), которые, в
свою очередь, могут использовать локальные подпрограммы, кон-
станты, переменные, типы.
В разделе инициализации помещаются команды, выполняемые до начала работы программной единицы, подключившей к себе дан-
ный модуль, и подготавливают её работу. Здесь могут присваиваться начальные значения переменным, открываться внешние файлы и т.д.
В заключительном разделе помещаются команды, выполняемые после завершения работы программной единицы, подключившей к себе данный модуль, например, закрытие внешних файлов. Последние два раздела обычно отсутствуют. Может отсутствовать и раздел реа-
лизации, тогда модуль содержит только описания переменных, типов,
констант. Заканчивается модуль end.
Отметим, что модуль описания формы (модуль проекта) подчи-
нён такой же структуре, просто он имеет значительный по объёму ко-
да раздел описаний, т.к. там описываются сложные объектные типы.
Создание и подключение модуля
Для создания собственного модуля можно запустить Delphi, за-
крыть форму и окно модуля, не сохраняя его. Затем выбрать команду
50