Часто
некоторую последовательность инструкций требуется повторить в нескольких местах
программы. Чтобы программисту не
приходилось тратить время и усилия на копирование этих инструкций, в
большинстве языков программирования предусматриваются средства для организации
подпрограмм. Таким образом, программист получает возможность присвоить
последовательности инструкций произвольное
имя и использовать это имя в
качестве сокращенной записи в тех местах, где встречается соответствующая
последовательность инструкций.
Подпрограмма
-- некоторая
последовательность инструкций, которая может повторяться в нескольких местах
программы.
Процедурой называется особым образом оформленный фрагмент
программы, имеющий собственное имя (идентификатор), который выполняет некоторую
четко определенную операцию над данными, определяемыми параметрами.
Упоминание
имени процедуры в тексте программы приводит к ее активизации и называется
вызовом процедуры. Вызов может быть осуществлен из любой точки программы. При
каждом таком вызове могут пересылаться
различные параметры. Сразу после активизации процедуры начинают выполняться
входящие в нее операторы, после выполнения последнего из них управление возвращается
обратно в основную программу, и выполняются операторы, стоящие непосредственно
за оператором вызова процедуры.
Описание процедуры состоит из
заголовка и тела. Заголовок процедуры имеет
вид:
procedure <имя> [ (<сп.ф.п.>) ] ;
здесь
<имя> имя процедуры
(правильный идентификатор); <сп. ф. п. > - список формальных параметров.
Список
формальных параметров необязателен и может отсутствовать. Если же он есть, то в нем должны быть перечислены имена формальных
параметров и их типы, например procedure MyProc (a: Real; b: Integer; с: Char);
Функция отличается от процедуры тем, что результат ее работы возвращается в виде значения этой функции, и, следовательно, идентификатор функции может использоваться наряду с другими операндами в
выражениях. Описание функции состоит из заголовка и тела. Заголовок функции
имеет следующий вид:
function <имя> [(<сп.ф.п.>)]: <тип>;
здесь <тип> — тип возвращаемого функцией
результата. Заголовок
функции может иметь следующий вид:
function MyFunc
(a,
b: Real): Real;
Операторы тела подпрограммы рассматривают список формальных параметров как своеобразное расширение раздела описаний: все переменные из этого списка могут использоваться в любых выражениях внутри подпрограммы. Так осуществляется настройка алгоритма подпрограммы на конкретную задачу. Работа с процедурами
и функциями отличаются в следующем:
1)
в заголовке функции помимо описания формальных параметров обязательно указывается тип возвращаемого ею результата;
2)
для возврата функцией значения в точку вызова среди ее операторов должен быть хотя бы один, в котором имени функции или
переменной Result присваивается значение результата;
3)
вызов
процедуры выполняется отдельным оператором;4)
вызов
функции может выполняться там, где допускается ставить выражение, например, в правой части оператора присваивания. ПЕРЕДАЧА ПАРАМЕТРОВ
Для обмена
информацией между основной программой и
процедурой используется один или несколько параметров вызова. Они перечисляются
за именем процедуры и вместе с ним образуют оператор ее вызова.
Механизм замены формальных параметров на фактические позволяет нужным образом настроить алгоритм, реализованный в подпрограмме. Компилятор обычно следит за тем, чтобы количество и тип
формальных параметров строго соответствовали количеству и типам фактических параметров в момент обращения к подпрограмме.
Смысл используемых фактических параметров зависит от того, в каком
порядке они перечислены при вызове подпрограммы. Поэтому программист должен сам следить за правильным порядком
перечисления фактических параметров при обращении к подпрограмме. Формальные параметры подпрограммы могут
быть трех видов:
параметры-значения;
параметры-переменные;
параметры-константы.
Например, procedure MyProc (A: Real; var В: Real; const С:
String);
здесь А - параметр-значение, в - параметр-переменная, С -
параметр-константа.
Способ
определения формального параметра очень важен для вызывающей программы. Если формальный параметр объявлен как параметр-значение
или параметр-константа, то при вызове ему может соответствовать произвольное
выражение. Если формальный параметр объявлен как параметр-переменная, то при
вызове подпрограммы ему должен
соответствовать фактический параметр в виде переменной нужного типа.
Чтобы понять,
в каких случаях использовать тот или иной тип параметров, нужно знать, как
осуществляется замена формальных параметров на фактические в момент обращения к
подпрограмме.
Если параметр
определен как параметр-значение, то перед вызовом
подпрограммы это значение вычисляется, полученный результат копируется во временную память и передается подпрограмме.
Любые возможные изменения в подпрограмме параметра-значения никак не
воспринимаются вызывающей программой, так как в этом случае изменяется копия
фактического параметра.
Если параметр определен как параметр-переменная, то при вызове подпрограммы передается сама переменная, а не ее копия (фактически
в этом случае подпрограмме передается адрес переменной). Изменение параметра-переменной приводит к изменению самого
фактического параметра в вызывающей программе.
В случае параметра-константы
в подпрограмму также передается адрес
области памяти, в которой располагается переменная или вычисленное значение. Однако компилятор блокирует любые присваивания параметру-константе нового значения в теле подпрограммы.
Параметры-переменные
используются как средство связи алгоритма,
реализованного в подпрограмме, с внешним миром. С помощью этих параметров
подпрограмма может передавать результаты своей работы вызывающей
программе.
Однако
описание всех формальных параметров как параметров-переменных нежелательно по
двум причинам. Во-первых, это исключает возможность вызова подпрограммы с
фактическими параметрами
в виде выражений, что делает программу менее компактной. Во-вторых, в
подпрограмме возможно случайное использование формального параметра, например,
для временного хранения промежуточного результата, т.е. всегда существует
опасность непреднамеренно испортить фактическую переменную.
По той же
причине не рекомендуется использовать параметры-переменные в заголовке
функции. Если результатом работы функции не может быть единственное значение,
то логичнее использовать процедуру или
нужным образом декомпозировать алгоритм на несколько подпрограмм.
Существует еще одно обстоятельство,
которое следует учитывать при выборе вида
формальных параметров. Как уже говорилось, при объявлении
параметра-значения осуществляется копирование фактического параметра во
временную память. Если этим параметром будет
массив большой размерности, то существенные затраты времени и памяти на копирование при многократных обращениях
к подпрограмме можно минимизировать, объявив этот параметр
параметром-константой. Параметр-константа не копируется во временную область памяти, что сокращает затраты времени на
вызов подпрограммы, однако любые его изменения в теле подпрограммы невозможны - за этим строго следит
компилятор.
Нетипизированные параметры. Одним из свойств языка Object Pascal является
возможность использования нетипизированных параметров.
Параметр считается нетипизированным, если тип формального параметра-переменной в заголовке подпрограммы не указан, при этом соответствующий ему фактический параметр может быть переменной
любого типа. Нетипизированными могут быть только параметры-переменные: procedure MyProc(var aParametr);
Нетипизированные параметры обычно используются в случае, когда тип
данных несуществен. Такие ситуации чаще всего возникают при разного рода
копированиях одной области памяти в другую, например, с помощью процедур BlockRead, BlockWrite, Move-Memory и т. п.
Процедурные типы. Основное назначение процедурных типов — дать программисту гибкие средства передачи функций и процедур в качестве фактических параметров обращения к другим процедурам и функциям. Для объявления процедурного типа
используется заголовок процедуры (функции), в котором опускается ее имя,
например:
type
Prod = procedure (a, b, с: Real; var d: Real);
РгосЗ == procedure;
Fund = function: String;
Func2 = function (var s:
String): Real;
В программе могут быть
объявлены переменные процедурных типов,
например:
var
p1 :
Proc1;
fl, f2: Func2;
ар: array
[1. . N] of Prod;
Переменным процедурных типов допускается присваивать в качестве
значений имена соответствующих подпрограмм. После такого присваивания имя переменной становится синонимом имени
подпрограммы.
|