Н. Вирт - Программирование на языке Модула-2 (1160777), страница 10
Текст из файла (страница 10)
Едва лисуществует хоть одна программа, написанная спрактической, а не учебной целью, котораябы не использовала циклов и массивов (или аналогичных им структур данных).Часть 210. ПРОЦЕДУРЫРассмотрим задачу обработки некоторого набора данных, состоящего из заголовка ипоследовательности из N отдельных подобных элементов. В общем виде это можно записать так:ВводЗаголовка;ОбработкаЗаголовка;ПечатьЗаголовка;FOR i := 1 ТО N DOВводЭлемента;47ОбработкаЭлемен нта:Печать(i):ПечатьЭлементаENDОписание исходной задачи дано в терминах подзадач, причем выделена лишь основнаяструктура задачи, а детали опущены.
Конечно, подзадачи ВводЗаголовка, ОбработкаЗаголовка ит.д. должны быть далее описаны со всеми необходимыми деталями. Однако можно не заменятьслова-описатели соответствующими Фрагментами программ на Модуле, а рассматривать этислова как идентификаторы и определить детали подзадач в текстуально отделенных частяхпрограммы, называемых процедурами (или подпрограммами). Такие определения называютсяописаниями процедур. Они называются так потому, что определяют действия процедуры и даютей имя. Идентификаторы в главной программе, соответствующие описаниям процедур,называются вызовами процедур и их действие заключается в выполнении соответствующейпроцедуры. С точки зрения синтаксиса, вызов процедуры представляет собой оператор.Процедуры играют фундаментальную роль при разработке программ. Они помогаютвыявлять структуру алгоритма и разбивать программу на логически связанные единицы.
Этоособенно важно в случае сложных алгоритмов, т.е. длинных программ. Хотя применение вприведенном выше примере отдельно описанных процедур, а не прямой подстановки текста наместо идентификаторов может показаться довольно расточительным, тем не менее радиполучения ясной структуры программы часто рекомендуется использовать явные процедуры дажев таком простом случав. Процедура, разумеется. особенно полезна, если она должна вызываться изразличных мест программы.Описание процедуры состоит из ключевого слова PROCEDURE и следующего за нимидентификатора (вместе они образуют заголовок процедуры), далее, ключевого слова BEGIN ипоследовательности операторов, называемой телом процедуры.
В тексте программы телопроцедуры заменено ее идентификатором. Описание заканчивается ключевым словом END иповторением идентификатора процедуры. Это позволяет компилятору выявлять отсутствиезавершителей операторов и описаний. Общий синтаксис описания процедуры будет дан позже.Приведем простой пример, в котором вычисляется сумма а[0]+...+а[N-1].PROCEDURE Сложить;BEGIN сумма := 0.0;FOR i := 0 ТО N-l DOсумма := а[i] + суммаENDEND СложитьКонцепция процедуры становится гораздо полезнее благодаря двум ее дополнительнымособенностям.
Это параметры и свойство локальности имен. Параметры делают возможным привызове одной и той же процедуры из различных мест программы применять эту процедуру кразличным величинам и переменным, задаваемым в месте вызова. Понятие локальности имен иобъектов значительно повышает роль процедур в структуризации программы и выделении еечастей. Далее в первую очередь мы будем обсуждать понятие локальности. Подводя итог всемусказанному, повторим следующие существенные моменты:1. Процедура помогает выявить внутреннюю структуру программы и облегчаетдекомпозицию программистской задачи на подзадачи.2. Если процедура вызывается из двух или более мест, то ее применение сокращаетпрограмму, а следовательно, уменьшает вероятность программистских ошибок. Дополнительнымпреимуществом является уменьшение размера откомпилированного кода.4811.
ПОНЯТИЕ ЛОКАЛЬНОСТИЕсли мы посмотрим на пример процедуры из предыдущей главы, то заметим, что рольпеременной i строго ограничена телом процедуры. Это свойство локальности следует выразитьявно, что можно сделать, описав i внутри процедуры. Тем самым i становится локальнойпеременной.PROCEDURE Сложить;VAR i: CARDINAL;BEGIN сумма : = 0.0;FOR i := 0 ТО N-l DOсумма := a[i] + суммаENDEND СложитьВ некотором смысле описание процедуры принимает вид отдельной программы.Фактически любые описания, допустимые в программе (констант, типов, переменных илипроцедур), могут появиться и в описании процедуры. Отсюда следует, что описания процедурмогут быть вложенными и что их определение рекурсивно.Считается хорошей привычкой описывать локальные объекты, т.е.
ограничивать областьсуществования объекта той процедурой, в которой он имеет смысл. Процедура, т.е. Фрагменттекста программы, для которого действительно описание имени, называется его областьювидимости. Так как описания могут быть вложенными, то вложимы друг в друга и областивидимости. Возможность существования объектов, локальных в некоторой области видимости,влечет за собой некоторые интересные следствия.
Можно, например, использовать одно и то жеимя для обозначения разных объектов. Фактически это самое полезное следствие, посколькупрограммист свободен в выборе идентификаторов и не должен знать, какие идентификаторысуществуют в окружающей области видимости, если они не обозначают объектов, используемых влокальной области (в противном случае программист обязан их знать). Такое разделениеинформации о различных частях программы особенно полезно, а возможно, даже жизненнонеобходимо в случае больших программ.Правила для областей видимости таковы:1. Областью видимости идентификатора является процедура, в которой он описан, и всепроцедуры, заключенные в ней, кроме тех, которые подчиняются правилу 2.2.
Если идентификатор i, описанный в процедуре Р, повторно описан в некоторойвнутренней процедуре Q, заключенной в Р, то процедура Q и все заключенные в ней процедурыисключаются из области видимости идентификатора i, описанного в Р.3. Стандартные идентификаторы Модулы считаются описанными в воображаемойпроцедуре, охватывающей всю программу.Эти правила можно запомнить с помощью алгоритма поиска описания данногоидентификатора i: вначале просматриваются описания процедуры Р, в теле которой встретился i:если среди них не встретилось описание для i, то продолжается поиск в процедуре, охватывающейР; далее повторяется это же правило, пока не встретится нужное описание.VAR a: CARDINAL;PROCEDURE P;49VAR b: CARDINAL;PROCEDURE Q;VAR b,c: BOOLEAN:BEGIN(* a,b(BOOLEAN),с видимы *)END Q;BEGIN(* a,b(CARDINAL) видимы *)END PСледствием концепции локальности и правила о том, что переменная не существует запределами ее области видимости, является тот Факт, что значение переменной теряется, когдаописывающая ее процедура завершается.
Предполагается, что при повторном вызове процедурызначение такой переменной неизвестно. Величины локальных переменных не определены привходе в процедуру (первом или повторном). Следовательно, если переменная должна сохранятьзначение между двумя вызовами, ее нужно описывать за пределами процедуры. "Время жизни"переменной - это время, в течение которого активна описавшая ее процедура.Использование локальных описаний имеет три существенных пРОимушества:1.
Становится ясным, что объект заключен в процедуре, которая обычно составляет лишьмалую часть всей программы.2. Есть гарантия, что случайное использование локального объекта другими частямипрограммы будет обнаружено компилятором.3. Возможна минимизация используемой памяти при реализации, поскольку память дляпеременных освобождается при завершении процедуры, в которой эти переменные локальны.Память затем может быть повторно использована для других переменных.12. ПАРАМЕТРЫПроцедуры могут иметь параметры. Именно эта существенная деталь делает процедурытакими полезными. Рассмотрим еше раз пример процедуры Сложить. Весьма вероятно, что впрограмме содержится несколько массивов, к которым можно было бы ее применить.Переписывать ее для каждого из них - громоздко и некрасиво.
Этого можно избежать, введяоперанд в качестве параметра процедуры.PROCEDURE Сложить(VAR x: Вектор);VAR i: CARDINAL;BEGIN сумма := 0.0;FOR i := 0 TO N-l DOсумма := x[i] + суммаENDEND Сложить50В список параметров заголовка процедуры введен параметр х. Тем самым онавтоматически становится локальным объектом, подменяющим Фактический массив, указанный ввызове процедуры.Сложить(а);...;Сложить(Ь)Массивы а и b называются фактическими параметрами, замещающими массив х,называемый формальным параметром. При задании Формального параметра должен указыватьсяего тип.
Это позволяет компилятору проверить, подходит ли тип подставляемого Фактическогопараметра. Мы говорим, что Фактические параметры а и b должны быть совместимы сФормальным параметром х. В приведенном выше примере его тип - Вектор, которыйпредположительно описан в окружении процедуры Сложить таким образом:TYPE Вектор = ARRAY [0..N-1] OF REAL;VAR а,Ь: ВекторЕще лучшая версия процедуры может включать в качестве параметров не только массив,но и результат суммирования.
Мы позже еше вернемся к этому примеру, но прежде нужнообъяснить, что существует два вида Формальных параметров: параметр-переменная и параметрзначение, Первый отмечается ключевым словом VAR, второй - его отсутствием.В завершение этого раздела дадим синтаксис описания процедуры и вызова процедуры.$ОписаниеПроцедуры - ЗаголовокПроцедуры "ж"$Блок Идентификатор.$ЗаголовокПроцедуры - "PROCEDURE" Идентификатор$[ФормальныеПараметры].$Блок = {Описание} ["BEGIN" ПослОператоров] "END".$ФормальныеПараметры = "(" [ФПСекция {";" ФПСекция}] ")"$[":" КвалИдент].$ФПСекция = ["VAR"] СписИдент ":" ФормТип.$ФормТип = ["ARRAY" "OF"] КвалИдент.$ВызовПроцедуры = Обозначение [ФактическиеПараметры].$ФактическиеПараметры = "(" [СписВыражений] ")".Теперь мы знакомы со всеми формами описаний, кроме описания модуля.$Описание = "CONST" {ОписаниеКонстанты ":"}|$"TYPE" (ОписаниеТипа ";"}|$"VAR" {ОписаниеПеременной ";"}|$ОписаниеПроцедуры ";" | ОписаниеМодуля ";".12.1. Параметры-переменныеКак можно заключить из названия, фактический параметр, соответствующийФормальному параметру-переменной (отмеченному словом VAR), должен быть переменной.Идентификатор Формального параметра заменяет эту переменную.
Пример:51PROCEDURE обмен(VAR x,y: CARDINAL);VAR z: CARDINAL; BEGIN z:=x;x:=y;y:=z END обменВызовы процедурыобмен(а,b): обмен(А[i],А[i+1])дают тот же результат, что и выполнение трех записанных ранее присваиваний с учетомсоответствующих подстановок при вызове. Относительно параметров-переменных важно помнитьследующее:1.