
9.Подпрограммы, их классификация. Рекурсия Способы оформления подпрограмм. Обращение к подпрограммам. Передача фактических параметров. Использование общих областей памяти. Формальные параметры. Параметры-значения и параметры-переменные. Локальные и глобальные переменные. Рекурсия.
Подпрограмма - это именованная логически законченная группа операторов языка, которую можно вызвать для выполнения любое количество раз из различных мест программы. В языке Turbo Pascal существуют две разновидности подпрограмм: процедуры и функции. Классификация подпрограмм При работе с Макроассемблером подпрограммы (процедуры) делятся на ближние и дальние, внутренние и внешние. Два первых термина характеризуют способ вызова подпрограммы и возврата из нее, а два вторых - локализацию подпрограмм по отношению к тексту задачи
Процедура - это независимая поименованная часть программы, предназначенная для выполнения определенных действий. По структуре ее можно рассматривать как небольшую программу. После однократного описания процедуру можно вызвать по имени из последующих частей программы. После выполнения процедуры программа продолжится с оператора, следующего непосредственно за оператором вызова процедуры. Имя процедуры не может находиться в выражении в качестве операнда.
Функция аналогична процедуре, но имеет два отличия:
1) функция передает в программу результат своей работы в виде значения простого типа;
2) имя функции может находиться в выражении как операнд.
Понятие рекурсии.
Язык Паскаль допускает, чтобы подпрограмма вызывала саму себя (рекурсивное обращение). Эта возможность связана с тем, что при каждом новом обращении к подпрограмме параметры, которые она использует, заносятся в стек, причем параметры предыдущего обращения тоже сохраняются.
В ряде случаев (обычно для рекурсивных алгоритмов) рекурсивное оформление подпрограммы может быть компактным и эффективным, но не следует забывать об опасности переполнения стека.
Пример: вариант функции, рекурсивно вычисляющей факториал числа N.
Function Factorial (N: Byte): LongInt;
Begin
If N in [0..1]
Then Factorial :=1
Else Factorial := N* Factorial(N-1)
End;
оформление подпрограмм
Использование подпрограмм (subroutine) или процедур (procedure) является одним из универсальных приемов программирования. Возможность работы с ними предусмотрена во всех языках программирования. Изначально идея заключалась в следующем: неоднократно выполняемые действия оформляются в виде самостоятельного фрагмента программы так, чтобы к нему можно было обратиться из любой ее точки и затем вернуться назад. Со временем эта идея развилась, появилась категория процедур, текст которых не описывается в программе, а готовится заранее, хранится в специальных библиотеках и доступен для любых программ. В комплект компиляторов с алгоритмических языков обычно включены библиотеки, содержащие процедуры различного назначения, в том числе и для работы с новым периферийным оборудованием. В настоящем приложении описана техника составления процедур при программировании на Макроассемблере. Особое внимание уделено рассмотрению условий, при которых такие процедуры могут использоваться в программах, составленных на языках высокого уровня Си, Паскаль, Фортран и др. Именно ради этого данное приложение включено в текст книги.
Обращение к подпрограмме (ее вызов) выполняет специальная команда сан, содержащая адрес точки входа. Для его указания можно использовать все стандартные способы адресации, например, имя точки входа, явное задание адреса, выбор адреса из регистра и т. д. Команда call помещает в стек адрес возврата и выполняет безусловный переход на указанную точку входа. Адресом возврата является текущее содержимое счетчика команд (IP). После выборки кода инструкции и операндов IP всегда содержит адрес начала следующей команды. Таким образом, специальная команда call нужна для того, чтобы сформировать в стеке адрес возврата для команды ret, завершающей выполнение подпрограммы. Подпрограмма может работать, и обычно работает, со стеком. Причем к моменту выполнения команды ret в верхушке стека должен находиться адрес возврата. Сказанное не означает, что его нельзя изменять. Это делается в особых случаях, когда по каким-то причинам надо вернуться не на вызывающий модуль, а в любое другое место задачи.
Передача параметров
В стандарте языка Паскаль передача параметров может производиться двумя способами - по значению и по ссылке. Параметры, передаваемые по значению, называют параметрами-значениями, передаваемые по ссылке - параметрами-переменными. Последние отличаются тем, что в заголовке процедуры (функции) перед ними ставится служебное слово var.
При первом способе (передача по значению) значения фактических параметров копируются в соответствующие формальные параметры. При изменении этих значений в ходе выполнения процедуры (функции) исходные данные (фактические параметры) измениться не могут. Поэтому таким способом передают данные только из вызывающего блока в подпрограмму (т.е. входные параметры). При этом в качестве фактических параметров можно использовать и константы, и переменные, и выражения.
При втором способе (передача по ссылке) все изменения, происходящие в теле процедуры (функции) с формальными параметрами, приводят к немедленным аналогичным изменениям соответствующих им фактических параметров. Изменения происходят с переменными вызывающего блока, поэтому по ссылке передаются выходные параметры. При вызове соответствующие им фактические параметры могут быть только переменными.
Выбор способа передачи параметров при создании процедуры (функции) происходит в соответствии со сказанным выше: входные параметры нужно передавать по значению, а выходные - по ссылке. Практически это сводится к расстановке в заголовке процедуры (функции) описателя var при всех параметрах, которые обозначают результат работы подпрограммы. Однако, в связи с тем, что функция возвращает только один результат, в ее заголовке использовать параметры-переменные не рекомендуется.
Все глобальные переменные и типизированные константы размещаются в одной непрерывной области оперативной памяти, которая называется сегментом данных. Длина сегмента определяется архитектурой процессора 8086 и составляет 64 Килобайта (65536 байт), что может вызвать определённые трудности при описании и обработке больших массивов данных. С другой стороны объём стандартной памяти - 640 Килобайт. Выход - использовать динамическую память.
Формальные параметры – это наименование переменных, через которые передается информация из программы в процедуру либо из процедуры в программу. Формальные параметры указывают, с какими параметрами следует обращаться к этой подпрограмме (количество параметров, их последовательность, типы). Они задаются в заголовке подпрограммы в виде списка формальных параметров, разбитого на группы, разделенные точками с запятыми. В группу формальных параметров включаются однотипные параметры одной категории. В языке Turbo Pascal существует четыре категории формальных параметров:
1. параметры-значения, которые в подпрограмме не изменяются;
2. параметры-переменные, которые подпрограмма может изменить и передать в основную программу;
3. параметры-константы (используются только в версии 7.0);
4. параметры-подпрограммы (параметры процедурного типа).
Для каждого формального параметра следует указать его имя и через двоеточие тип, а в случае параметра-переменной или параметра-константы - его категорию. Тип формального параметра может быть практически любым, однако в заголовок подпрограммы нельзя вводить новый тип. Например, нельзя записать:
Function Max(A: array[1..100] of Real): Real;
Параметр-значение не может быть файлового типа. Если параметров-значений одного типа несколько, их можно объединить в одну группу, перечислив их имена через запятую, а затем через двоеточие указать общий тип, например:
Procedure One(Max,Min: Real; Number: Word);
Function Two(X,Y: Integer): Real;
Параметр-переменная указывается в заголовке подпрограммы аналогично параметру-значению, но перед именем параметра записывается слово Var. Действие слова Var распространяется в пределах одной группы параметров (до ближайшей точки с запятой). Тип параметров-переменных может быть любым, включая файловый.