Отправляет email-рассылки с помощью сервиса Sendsay

Всё о работе в Интернет

  Все выпуски  

Занятие 43. Более детально рассмотрен механизм применения подпрограмм в языке Паскаль.


Здравствуйте, уважаемые подписчики! Как известно, все хорошее заканчивается очень быстро! То же самое произошло и с моим отпуском! Но, на смену одному хорошему всегда приходит другое! Я снова с вами, уважаемые подписчики!!!

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

ПОДПРОГРАММЫ В ЯЗЫКЕ ПАСКАЛЬ

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

Для этого обратитесь к материалам занятия 6 “Общий вид алгоритма на АЯ”, а также к материалам занятия 8 “Обращения к алгоритмам”.

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

1. Процедуры и их параметры.

Описание процедуры представляет собой блок в составе описательной и исполняемой части. Заголовок описательной части содержит зарезервированное слово Procedure, идентификатор процедуры, а также список параметров, указанных в круглых скобках. В разделе описаний описательной части блока может быть представлен раздел переменных. Таким образом, в исполняемой части процедуры доступны переменные как из её заголовка, так и из её раздела переменных. Кроме этого, в процедуре, в принципе, могут быть доступны и глобальные переменные, описанные в блоках, внешних по отношению к данному.

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

Глобальные переменные. Они описаны в блоках, внешних по отношению к данной процедуре. Эти переменные процедура может использовать для вычислений, может изменять их значения, и таким образом влиять на работу программы в целом. При этом существенно то, что перечень использованных глобальных переменных по отношению к данной процедуре фиксирован и нет никаких возможностей (кроме написания другой программы) вносить в него изменения. Процедура, работающая только с глобальными переменными, всегда делает одно и то же с одним и тем же неизменным результатом. Такие процедуры называются процедурами без параметров. Чаще всего с их помощью программу разбивают на блоки, относительно самостоятельные в функциональном плане. Это облегчает чтение и восприятие объёмной программы, поскольку она в таком случае представляется последовательностью обращений к различным процедурам. Впрочем, для этого не обязательно использовать процедуры. Можно обойтись, например, комментариями.

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

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

Для каждого из формальных параметров процедуры может быть избран один из трёх возможных способов передачи значения соответствующего фактического параметра. В качестве примера рассмотрим заголовок процедуры Procedure Q(A:Real; Var B:Real; Const C:Real);, где видны  все три способа.

Формальный параметр-значение. В процедуре Q таковым является параметр A: Real. При обращении к процедуре значение соответствующего фактического параметра сначала вычисляется, а затем полученный результат размещается во временно выделенной области памяти. И только после этого он используется при выполнении операторов процедуры. Следовательно, процедура работает с копией фактического параметра. Любые изменения копии никак не сказываются на самом фактическом параметре. Отметим, что использование в процедурах параметров-значений требует дополнительных затрат памяти. Описанный механизм называется передачей значения параметра.

Формальный параметр-переменная. В процедуре Q таковым является параметр B: Real, отмеченный директивой Var. При обращении к процедуре с соответствующим фактическим параметром никакие предварительные действия не выполняются. Процедура работает с самим фактическим параметром непосредственно. Это значит, что все изменения, предусмотренные в процедуре для формального параметра-переменной, происходят и с фактическим параметром. Использование в процедурах параметров-переменных дополнительных затрат памяти не требует. Описанный механизм называется передачей адреса параметра. 

Формальный параметр-константа. В процедуре Q таковым является параметр C: Real, отмеченный директивой Const. В этом случае механизм состоит в передаче либо адреса фактической переменной, либо адреса предварительно вычисленного значения фактического параметра. Следовательно, процедура работает непосредственно с фактическим параметром, а не с его копией, что не требует дополнительных затрат памяти. А самое главное состоит в том, что уже на этапе компиляции при любых попытках изменить значение параметра в самой процедуре приводит к получению сообщения “Error 122: Invalid variable reference” — неправильное обращение к переменной. Именно поэтому и соответствующий фактический параметр изменить из процедуры невозможно.

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

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

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

-       программист неумышленно использует не по основному назначению параметр-переменную, что приводит к порче соответствующего фактического параметра;

-       программист неумышленно использует не по основному назначению глобальную переменную, что также приводит к порче её значения;

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

2. Операторы обращения к процедурам.

Оператор обращения к процедуре предназначен для инициирования процесса выполнения операторов, входящих в состав её описания.

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

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

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

{$B+,D+,E+,I+,L+,N+,Q+,R+,X-}
Program Example008;
   Type
      Real1=Real;
      Integer1=Integer;
      Integer2=-10..10;
   Procedure X(a: Real; Var b: Real);
   Begin End;
   Procedure Y(c: Integer; Var d: Integer);
   Begin End;
   Var
      s: Extended; t: Single; r: Real;
      k: LongInt; m: ShortInt; n: Integer;
      p: Boolean; q: Char;
   Var
      r1: Real1;
      n1: Integer1;
      n2: Integer2;
Begin
   X(r,r);
   Y(n,n)
End.

В программе описаны две пустые процедуры X и Y, каждая из которых имеет два формальных параметра: первый параметр-значение, второй параметр-переменная. Кроме стандартных простых типов в программе использованы и нестандартные. Нестандартные типы Real1 и Integer1 – это просто иные наименования соответствующих стандартных. Нестандартный интервальный тип Integer2 представляет собой отрезок базового типа Integer. Кроме того, в программе в соответствующих разделах описаны переменные различных стандартных и нестандартных типов. Указывая в исполняемой части программы различные обращения к процедурам X и Y, можно убедиться в нижеследующих услових совместимости типов.

1. Между типами фактических и формальных параметров-переменных должно быть полное совпадение. Поэтому допустимы обращения X(r,r), Y(n,n). Однако, недопустимы обращения X(r,s), X(r,t), X(r,k), Y(n,m), Y(n,q) и т. п.

2. Имена типов фактических и формальных параметров-переменных могут быть различными, но только в том случае, если это различные имена для одного и того же типа. Поэтому допустимы обращения X(r,r1) и Y(n,n1).

3. Между типами фактических и формальных параметров-значений совпадения может и не быть. Однако, в любых случаях, не могут быть совместимыми числовой и логический, числовой и символьный, логический и символьный типы. Это же касается и любых нестандартных интервальных типов, построенных на основе указанных стандартных. Так, недопустимы обращения X(p,r), Y(q,n) и т. п.        

4. Типы формальных и фактических параметров-значений считаются совместимыми, если один из типов является отрезком другого, или, если оба типа являются отрезками одного и того же базового. Именно поэтому допустимы обращения вида Y(n2,n).

5. Если тип формального параметра-значения является вещественным, то совместимым с ним считается любой числовой тип фактического параметра. Например, допустимы обращения X(s,r), X(t,r), X(k,r), X(n,r), X(n2,r) и т. п.

6. Если тип формального параметра-значения является целочисленным, то совместимым с ним считается любой целочисленный тип фактического параметра. Поэтому допустимы обращения Y(k,n), Y(m,n) и т. п. А вот обращения Y(s,n), Y(t,n) и Y(r,n) недопустимы.

Всё только-что сказанное в отношении совместимости типов для параметров-значений касается и параметров-констант.

Отметим, что условия совместимости типов для формальных и фактических параметров-значений (и параметров-констант) полностью совпадают с условиями совместимости по присваиванию. И так же, как в случае оператора присваивания, синтаксически правильный оператор обращения к процедуре не обязательно может быть выполнен. Здесь уже многое зависит от того, соответствуют ли друг другу допустимый диапазон значений формального параметра и конкретное значение фактического. Если значение фактической переменной выходит за допустимые пределы для типа формального параметра, то будет получено сообщение об ошибке времени выполнения “Error 201: Range check error” – выход значения за пределы допустимого диапазона.

Формально правило выполнения оператора обращения к процедуре состоит в следующем:

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

-       Выполняются операторы процедуры, к которой указано обращение.

-       Фактическим параметрам-переменным присваиваются значения соответствующих формальных параметров.

3. Функции пользователя.

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

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

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

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

При описании функции используется зарезервированное слово Function. Тип функции указывается после списка параметров через двоеточие.

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

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

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

В качестве примера рассмотрим оформление подпрограммы вычисления значения функции y = ln (sin x + cos x).

   Function f ( x: Real; Var y: Real ): Boolean;
      Var z: Boolean; a: Real;
   Begin
      a := Sin(x) + Cos(x);
      z := a > 0; f := z;
      If z Then y := Ln(a)
   End;

При построении подпрограммы f применён принцип вычисления значений функций с разрывами. Подпрограмма f имеет два результата. Один из них – значение заданной функции y, которое при определённых значениях аргумента не всегда может быть не вычислено, второй – флажок логического типа, сигнализирующий об этом. Оба результата имеют простой тип, и в принципе любой из них может быть передан через имя функции. Однако целесообразнее сделать это для флажка в виде f(x:Real; Var y:Real):Boolean.

При этом становится возможной конструкция вида “If f(x,y) Then <операторы_1> Else <операторы_2>”. Смысл такой конструкции состоит в следующем. Обращение к подпрограмме вычисления значения функции y при заданном аргументе x представлено как логическое выражение команды ветвления. Если f(x,y) оказалось истинным, то значение y вычислено, и поэтому после слова Then можно указывать <операторы_1>, использующие его. Если же f(x,y) оказалось ложным, то после слова Else должны быть только <операторы_2>, которые значение y не используют.

В ИСП предусмотрен элемент расширенного синтаксиса, состоящий в том, что обращения к функциям (за исключением стандартных) можно записывать в виде отдельных операторов, то есть так же, как и к процедурам. Естественно, что значение функции будет при этом теряться. Для реализации указанной возможности следует указать директиву компиляции {$X+}.

Уважаемые подписчики! При необходимости задать вопрос, проконсультироваться, уточнить или обсудить что-либо обращайтесь через Гостевую книгу моего персонального сайта http://a-morgun.narod.ru. При этом настоятельно рекомендую пользоваться браузером Internet Explorer.

С уважением, Александр.


В избранное