В.Г. Абрамов, Н.П. Трифонов, Г.Н. Трифонова - Введение в язык Паскаль (1107618), страница 38
Текст из файла (страница 38)
Какие идентификаторы могут использоваться в качестве формальныхпараметров? Любые, не используемые в данной процедуре для других целей.В частности, в качестве формальных параметров можно использовать и теидентификаторы, которые использованы в основной программе — приусловии, что объекты основной программы, обозначенные этими идентификаторами, в явном виде не фигурируют в теле процедуры.
Последнее156утверждение, правда, может вызвать некоторое недоумение и потому требует пояснений.В самом деле, пусть в основной программе введены в употреблениепеременные f, b, с и d:v a r -f,b,c,d: real;Введем в употребление в этой же программе процедуру сложения двухвещественных значений с присваиванием результата некоторой вещественной переменной, используя в качестве формальных параметров этой процедуры идентификаторы f.
b и с:p r o c e d u r e СУМ2(+,Ь:real;v a r с:real);b e g i n c : = f + b endЕсли где-то в основной программе требуется реализовать вычисленияпо формуле f = b * с + 0.5 * d, то вместо оператора присваивания можнозаписать оператор процедуры СУМ2 (Ь * с, 0.5 * d, f). Вспомним, что выполнение этого оператора процедуры сводится к выполнению эквивалентного ему блокаv a r -f ,b: real ;b e g i n f:=b*c;b:»0.5*d;b e g i n -f:=f+b endendКак видно, здесь довольно трудно разобраться, чем же на самом делеявляются идентификаторы f и Ь. Например, идентификатор f в левой частиоператора присваивания f: = f + b должен быть именем переменной, существующей вне процедуры, а этот же идентификатор в правой части оператораприсваивания должен быть именем внутренней переменной, поставленнойв соответствие первому формальному параметру-значению данной процедуры.
Произошла, к а к говорят, " к о л л и з и я " (смешение, путаница) междуформальными параметрами-значениями и фактическими параметрами,вызванными по имени. Такой ситуации не следует бояться: паскаль предполагает, что возникающая коллизия устраняется путем систематическогоизменения формальных параметров (идентификаторов), затрагиваемыхколлизией. В рассматриваемом случае можно считать, что блок, эквивалентный оператору процедуры, будет выглядеть, например, так:v a r -f 1 ,Ы е real ;b e g i n -fl:=b*c;bl:=0.5*d;b e g i n -f:=-fl+bl endendЗдесь уже нет никаких недоразумений относительно того, что обозначает тот или иной идентификатор.
Следует подчеркнуть, что устранениевозникающих коллизий не требует каких-либо дополнительных усилийсо стороны программиста, а осуществляется автоматически. Трансляторпросто должен для вспомогательных переменных процедуры, сопоставляемых параметрам-значениям, отводить ячейки памяти, не используемыев основной программе и в других процедурах. А поскольку при трансляции программы на я з ы к машины каждое имя переменной заменяется157на соответствующий машинный адрес, то тем самым коллизии устраняютсяавтоматически.4. В к а к о м порядке перечислять формальные параметры в заголовкепроцедуры? В к а к о м программист считает необходимым. Однако зафиксировав этот порядок, его необходимо затем строго придерживаться приобращениях к процедуре: в операторе процедуры фактические параметрынеобходимо задавать в том же самом порядке, иначе будет неправильноустановлено соответствие между фактическими и формальными параметрами.
Если, например, заголовок приведенной выше процедуры СУМ2был бы записан в видеp r o c e d u r e CyM2(var ci real; f,b: real)тооператорпроцедуры необходимо было бы записать в видеСУМ2 (f, b * с, 0.5 * d), а не в виде СУМ2 (Ь * с, 0.5 * d, f), как раньше.5.
Обратим внимание на то, что в заголовке процедур для указаниятипов формальных параметров могут использоваться только имена типов,но не их задания. Так что паскаль запрещает использование в заголовкепроцедуры безымянных типов. Например, в паскале недопустим заголов о к процедурыp r o c e d u r e Q(ms 1 .
. 2 0 ; v a r y s a r r a y Cchar} o f r e a l )Выйти из создающегося положений можно только описав предварительнов программе используемые типы, например:typeдиап=1.„20;вект=аггауCcharDof real;p r o c e d u r e Q(ms диап; var у: вект)Казалось бы, к а к а я разница — использовать имя типа или его непосредственное задание в виде безымянного типа? Однако разница есть,притом весьма существенная. В частности, из-за этого ограничения в паскале нельзя определить процедуру, применимую к произвольным массивам, даже в том случае, когда компоненты массивов имеют одини тот же тип.Действительно, пусть в программе используются вещественные векторых, у, состоящие из 20 компонент, вещественный вектор z из 30 компонент,и в разных местах программы приходится находить суммы компоненткакого-либо из этих векторов.
Для решения этой частной задачи хотелось бы ввести в употребление соответствующую процедуру, однако в паскале нельзя определить процедуру, пригодную для нахождения суммыкомпонент любого из упомянутых векторов х, у или z.В самом деле, в заголовке такой процедуры надо указать имя типаиспользуемого вектора, напримерp r o c e d u r e СУММА(var а: вект; v a r Bums real);Но вект - это либо имя типа array [1..20] of real, либо имя типаarray [1 ..30] of real, но не одно и другое одновременно.
В паскале это разные типы, и поэтому дать им одно и то же имя нельзя. Поэтому придется158определить одну процедуру для суммирования компонент векторов из20 компонент, и другую процедуру - для суммирования компонент векторов из 30 компонент. Например, для векторов из 20 компонент эта процедура может иметь видtype вект20=аггау С!.. 20] o-f real;var >:,у: вект20; a,b,c: real;procedure CyM20<var а: вект20; var sum: real);var i: 1..20;begin sum:=G;forto 20 do sum:=sum+aCi1endа обращение к этой процедуре будет иметь, например, вид СУМ20(х, а)и СУМ20(у, Ь). Процедура для суммирования компонент вектора из30 компонент будет выглядеть аналогичным образом, но должен бытьописан тип таких векторов, напримервект30=аггау С1..303 o-f realи в процедуре с именем, например, СУМЗО у первого формального параметра должно быть указано имя типа вектЗО.Итак, в паскале нельзя ввести в употребление процедуру для обработкимассивов различных типов — даже в том случае, когда массивы отличаютсятолько числом компонент.
Это, конечно, существенное ограничение. Причина этого ограничения кроется в том, что в противном случае усложнился бы транслятор и оттранслированная программа была бы менее эффективной, поскольку в этой программе приходилось бы предусматриватьспециальную "административную систему", которая должна была быдинамически (т.е. в процессе выполнения программы) отводить нужноеместо в памяти для массивов, вызываемых значением.8.3.2. Определение оператора процедурыНапомним, что обращение к процедуре (ее активация) из основной программы осуществляется с помощью оператора процедуры:(оператор процедуры):: = (имя процедуры) |(имя процедуры)((список фактических параметров))Если в описании процедуры отсутствует список формальных параметров, то оператор процедуры состоит из одного имени процедуры. Процедуры без параметров мы уже рассматривали: в этом случае процедурапри каждом обращении к ней применяется к одним и тем же значениями (или) программным объектам либо выполняет всегда одно и то жедействие, не требующее задания фактических параметров, например выводна печать некоторого фиксированного сообщения.Еслив описаниипроцедуры используются формальные параметры,то оператор процедуры должен содержать список фактических параметров, с помощью которых при каждом обращении к процедуре конкрети159зируются ее формальные параметры:(список фактических параметров):: = (фактический параметр){, (фактический параметр)}Пока мы будем исходить из того, что фактическим параметром можетбыть выражение - имея при этом в виду, что переменная (полная иличастичная) является частным случаем выражения.Примеры обращений к процедурам с параметрами уже приводилисьвыше, так что сразу займемся уточнением некоторых вопросов, связанныхс фактическими параметрами.1.
Число фактических параметров в операторе процедуры должно бытьравно числу формальных параметров в описании процедуры. Отметим,что если у процедуры нет параметров, то оператор процедуры состоиттолько из имени процедуры, без круглых скобок, например МЛХ2А.но не МАХ2А ( ) .2. При записи оператора процедуры необходимо иметь в виду, что соответствие между фактическими и формальными параметрами устанавливается путем их сопоставления слева направо в соответствующих списках:первый фактический параметр ставится в соответствие первому формальному параметру, второй фактический параметрвторому формальномупараметру и т.д.
Поэтому для избежания ошибок в записи оператора процедуры надо твердо знать, что представляет в теле процедуры каждый очередной формальный параметр.3. Тип каждого фактического параметра должен соответствовать типуформального параметра. Это требование очевидно: если, например, какой-то формальный параметр в теле процедуры представляет логическоезначение, то в качестве соответствующего ему фактического параметрабессмысленно задавать вещественное или литерное значение. Для того,чтобы уменьшить вероятность допущения ошибок подобного рода, в загол о в к е процедуры и указывается тип каждого параметра.4. При задании каждого очередного фактического параметра надо особенно внимательно следить за тем, что представляет в процедуре соответствующий ему формальный параметр — значение или переменную.Если это параметр-переменная (в начале соответствующей секции формальных параметров указано служебное слово var), то фактическим параметром может быть только переменная, причем переменная в точноститого же типа,- что и тип формального параметра.