- •Внимание! Серым цветом выделен необязательный материал! Глава «Введение» - также для общего развития.
- •Курс лекций по программированию на языке Pascal Содержание курса
- •Введение
- •Программное управление компьютером
- •Этапы разработки программного обеспечения. Языки программирования.
- •Языки программирования
- •Трансляция
- •Алгоритмы и структурное программирование
- •Основные структуры алгоритмов. Понятие о структурном подходе к разработке алгоритмов
- •Методы разработки программного обеспечения
- •Структуры данных
- •Сортировка
- •Стратегии распределения памяти
- •Объектно-ориентированное программирование
- •Базовые элементы языка тurbo рascal
- •Алфавит
- •Константы и переменные
- •Выражения и операции
- •Структура программы
- •Типы данных языка тр
- •Простые типы
- •Целые типы
- •Логический тип
- •Символьный тип
- •Перечисляемый тип
- •Вещественный тип
- •Математические функции
- •Математические процедуры
- •Структурированные типы
- •Массивы
- •Множества
- •Процедуры преобразования
- •Совместимость и преобразование типов
- •Управляюшие структуры языка turbo pascal Операторы
- •Простой и составной оператор
- •Условный оператор
- •Оператор множественного выбора
- •Оператор цикла "пока" (с предусловием)
- •Оператор цикла "до" (с постусловием)
- •Оператор цикла с параметром (цикл по счетчику)
- •Оператор безусловного перехода
- •Процедуры и функции
- •Особенности функций
Процедуры и функции
В разделе будут рассмотрены вопросы, связанные с написанием и употреблением подпрограмм, представленных в виде процедур и ли функций.
Процедуры и функции представляют собой относительно самостоятельные фрагменты программы, оформленные особым способом и снабженные именем. Упоминание этого имени в тексте программы называется вызовом процедуры (функции).
Подпрограммы представляют собой инструмент, с помощью которого любая программа может быть разбита на ряд в определенной степени независимых друг от друга частей. Такое разбиение имеет смысл по двум причинам.
Во-первых, это средство экономии памяти и других ресурсов: каждая подпрограмма существует в программе в единственном экземпляре, в то время как обращаться к ней можно многократно из разных точек программы. При вызове подпрограммы активизируется последовательность образующих ее операторов, а с помощью передаваемых подпрограмме параметров нужным образом модифицируется реализуемый в ней алгоритм.
Во-вторых, при таком разбиении максимально реализуется принцип нисходящего проектирования. В этом случае алгоритм представляется в виде последовательности относительно крупных подпрограмм, реализующих более или менее самостоятельные смысловые части алгоритма. Подпрограммы в свою очередь разбиваются на менее крупные подпрограммы нижнего уровня и т.д. Все заканчивается, когда реализуемые подпрограммами алгоритмы не станут настолько простыми, чтобы их можно было запрограммировать.
Структура процедуры во многом повторяет структуру программы в целом:
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.
