Учебное пособие Для студентов технических специальностей всех форм обучения


Глава 5. Процедурное программирование



бет12/24
Дата10.03.2016
өлшемі2.27 Mb.
#49466
түріУчебное пособие
1   ...   8   9   10   11   12   13   14   15   ...   24

Глава 5. Процедурное программирование

§5.1. Функции


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

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

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

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

Структура программы практически повторяет структуру всей Паскаль-программы, что подчеркивает регулярный характер языка. Структура подпрограммы-функции следующая.
Function <имя>[(<список формальных параметров>)]:<тип>;

[<описания>;]



<операторы>

End;
Здесь <имя> – имя функции, по которому происходит обращение к ней при вычислении выражения, с ним связан результат вычислений. Имя функции должно встречаться хотя бы один раз в разделе операторов функции слева в операторе присваивания, то есть результат функции должен быть определен.



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

<список формальных параметров> может отсутствовать. Формальным параметрам, в отличие от фактических, не соответствуют никакие значения, – они лишь ставят в соответствие фактические значения и порядок вычислений по подпрограмме, то есть в этом списке должны быть только имена. Каждый параметр, заданный в заголовке, считается локальным в данной подпрограмме так же, как и переменные, описанные в блоке этой подпрограммы.

Допускается три способа задания формальных параметров подпрограммы (в заголовке в круглых скобках). Они могут быть определены следующим образом.


Параметры – значения


Это наиболее распространенный и самый простой способ передачи параметров, который имеет следующий вид:

<имя1>, <имя2>, …, <имяn>:<имя типа>

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

Function Z(A:array[1..20] of real):real;

Пример: функция вычисления суммы квадратов.

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

Begin


SumSqr:=x*x+y*y

End;

Параметры – переменные


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

Var <имя1>, <имя2>, …, <имяn>:<имя типа>;

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

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


Бестиповые параметры


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

Var <имя1>, …

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

A := x+SumSqr(5.3,c+d);


§5.2. Процедуры


Описание процедур похоже на описание функций. Более того, функции есть разновидность процедур с возвращаемым результатом, который используется в выражении. Функции просто применяют для упрощения составления программ, в машинном языке присутствуют только процедуры. Описание процедуры имеет вид:

Procedure <имя>[(<список параметров>)];

[<описания>;]



<операторы>

End;


Имя и параметры здесь те же, что и в подпрограммах-функциях. Но есть и отличия процедур от функций:

  1. С именем процедуры, в отличие от функции, не связано никакое значение, поэтому имени в теле процедуры значение не присваивается и, соответственно, не указывается тип возвращаемого результата.

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

Правила использования подпрограмм


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

  2. В подпрограммах допускается наличие вложенных подпрограмм, количество вложений не ограничено.

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

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

Procedure P(x,y:real; Var Res:real);

Begin


If x Res:=Sqrt(x*x-y*y)

End;

Procedure P(x,y:real; Var Res:real);



Begin

If x>=y Then Res:=Sqrt(x*x-y*y)

End;

Рекурсия


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

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

Большинство циклических алгоритмов с известным количеством повторений можно записать с помощью рекурсии, например, вычисление факториала или суммы:

Program SumRec;

Var S:real;

Procedure Sum(Var S:real;N:integer);

Begin

If N=1 then



S:=1

Else


Begin

Sum(S,N-1);

S:=S+1/N

end


end;

Begin


sum(S,100);

Writeln('Сумма=',S:10:4)

end.

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


Директивы


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

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

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

Procedure Q(x:T); Forward;

Procedure P(y:T);

Begin



Q(A);


end;


Procedure Q;

Begin



P(B);


end;


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

В Турбо-Паскале есть еще несколько директив, относящимся к подпрограммам. Если подпрограмма или группа подпрограмм разработана вне системы Турбо-Паскаль, например, на языке Ассемблер или Си, а их объектный код находится в объектном файле, то такую подпрограмму можно подключить с помощью директивы External, дополнительно задав директиву компилятора $L с именем OBJ-файла:

Procedure SqRoots(A,B,C:word); external;

{$L ROOTS.OBJ}



Для обеспечения корректности такого подключения необходимо соблюдать определенные межъязыковые соглашения о связях.

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

Для подпрограммы допускается указание типа вызова процедуры: дальний (межсегментный) или ближний (внутри одного сегмента), задаваемые соответственно словами Far и Near. Они эквивалентны директивам компилятора {$F+} и {$F }.

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


Процедурные типы


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

Общее описание процедурного типа следующее:


Type <имя типа>=Function (<список параметров>):<тип>;

Type <имя типа>=Procedure (<список параметров>);

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


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

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

  3. Данные подпрограммы не могут быть вложенными в другие подпрограммы.

  4. Такие подпрограммы не могут быть процедурами прерываний.

Пример использования подпрограмм


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

.

Вычисление производится по формуле



,

где , ,

количество отрезков разбиения площади интегрирования определяется по заданной точности  = 10-3. Сначала интеграл представляется в виде одной трапеции, потом двух, потом четырех и т.д., то есть шаг интегрирования в каждом цикле уменьшается в два раза.

Program SumInt;

{ Демонстрационная программа на использование функций: вычисление суммы двух интегралов методом трапеций с заданной точностью }

Const EPS=1E-3; { Точность зададим константой }

Type Func=Function(x:real):real; { процедурный тип }

Var SI:Real; { Результат: сумма интегралов }

{ Сначало опишем подпрограммы с использованием дальнего вызова, которые будут передаваться в подпрограмму как параметры }

{$f+}


Function F1(x:real):real;

Begin


F1:=exp(-x)*(x*x+7*x+9)

End;


Function F2(x:real):real;

Begin


F2:=sin(x)*(x*x*x+3)

End;


{$f-}

{ В функцию передаем границы (вещественные) и последовательность вычислений – процедурный тип }

Function IntTrap(A,B:Real;F:Func):real;

Var IntAlt,IntNew, { старое и новое значение интеграла }

H,S,x,

v:real; { вспомогательная переменная }



Begin

H:=B-A;


v:=F(A)+F(B); { для сокращения вычислений }

IntNew:=H/2*v; { Первый интеграл из одной трапеции }

Repeat

IntAlt:=IntNew; { Старим предыдущее значение }



H:=H/2; { Уменьшаем шаг в 2 раза }

S:=0; x:=A;

Repeat

x:=x+H;


S:=S+F(x)

Until x>=B;

IntNew:=H/2*(v+2*S);

Until Abs(IntAlt-IntNew)

IntTrap:=IntNew;

End;


{ Раздел операторов – непосредственно сама программа }

Begin


{ Очень важно соблюдать типы и последовательность параметров при обращении к функциям}

SI:=IntTrap(0.0,2.0,F1)+IntTrap(0.0,2.0,F2);

Writeln('Сумма интегралов=',SI:7:3)

End.

Контрольные вопросы


  1. Для каких целей применяют подпрограммы?

  2. Что такое подпрограмма?

  3. Какова общая структура подпрограммы-функции?

  4. Что такое формальные параметры, и где они используются?

  5. Зачем в заголовке функции указывать ее тип?

  6. Когда применяются и как описываются параметры-значения?

  7. Когда применяются и как описываются параметры-переменные?

  8. Какова общая структура подпрограммы-процедуры?

  9. Каковы отличия процедур от функций?

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

  11. Что такое вложенные подпрограммы?

  12. Что такое локальные переменные?

  13. Что такое глобальные переменные?

  14. Какая процедура используется для завершения подпрограммы или всей программы?

  15. Что такое «рекурсия»?

  16. Где используется рекурсия?

  17. Какая директива присутствует в стандартном Паскале?

  18. Когда применяется директива external?

  19. Когда применяется директива inline?

  20. Когда применяется директива assembler?

  21. Когда применяется директива interrupt?

  22. Когда применяется процедурный тип?

  23. Как описывается процедурный тип?

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





Достарыңызбен бөлісу:
1   ...   8   9   10   11   12   13   14   15   ...   24




©dereksiz.org 2024
әкімшілігінің қараңыз

    Басты бет