мета-данные страницы
  •  
Загрузка не удалась. Возможно, проблемы с правами доступа?

Это старая версия документа!


Процедуры и функции

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

Процедура (подпрограмма) – большой (более или менее) фрагмент кода, который описан один раз, но может вызываться из разных мест программы. Процедурами, вернее – вызовами стандартных процедур, являются многие команды, такие, как команды ввода/вывода - write, writeln, read и readln.

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

  • стандартные добавляются автоматически,
  • библиотечные требуют подключения внешних библиотек, т.е. наборов дополнительных описаний различных объектов (пример – keypressed, readkey, delay из CRT),
  • локальные описываются в программе.

Библиотеки могут

  • поставляться изначально как стандартные, в составе инструментов разработчика вместе с компилятором, отладчиком и т.д.
  • создаваться программистом или его коллегами для себя;
  • создаваться и распространяться некоторой третьей стороной.

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

Пример, на примере сортировки массива по возрастанию значений с помощью сортировки выбором.

Идея сортировки в следующем: Массив рассматриваем как состоящий в каждый момент работы программы из двух частей - сортированной и несортированной. Сами части будут меняться! В начале считаем, что несортированная часть занимает весь массив, а сортированная - всё остальное, 1) Находим максимальный во всём массиве элемент. В рассматриваемой части массива

| Крайне общий алгоритм программы сортировки массива
uses allForSorting;         // Библиотека "Всё для сортировки". 
                            // Скорее всего - не существует в реальности.
                            // Содержит ВСЁ (происхождение чего мы не хотим объяснять)
 
const 
  n=1000;                   // Размер массива. Выбран по принципу - "а почему бы и нет?"
 
type
  ArrayType = array[1..N] of integer;
                            // Описание типа ("устройства") сортируемого массива
var
  SortedA : ArrayType;      // Объявление самого сортируемого массива
 
begin
  FillArray (SortedA);      // Заполняем наш массив начальными значениями
  PrintArray(SortedA);      // Показываем, что получилось.
  SortArray (SortedA);      // Сортируем наш массив "таинственным способом".
  PrintArray(SortedA);      // Показываем, что получилось
 
end.

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

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

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

Вызов процедуры – применение ранее описанного алгоритма к конкретно указанным объектам уже при работе программы.

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

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

Например, алгоритм сортировки выбором (по возрастанию) требует нахождения максимального элемента на различных частях массива, а также.

Большинство языков программирования позволяют оформлять многократно используемый код в виде процедур и/или функций. Целью написания процедур может быть:

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

стандартизация кода

Процедуры

| Объявление и описание процедуры
procedure somename(x:integer);
// Процедура выводит на экран целое значение x, умноженное на 10.0 
// в указанном формате. 
//
// Написана довольно давно неизвестным программистом 
//
// Такой комментарий, содержащий 
//     цель написания процедуры (что она делает и зачем нужна), 
//     данные о времени написания и об авторе,
//     описания параметров,
//     особенности алгоритма
// полезно включать в код любой процедуры
 
var             // Локальные переменные - могут использоваться только внутри данной процедуры!
  y: real;
 
begin           // Раздел кода процедуры
  y := 10.0;
  x := x * y;
  write(x:10:1);
end;

В данном примере выводится значение x, которое является параметром, умноженное на 10, в формате минимум 10 знаков и с точностью до десятых (одна цифра после десятичной точки).

В качестве параметра x может быть подано любое выражение, совместимое с указанным в описании типом параметра x, т.е. integer.

Функции

FIXME

| Объявление и описание функции
function somename(x:integer):real;
var 
  y: real;
 
begin
  y := 10.0;
  somename := x * y;
end;

Использование глобальных и локальных объектов, а также параметров

Локальные и глобальные объекты

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

Всё, что описано вне процедур, а именно — в самой программе, импортировано из других модулей с помощью предложения uses, а также — системные объекты, вроде процедуры writeln или типа integer, называется глобальными объектами.

Локальные переменные

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

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

  1. между вызовами конкретной процедуры все её локальные переменные просто не существуют и любые попытки обратиться к ним по именам являются синтаксической ошибкой, а попытки обратиться по адресам — опасны;
  2. при рекурсивных вызовах процедур, когда процедура вызывает сама себя, одновременно существует несколько экземпляров одной и той же переменной;
  3. локальные неинициализированные переменные, т.е. не получившие явного начального значения, могут содержать не только нулевые значения, но и любой другой «мусор»;
  4. значения локальных переменных между вызовами не сохраняются.
| Объявление и описание функции
var 
  i,j : integer;                             // Глобальные переменные
 
  procedure P1;                                  // Началось описание процедуры P1
  var                                            //
    k : integer;                                 // к - локальная переменная в P1
                                                     //
    procedure P2;                                    // Вложенная процедура P2
    var                                              //
      n : integer;                                   // n - локальная переменная в P2
                                                     //
    begin                                            // Начался код P2
      ...                                            //
    end;                                             // P2 - закончилась
                                                 //
  begin                                          // Начался код P1
    ...                                          //
    P2;                                          // Вызов P2 
    ...                                          //
  end;                                           // P1 - закончилась
 
var
  m,l:integer;                               // Продолжение описаний глобальных переменных. 
                                             // Необходим новый раздел
                                             //
begin                                        // Начался код самой программы
  ...                                        //
  P1;                                        // Вызов P1 внутри программы 
  ...                                        // 
end.                                         // Вся программа закончилась

Типизированые константы

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

| Объявление и описание функции
Function F:integer;
// синтаксически правильная бессмысленная функция с ужасным кодом и логической ошибкой. 
 
var 
  i : integer;
 
const
  o = 0;                                              // обычная константа
  tConst : integer = 10;                              // Типизированная константа
 
begin
 
  for i := o to tConst do
    F :=                         // Последнее значение переменной F определяет, 
                                 // какое значение вернёт функция F после вызова
          F + i;                 // Здесь F - рекурсивный вызов функции F внутри
                                 // функции F
  if tConst > 0 then dec(tConst);
 
end;

Правила видимости

В языке Паскаль

Параметры

Считается правильным, когда процедура(функция) не обращается скрытым образом к объектам, описанным вне её — в программе или других процедурах и функциях. По крайней мере, она не должна их скрытым образом менять. Если необходимо получить доступ к внешним данным, а тем более их изменить, то рекомендуется делать это явным образом - через передачу в качестве параметров.

Различают формальные и фактические параметры.

Различают способы передачи параметров — передачу по значению и передачу по ссылке.

Формальные и фактические параметры

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

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

Типы формальных и фактических параметров должны соответствовать друг другу, а в некоторых случаях должны точно совпадать.

Передача по значению

Если перед формальным параметром НЕ стоит префикс «var», то говорят, что аргумент передаётся процедуре по значению. Это означает, что компилятором создаётся следующий код:

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

Таким образом, параметр, передаваемый по значению похож на локальную переменную. Такие параметры называют параметрами-значениями.

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

| Пример
procedure badswap(a,b:integer);
var 
  t:integer; 
 
begin
  t := a;
  a := b;
  b := t;
end;

Передача по ссылке

Если перед формальным параметром стоит префикс «var», то говорят, что аргумент передаётся процедуре по ссылке. Это означает, что процедура работает с реальным объектом. Соответственно, все изменения этого объекта сохранятся в программе. Такие параметры называются параметрами -переменными

| Пример
procedure goodswap(var a,b:integer);
// Нормально работающая процедура обмена значениями переменных.
 
var 
  t:integer; 
 
begin
  t := a;
  a := b;
  b := t;
end;

</code>