Учебник по программированию.

Первые шаги. Язык программирования PascalABC.

Предыдущий параграф Назад в содержание Следующий параграф


§4. Процедуры и функции. Константы.

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

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

В начале, научимся пользоваться процедурами. Для того, что бы создать процедуру, необходимо её описать. Делается это следующим образом:


Procedure TryStroky;

begin

  writeln;

  writeln;

  writeln

end;


begin

  writeln('Привет всем!');

  trystroky;

  Writeln('Меня зовут Денис.')

end.

____________________________________________

Привет всем!




Меня зовут Денис.


Данная программа демонстрирует использование процедуры TryStroky (Три строки), которая вставляет 3 пустых строчки. Описание процедуры происходит перед телом программы. Для этого пишется слово Procedure и имя процедуры, после чего ставится точка с запятой:


Procedure TryStroky;


Далее идёт тело процедуры, заключённое словами begin и end:


begin

  writeln;

  writeln;

  writeln

end;


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

Теперь, что бы был понятен смысл использования процедуры, приведу пример такой же программы, но без использования процедуры:


begin

  writeln('Привет всем!');

  writeln;

  writeln;

  writeln

  Writeln('Меня зовут Денис.')

end.

________________________________

Привет всем!




Меня зовут Денис.


Как видно, результат выполнения тот же самый, однако в теле самой программы 3-я, 4-я и 5-я строчки абсолютно идентичны. В данном случае количество строк во всём коде стало даже меньше, но представьте себе, что в результате работы программы необходимо неоднократное выведение 3-х пустых строк. В таком случае использование данной процедуры будет вполне оправдано.

Двигаемся дальше. Часто процедура должна выполнить какие-либо действия с переменными. Например, вывести на экран результат вычислений. Если переменные объявлены до объявления процедуры, то в процедуре можно обратиться к ним, просто используя их имена:


Var y:real;

Procedure VivodRezultata;

begin

  writeln('y=',y);

end;


begin

  y:=2+3;

  VivodRezultata;

end.

____________________________

Y=5


Если мы опишем переменную y после процедуры, то компилятор выдаст ошибку «Неизвестное имя y». Дело в том, что обработка текста программы происходит последовательно, и если вы используете переменную до того как она будет объявлена, то компилятор будет выдавать ошибку так как он не будет знать, что эта переменная где-то объявлена.

Что бы избежать данной ошибки можно передать процедуре значение переменной в качестве параметра. Для этого после имени процедуры в скобках необходимо поместить параметр. Однако это возможно в том случае, если в описании процедуры это предусмотрено. Т.е. если процедура может получать параметр. Делается это следующим образом:


Procedure VivodRezultata(x:real);

begin

  writeln('y=',x);

end;

Var

  y:real;


begin

  y:=2+3;

  VivodRezultata(y);

end.

________________________________

Y=5


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

Сделаем небольшое отступление. В предыдущем абзаце появилось слово константа. Если в тексте программы какое-либо значение не должно меняться, то можно это значение объявить в разделе объявления констант:


Const

  Pi=3.14;


Пишется слово Const, затем имя константы и после знака равно значение этой константы. Обратите внимание, что здесь используется знак равно, а не оператор присваивания. В тексте программы  использование этой константы аналогично переменной, однако если вы попытаетесь изменить её значение, то это будет ошибкой и программа не будет откомпилирована.

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


  Pi=3.14;


Т. е. константой называется либо просто число, либо имя числа, присвоенное в разделе описания констант. Точно так же константой может называться любой другой тип данных. В следующем примере приведена строковая константа «Привет всем»:


  'Привет всем!'

При вызове процедуры, при передаче параметра мы можем написать либо имя константы, объявленное в разделе объявления констант, либо какое-либо число:


  VivodRezultata(pi);

  VivodRezultata(3.14);


В том и другом случае мы будем говорить, что была передана константа.

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

Двигаемся дальше. Прежде чем начать изучение функций, хочу обратить внимание на команды write и read. До этого мы называли их командами, это в принципе не верно. На самом деле это как раз и есть процедуры. В скобках после имён процедур write или read пишется параметр, который передаётся данной функции. Далее мы будем называть их именно процедурами.

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


Var

A,B,C:real;


Function Summ(x,y:real):real;

begin

  Summ:=x+y;

end;


begin

  B:=3.5;

  Writeln('B=',B);

  C:=23.4;

  Writeln('C=',C);

  A:=Summ(B,C);

  Write('B+C=',A);

end.

______________________________

B=3.5

C=23.4

B+C=26.9


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

Приведу ещё один пример функции, но без передаваемых параметров:


Var

A,B,C:real;


Function Summ:real;

begin

  Summ:=B+C;

end;


begin

  B:=3.5;

  Writeln('B=',B);

  C:=23.4;

  Writeln('C=',C);

  A:=Summ;

  Write('B+C=',A);

end.

____________________

B=3.5

C=23.4

B+C=26.9


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

Пришло время поговорить о локальных и глобальных переменных. Переменные, объявленные в самом начале кода программы, могут использоваться в любом месте программы, в любой подпрограмме они являются глобальными. Переменные, объявленные в какой-либо подпрограмме, могут использоваться только подпрограммой. Например, в предыдущей программе, переменные x и y, которые содержат значения передаваемых параметров, являются локальными и могут использоваться только в данной подпрограмме.

Переменные можно объявлять внутри подпрограммы так же, как и в самой программе. Например:


Var

A,B,C:real;


Function Summ:real;

Var

  B,C:real;

begin

  Summ:=B+C;

end;


begin

  B:=3.5;

  Writeln('B=',B);

  C:=23.4;

  Writeln('C=',C);

  A:=Summ;

  Write('B+C=',A);

end.

_____________________

B=3.5

C=23.4

B+C=0


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

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

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

Если что-то непонятно, то прочитайте снова. Если же всё понятно, то можно двигаться дальше.

В подпрограмме может быть одна или несколько подпрограмм. Вдумайтесь внимательно в это предложение. Другими словами, каждая подпрограмма может содержать в себе свои собственные подпрограммы. Ещё можно сказать более обобщённо. Каждая подпрограмма представляет собой самостоятельную программу со своими переменными, константами, процедурами и функциями. Отсюда и название «подпрограмма». Разница лишь в том, что выполнение программы начинается в теле основной программы, а подпрограммы вызываются в течении работы программы. Теперь приведу пример:


Var

A,B,C:real;


Function Summ:real;

Var

  B,C:real;

Procedure Soobshenie;

begin

  Writeln('Заработала функция Summ');

end;

begin

  Soobshenie;

  Summ:=B+C;

end;


begin

  B:=3.5;

  Writeln('B=',B);

  C:=23.4;

  Writeln('C=',C);

  A:=Summ;

  Write('B+C=',A);

end.

_____________________________________

B=3.5

C=23.4

Заработала функция Summ

B+C=0


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

Так же стоит заметить, что подпрограмма Soobshenie может содержать в себе свои подпрограммы, эти подпрограммы в свою очередь свои и так до бесконечности.

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

Ещё есть один нюанс. Имена подпрограмм могут повторяться в том случае, если они созданы в разных подпрограммах.


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


Задачи:

1.Ниже по тексту приведена программа.


Var

  S,Rad:real;

Procedure Soobshenie_1;

begin

  Writeln('Введите радиус круга:');

end;


Procedure Soobshenie_2;

begin

  Writeln('Площадь круга равна:',S);

end;


Function Ploshad(r:real):real;

Const pi=3.14;

Procedure Soobshenie_1;

begin

  Writeln('Заработала функция Ploshad.');

end;

Procedure Soobshenie_2;

begin

  Writeln('Функция Ploshad закончила свою работу.');

end;

begin

  Soobshenie_1;

  Ploshad:=pi*r*r;;

  Soobshenie_2;

end;


begin

  Soobshenie_1;

  Read(Rad);

  S:=Ploshad(Rad);

  Soobshenie_2;

end.


Ответьте на вопросы:

  • Проанализируйте текст программы и напишите результат работы, не используя для этого компьютер;
  • Почему возможно то, что существует по две подпрограммы Soobshenie_1 и Soobshenie_2;
  • Возможно ли в теле основной программы использовать константу pi;
  • Какими являются переменные pi и Rad, глобальными или локальными.


2. Используя подпрограммы, напишите программу вывода на экран вашего полного имени и даты рождения.


Решение:


1.

  • Результат работы программы:

Введите радиус круга:

4

Заработала функция Ploshad.

Функция Ploshad закончила свою работу.

Площадь круга равна:50.24


  • Это возможно, так как они созданы в разных подпрограммах. В первом случае они в основной программе, во втором случае они в подпрограмме Ploshad.
  • В теле основной программы константу pi использовать нельзя, т.к. она создана в подпрограмме Ploshad.
  • Переменные pi и Rad являются глобальными.


2.

Procedure Imya;

begin

  Writeln('Меня зовут Денис.');

end;


Procedure Familiya;

begin

  writeln('Моя фамилия Куклин.');

end;


Procedure Otchestvo;

begin

  writeln('Моё отчество Вадимович.');

end;

Procedure DataRojdeniya;

begin

  writeln('Я родился 30 октября 1981 года.');

end;


begin

  Imya;

  Familiya;

  Otchestvo;

  DataRojdeniya;

end.

_____________________________________________

Меня зовут Денис.

Моя фамилия Куклин.

Моё отчество Вадимович.

Я родился 30 октября 1981 года.




Предыдущий параграф Назад в содержание Следующий параграф