Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
2- Введение в программирование.doc
Скачиваний:
1
Добавлен:
01.07.2025
Размер:
753 Кб
Скачать
☆

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

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

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

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

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

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

Структура процедуры во многом повторяет структуру программы в целом:

Procedure <имя> (<список формальных параметров>);

Label <метки внутри тела процедуры>;

Const <локальные константы процедуры>;

Type <локальные типы>;

Var <локальные переменные>;

Procedure <вложенные процедуры и функции>;

…

Function

…

Begin

<операторы – тело процедуры>

End;

Отличие от структуры программы состоит в заголовке и завершающей «;» вместо «.» после оканчивающего End. Порядок следования разделов описаний подчиняется тем же правилам, по которым строится вся программа. В отличие от стандартного языка Pascal в ТР разделы Label, Type, Const, Var могут следовать друг за другом в любом порядке и встречаться в разделе описаний сколько угодно раз. Однако поскольку программа компилируется последовательно, начиная с начала, важно соблюдать правило: все, что в программе используется должно быть перед этим описано.

Отличие структуры функции от структуры процедуры состоит в указании типа возвращаемого значения функции:

Function <имя> (<список формальных параметров>) : <тип>;

Label

…

End;

Поскольку процедуры и функции должны обладать определенной независимостью в смысле использования переменных и т.д., при их введении в программу возникает разделение данных и их типов на глобальные и локальные. Глобальные константы, типы, переменные – это те, которые объявлены в программе вне процедур или функций. Локальные – это константы, типы, переменные, существующие только внутри процедур или функций, и объявленные либо в списке формальных параметров (только параметры-значения), либо в соответствующих разделах Const, Type, Var внутри данной процедуры или функции. Считается, что все имена, описанные внутри подпрограммы (локальные данные), локализуются в ней, т.е. они как бы "невидимы" снаружи подпрограммы. Подпрограммы, наряду со своими локальными данными, могут использовать и модифицировать и глобальные. Для этого лишь нужно, чтобы описание процедуры (функции) стояло в тексте программы ниже, чем описание соответствующих глобальных типов, констант и переменных.

Program Main;

Var

Xmain, Ymain : Integer; {глобальные переменные}

Procedure P1; {описание процедуры, у которой нет параметров}

Var

Res : Real; {локальные переменные}

begin

Res := 0.5;

Res := Res + Xmain*Ymain;

Xmain := Xmain + 1

end;

…

Var {описание других переменных, недоступных из Р1}

…

Begin

…

P1; {вызов процедуры}

…

End.

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

Параметры

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

Procedure <имя> ( <имя п.-з.> : <тип>;

Var <имя п.-п.> : <тип>;

Const <имя п.-к.> : <тип>);

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

Procedure P1 (A : Integer; Var B : Real)

…

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

Р1 (Afact,Bfact);

Переменная Аfact (типа Integer) действует в основной программе. Ее значение подставляется в подпрограмму при ее вызове на место формального параметра А.

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

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

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

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

Пример удвоения чисел, где одно задается как параметр-переменная, а второй - как параметр-значение.

Const

A : Integer = 5;

B : Integer = 7; {типизированные константы - переменные}

Procedure Plus (Var C : Integer; B : Integer);

begin {в процедуре одна локальная переменная В)

C := C + C;

B := B + B;

Writeln(C,B)

end;

Begin

Writeln(A,B);

Plus(A,B);

Writeln(A,B)

End.

Вначале на экран будут выведены числа "5 7". В вызове процедуры Plus фактическими параметрами являются параметр-переменная А и параметр-значение В. Переменная А во время действия процедуры меняет свое значение (в течении процедуры она выступает с именем С), новое удвоенное значение записывается на место старого. Переменная В копирует свое значение в локальную переменную с тем же именем. После выполнения процедуры на экране появляются "10 14". Последний оператор выводит на экран числа "10 7".

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

Существенное различие в объявлении переменных в списке формальных параметров от объявления их в разделе описания переменных состоит в том, что типом любого параметра в списке формальных параметров может быть только стандартный или ранее объявленный тип (не годится Procedure P (A : array [1..10] of Real)). Поэтому для того, чтобы передать массив (или строку) нужно сначала описать его тип. Это накладывает некоторые ограничения в том случае, когда заранее не известна длина массива (строки). Описывать его по максимуму приводит к затратам памяти. Вообще, невозможность использования статических массивов с "плавающими" границами является существенным недостатком ТР, и объектом его критики. В версии 7.0 язык поддерживает т.н. открытые массивы, с помощью которых легко решается проблема передачи подпрограмме одномерных массивов переменной длины. Открытый массив - формальный параметр описывается как:

Procedure P (OpenArray: array of Real). В этом случае можно подставлять в процедуру фактические одномерные массивы любой длины. Верхняя граница возвращается функцией High.