Итак, процедура – это часть программы (подпрограмма), имеющая имя и предназначенная для решения некоторой частной задачи (подзадачи). Процедуры делятся по способам описания и обращения к ним (см. рис. 28).
Рис. 28. Типы процедур
Процедура встроенная (машинная) – это процедура, описание которой считается известной транслятору, в связи с чем ее можно использовать в программе, зная только ее имя.
Процедура пользователя – процедура, которую создает (описывает) программист на основе имеющихся операторов и встроенных процедур и функций данного языка по определенным правилам данного языка.
Процедура без параметров – процедура, при обращении к которой не требуется задания начальных установок, значений и после выполнения которой в основную программу не передаются результаты работы данной процедуры.
Процедура с параметрами-значениями – процедура, при обращении к которой требуются только начальные значения. На выходе данные не передаются в основную программу.
Процедура с параметрами-переменными – процедура, не требующая начальных значений, однако передающая в основную программу результаты своей работы (передает значения некоторых переменных).
Комбинированная процедура – процедура, имеющая параметры-переменные и параметры-значения, т.е. входные и выходные данные.
5.1.1. Встроенные процедуры
Встроенные процедуры являются составной частью системы программирования. Среди них есть стандартные процедуры, которыми можно пользоваться в любом месте программы без какого-либо предварительного объявления. Сюда относятся уже ранее упомянутые процедуры ввода/вывода, управления работой программы, динамического распределения памяти, строковые процедуры и пр. Полный перечень встроенных процедур можно найти в справочнике для языка.
Помимо стандартных процедур в Паскале есть также стандартные модули, представленные в виде TPU – файлов, каждый из которых содержит в себе целый набор процедур и функций. Для того чтобы использовать процедуры из модулей, необходимо вызвать нужный модуль в разделе USES. Система TurboPascal имеет модули PRINTER, DOS, CRT, GRAPH и др.
CRT позволяет использовать все возможности дисплея и клавиатуры, включая управление режимом работы экрана, расширенные коды клавиатуры, цвет, окна и звуковые сигналы.
DOS поддерживает различные функции ДОС, включая установку и получение текущего значения даты и времени, поиск по каталогам файлов и выполнение программ.
PRINTER позволяет легко организовать доступ к устройству печати.
GRAPH – мощный графический пакет с набором процедур и функций обработки графических объектов (точек, отрезков, прямоугольников, окружностей и пр.).
Рассмотрим несколько примеров встроенных процедур:
· CLRSCR – процедура очистки экрана. Результатом работы является стирание всей информации с экрана. Данная процедура является примером процедур без параметров.
· GOTOXY (A, B) – процедура позиционирования курсора на экране дисплея в точку с координатами (A, B). A и B являются входными данными, следовательно, это пример процедуры с параметрами-значениями.
· WRITE (A, B, ..., Q) – процедура вывода информации на экран дисплея. Данная процедура – процедура с параметрами-значениями.
· READ (A, B, ..., Q) – процедура ввода информации в ЭВМ. При выполнении данной процедуры переменным A, B, ..., Q присваиваются конкретные значения, т.е. данные передаются в основную программу, и, значит, процедура является примером процедур с параметрами-переменными.
5.1.2. Процедуры пользователя
При работе с процедурами пользователя необходимо уметь производить два вида деятельности: описание процедуры и обращение к ней в основной программе. Вызов процедуры пользователя осуществляется так же, как и вызов встроенной процедуры, – с помощью оператора вызова процедуры, имя которого совпадает с именем процедуры, с указанием списка параметров, если таковые имеются. Описание же процедуры включает в себя разработку подпрограммы и правильное оформление ее заголовка. Остановимся на нем более подробно.
В основной программе все процедуры (а также и функции) пользователя должны быть объявлены. Объявление процедур и функций осуществляется после объявления переменных и перед первым словом BEGIN программы.
Процедура, как видно из ее определения, оформляется так же, как и основная программа. Вообще процедуру нужно воспринимать как программу в миниатюре. В свою очередь, основная программа может быть легко переделана в процедуру с заменой слова PROGRAM на PROCEDURE. Если процедура объявлена, ее можно использовать в последующих частях программы, просто записывая ее имя, за которым, если необходимо, следует список параметров. Вызов процедуры для основной программы становится новым оператором. Обращение к процедуре активизирует эту процедуру, т.е. приводит к выполнению группу операторов, содержащихся в ее теле. После этого управление переходит к оператору, следующему за вызовом процедуры.
Описание процедур будем рассматривать по той же схеме, что и машинные процедуры, а именно: сначала без параметров, далее с параметрами-значениями, с параметрами-переменными и, наконец, комбинированные процедуры.
5.1.3. Процедуры без параметров
Заголовок процедуры без параметров представлен на рис. 29.
Рис. 29. Синтаксическая диаграмма заголовка
процедуры без параметров
Вызываются такие процедуры путем написания в основной программе имени этой процедуры. В виде процедуры без параметров оформляются такие подзадачи, у которых нет входных и выходных данных, или же эти данные удобнее передавать с помощью операторов присваивания – READ и WRITE.
Рассмотрим несколько примеров, в которых представлены эти варианты.
П р и м е р 1. Нарисовать три вертикальных квадрата 3 × 3 с помощью символа «*».
Очевидно, что в этой программе надо выделить рисование квадрата в виде процедуры без параметров, а затем трижды вызвать ее в основной программе.
program RISUNOK;
procedure KVADRAT;
begin
writeln ('***');
writeln ('* *');
writeln ('***');
end;
begin
clrscr; KVADRAT;
writeln; KVADRAT;
writeln; KVADRAT;
end.
П р и м е р 2 . Вычислить площадь четырехугольника ABCD.
Зная длины сторон четырехугольника и длину одной из его диагоналей, например BD, можно по формуле Герона найти площади двух вспомогательных треугольников и сложить их. Отсюда следует, что в программе надо выделить процедуру вычисления площади треугольника.
program PLOCHAD_1;
var AB, BC, CD, AD, BD, S1, S, a, b, c, p:real;
procedure GERON_1;
begin
p := (a + b + c)/2;
S := sqrt (p*(p - a)*(p - b)*(p - c));
end;
begin {*ОСНОВНАЯ ПРОГРАММА*}
read (AB, BC, CD, AD, AC);
a := AB; b := AD; c := BD; GERON_1; S1:= S;
a := BC; b := CD; c := BD; GERON_1; S1:= S1 + S;
write (S1);
end.
Примечание. В данной программе все вычисления проходят с помощью переменных, объявленных в разделе VAR основной программы.
5.1.4. Фактические и формальные параметры
Прежде чем переходить к рассмотрению процедур с параметрами, необходимо определить сами эти понятия. Сделаем это на примере программы вычисления площади четырехугольника (пример 2).
Рассмотренная программа имеет недостаток в том, что в основной ее части идет ряд присваиваний, которые предшествуют вызову процедуры. Чтобы избавиться от этих присваиваний, вводят процедуры с параметрами. С помощью параметров осуществляется передача информации в процедуру, а также и прием (возврат) информации из процедуры в основную программу.
Различают формальные и фактические параметры. Формальные параметры – это переменные, фигурирующие в самой процедуре, а точнее, в ее заголовке – после имени процедуры в скобках. Среди них имеются параметры-аргументы и параметры-результаты. Эти параметры называют формальными, потому что они служат только для фиксации числа параметров процедуры, их имена могут быть произвольными, смена имен не отражается на работе процедуры.
Фактические параметры задаются в вызове процедуры, т.е. они принадлежат основной части программы. В отличие от формальных параметров, которые всегда есть переменные, фактические параметры имеют вид:
Рассмотрим заново программу вычисления площади четырехугольника. В ней все переменные объявлены в основной программе. Однако среди них есть переменные, которые задействованы только в процедуре. Это переменные A, B, C, P, S. Их принято называть локальными по отношению к процедуре. Остальные переменные называются глобальными. Среди локальных переменных можно выделить параметры-аргументы A, B, C и параметр-результат S. Формальные параметры принято описывать в заголовке процедуры с указанием их типа. Локальная же переменная P является вспомогательной и описывается в процедуре так же, как в основной программе, т.е. в разделе VAR.
Порядок следования формальных параметров в заголовке процедуры и фактических параметров в вызове процедуры важен, поскольку определяет, какому параметру будет присвоено то или иное значение.
Все переменные должны быть отнесены к какому-либо типу, поэтому необходимо задать тип каждого параметра. Передаваемое значение и соответствующий ему параметр (фактический) должны быть одного и того же типа.
Новые варианты программы вычисления площади четырехугольника будут даны в следующих разделах, а пока рассмотрим подробнее понятия локальных и глобальных переменных в Паскаль-программах.
5.1.5. Локальные и глобальные переменные
В предыдущем разделе уже было дано определение локальных и глобальных переменных. Уточним еще раз, что локальные переменные объявляются внутри блока процедуры и бывают двух видов: формальные параметры заголовка процедуры и вспомогательные переменные в разделе VAR процедуры. Эти переменные не известны основной программе, и их использование в основном блоке вызовет сообщение об ошибке.
Глобальные переменные объявляются в разделе VAR основной программы. Они называются глобальными, потому что могут фигурировать не только в основной программе, но и в теле процедуры. Заметим, что иногда одна и та же переменная может быть и локальной, и глобальной. Например, если переменная J является одновременно локальной и глобальной, то локальная переменная J отличается от переменной J из главной программы. Изменения, происходящие с J в процедуре, не влияют на значение переменной J из главной программы, и наоборот. Это происходит потому, что, несмотря на сходство имен переменных, компилятор отводит локальной переменной J одну ячейку памяти, а глобальной переменной J – другую. Обычно стараются избегать совпадения имен переменных во избежание нежелательных посторонних эффектов, которые могут возникнуть из-за использования одних и тех же имен для разных переменных.
Для ясности рассмотрим пример, связанный с использованием локальных и глобальных переменных:
program NEST;
var A, B:integer;
procedure NESTEGG;
var A, X: char;
begin
A := "!";
X := "?";
B := B + 1;
end;
begin {ОСНОВНАЯ ПРОГРАММА}
A := 0; B := 100;
NESTEGG; {ВЫЗОВ ПРОЦЕДУРЫ}
writeln (A,' ',B);
end.
В этой программе X – локальная переменная для процедуры NESTEGG, поэтому основная программа не может ни изменить ее значение, ни обратиться к ней. С другой стороны, переменная B (глобальная) известна и в программе, и в процедуре. Если переменная B является глобальной, т.е. объявлена в главной программе, то все входящие в состав этой главной программы процедуры могут ссылаться к ней, но только в том случае, если в них нет другого объявления для B. Любое объявление имени в процедуре делает недоступным объект, имеющий то же самое имя и объявленный в основной программе. Так, у нас A для основной программы есть INTEGER, но в процедуре есть A типа CHAR. Процедуре NESTEGG недоступна переменная A из главной программы. Все изменения, происходящие с A в процедуре, становятся несущественными при выходе из этой процедуры. Но поскольку B известна в главной программе, то все изменения с B в процедуре важны и сохраняются после выхода из нее. Итак, будет выведено: 0 101.
5.1.6. Процедуры с параметрами-значениями
Как было сказано ранее, процедуры с параметрами-значениями требуют входных данных (см. п. 5.1). Где они записываются и как задаются? На этот вопрос может ответить синтаксическая диаграмма заголовка процедуры (рис. 30).
Здесь под параметром понимают имя переменной, которая является «входной» для процедуры (формальный параметр-аргумент). Этот параметр с синтаксической точки зрения является параметром-значением, при его описании в заголовке процедуры не требуется писать слово VAR. Параметры-значения при вызове процедуры принимают из основной программы свои конкретные значения. Заметим также, что в самой процедуре значения параметров-значений не меняются в ходе работы процедуры.
Рис. 30. Синтаксическая диаграмма заголовка
процедуры с параметрами-значениями
При обращении к процедуре с параметрами-значениями в основной программе фактическими параметрами могут служить как имена переменных (которые описаны и определены выше), так и конкретные значения (константы) и выражения. При обращении необходимо следить за соответствием списка параметров при обращении и описании. Кроме того, следует строго соблюдать соответствие типов параметров.
Рассмотрим работу процедур такого типа на примерах.
П р и м е р 1. Нарисовать квадрат с произвольной длиной стороны в левом верхнем углу (длина стороны задается с клавиатуры).
В этой программе также надо оформить рисование квадрата в виде процедуры, но уже с входным параметром-значением – длиной стороны квадрата.
program RISUNOK_2;
var I: integer;
procedure KVADRAT (N: integer);
var J, K: integer;
begin
for J := 1 to N do write ('*'); writeln;
for J := 1 to N - 2 do
begin
write ('*'); for K := 1 to N - 2 do write (' ');
writeln ('*');
end;
for J := 1 to N do write ('*');
end;
begin { Основная программа }
write ('Введите длину стороны – ');
readln (I); clrscr; KVADRAT (I);
end.
П р и м е р 2. Вычислить площадь четырехугольника с применением процедуры с параметрами-значениями.
program PLOCHAD_2;
var AB, BC, CD, AD, AC, S1, S: real;
procedure GERON_2 (a, b, c: real);
var P: real;
begin
P := (a + b + c)/2; S := sqrt (P*(P - a)*(P - b)*(P - c));
В данной программе определена процедура GERON_2 с тремя параметрами-значениями и локальной переменной P. Значение же площади треугольника помещается в глобальную переменную S. При вызове этой процедуры формальные параметры a, b, c замещаются на фактические параметры AB, BC, AC при первом обращении и на AD, AC, CD – при втором.
Заметим также, что здесь фактические параметры представлены переменными, которые получают свое значение с помощью процедуры READ. Однако если известны длины сторон треугольника, например, 6, 7, 4, то можно вычислить площадь этого треугольника, вызвав процедуру GERON_2(6, 7, 4), и получить ответ в переменной S.
5.1.7. Процедуры с параметрами-переменными
В отличие от процедур с параметрами-значениями, процедуры с параметрами-переменными не имеют входных параметров, т.е. из основной программы не передаются значения переменных в процедуру, за исключением глобальных переменных. Отличие в описании и обращении к процедурам с параметрами-переменными заключается в специфическом написании заголовка процедуры. В остальном все процедуры схожи. Синтаксическая диаграмма заголовка процедуры с параметрами-переменными представлена на рис. 31.
При детальном ознакомлении с синтаксической диаграммой видно, что параметрам-переменным должно предшествовать служебное слово VAR, причем оно пишется столько раз, сколько различных типов представлено в выходных данных, например:
PROCEDURE PRIMER (VAR a, b, c : INTEGER; VAR m : CHAR; VAR i, j : REAL).
При обращении к процедурам с параметрами-переменными фактическими параметрами должны являться имена переменных, которые описаны в основной программе.
П р и м е р 1. Обмен значениями переменных A и B.
program ZERKALO;
var A, B: integer;
procedure OBMEN (var X,Y: integer);
begin X := B; Y := A end;
begin
A := 1; B := 2; writeln (A, B);
OBMEN (A, B); write (A, B);
end.
П р и м е р 2. Вычисление площади четырехугольника.
program PLOCHAD_3;
var AB, BC, CD, AD, AC, S1, S2, a, b, c: real;
procedure GERON_3 (var S: real);
var P: real;
begin
P := (a + b + c)/2; S := sqrt (P*(P - a)*(P - b)*(P - c));
end;
begin { Основная программа }
read (AB, BC, CD, AD, AC);
a := AB; b := BC; c := AC; GERON_3 (S1);
a := AD; b := AC; c := CD; GERON_3 (S2);
write ('S = ', S1 + S2)
end.
5.1.8. Комбинированные процедуры
Комбинированные процедуры включают в себя входные и выходные данные. В заголовке процедуры выходные параметры предваряются словом VAR (см. рис. 32). Порядок следования параметров может быть произвольным, например:
PROCEDURE PRIMER (VAR a, b, c: INTEGER;
m: CHAR; VAR i, j: REAL);
Здесь a, b, c, i, j – параметры-результаты (переменные); m – параметр-аргумент (значение).
Рис. 32. Синтаксическая диаграмма заголовка
комбинированной процедуры
В качестве иллюстрации комбинированных процедур рассмотрим последний вариант вычисления площади четырехугольника:
program PLOCHAD_4;
var AB, BC, CD, AD, AC, S1, S2: real;
procedure GERON_4 (a, b, c : eal; var S : real);
var P : real;
begin
P := (a + b + c)/2;
S := sqrt (P*(P - a)*(P - b)*(P - c));
end;
begin {*ОСНОВНАЯ ПРОГРАММА*}
read (AB, BC, CD, AD, AC);
GERON_4 (AB, BC, AC, S1);
GERON_4 (AD, AC, CD, S2);
write ('S = ', S1 + S2)
end.
Примечание. Для более полного усвоения введенных ранее терминов перечислим на базе последнего примера все виды параметров и переменных:
Заметим также, что термины «параметр-значение» и «аргумент», как и «параметр-переменная» и «результат», не всегда идентичны. Дело в том, что характеристика «значение (переменная)» отражает синтаксическую сущность параметра, а «аргумент (результат)» – его семантику (функциональную роль в процедуре). Иногда один и тот же параметр может быть аргументом и результатом одновременно, но описан в процедуре в виде параметра-переменной. Примером такой ситуации является программа ZERKALO п. 5.1.7.
Попытка же описать выходной параметр в виде параметра-значения (без слова VAR в заголовке процедуры) приведет к тому, что результат работы процедуры не будет возвращен в основную программу. Это происходит потому, что характер «поведения» параметров-значений и параметров-переменных в процессе работы процедуры различен. Разница эта состоит в том, что преобразования, которые претерпевают формальные параметры-значения в процедуре, не вызывают изменения соответствующих им фактических параметров, в то время как изменения параметров-переменных могут изменять значения соответствующих фактических параметров.
Причиной этого феномена является неодинаковое распределение памяти под хранение параметров процедуры. Формальному параметру-значению отводится некоторая область (ячейка) памяти, куда заносится значение соответствующего фактического параметра, вычисленного на момент обращения к процедуре. На этом связь между ними обрывается. Действительно, если фактическим параметром является константа или выражение, то как изменения в формальном параметре-значении (а это есть всегда переменная) могут повлиять, например, на выражение?
Фактическим же параметром, соответствующим формальному параметру-переменной, является всегда переменная. На время выполнения процедуры эти параметры отождествляются, им соответствует одна и та же область памяти. Вполне понятно, что в этой ситуации изменения формального параметра влекут адекватные изменения фактического параметра, и после завершения процедуры его значение может отличаться от его первоначального значения.
Именно поэтому, объявив в процедуре параметр-результат как параметр-значение, этот результат так и останется в формальном параметре-переменной без его передачи в соответствующий фактический параметр.