Читайте также: |
|
Побочный эффект
Функция – это подпрограмма, возвращающая обязательное значение. Общий вид определения функции:
function Имя_функции(S): TF;
Разделы описаний
Begin
Основной блок функции
End;
Здесь S обозначает список описаний формальных параметров, который может отсутствовать – тогда опускаются и скобки. TF – имя типа значения функции. В качестве типа функции TF используются простые типы, а из сложных – разрешены только строковый и ссылочный типы. Разделы описаний и основной блок аналогичны таким же разделам процедуры. Возвращаемое значение функции связывается с её именем, поэтому среди инструкций основного блока должно выполниться хотя бы одно присваивание вида
Имя_функции := выражение_типа_TF
Таким образом, самая короткая функция выглядит так:
function Имя_функции: TF;
Begin
Имя_функции := выражение_типа_TF
End;
Обращение к такой функции состоит только из одного имени функции.
При указании имени функции в каких-либо выражениях в её основном блоке в качестве простой переменной – это воспринимается как попытка рекурсивного вызова (смотри далее Тему "Рекурсия").
Всё сказанное о параметрах процедуры остаётся верным и для функции, только использование передачи параметров по ссылке носит название побочного эффекта. В этом случае, кроме основного обязательного значения функции, через такие параметры могут вернуться дополнительные значения. Для упрощения логики программы и избежания труднообнаружимых ошибок побочный эффект рекомендуется применять только при крайней необходимости. В следующем примере из-за побочного эффекта на экран выдаётся значение 10 вместо (по-видимому, ожидаемого) значения 9. Здесь функция F вычисляется первой и успевает модифицировать второе слагаемое – переменную A – до вычисления суммы:
function F(var X: Integer): Integer;
Begin
X := X + 1;
F := X*X*X
end; {F}
Var
A: Integer;
Begin
A := 1;
WriteLn(F(A) + A)
End.
Если глобальная переменная доступна в какой-то функции и модифицируется ею, то это также является побочным эффектом.
Лекция 12. Рекурсия.
Модули.
Процедурный (функциональный) тип – это множество однотипных либо процедур, либо функций. Определение процедурного типа имеет вид:
Type
TP1 = procedure (S);
а определение функционального типа:
TF1 = function (S): TF;
здесь TP1, TF1 – имя того или иного типа, S – обычный список описаний формальных параметров, который может отсутствовать – тогда опускаются и скобки. TF – имя типа значения функции. Принадлежность реальной процедуры или функции определённому типу устанавливается по типам в списке S, а для функций – ещё и по типу TF. Имена формальных параметров могут не совпадать с именами в определении процедурного типа – обязательным является совпадение их типов.
Однотипные процедурные переменные разрешается присваивать друг другу. Имена реальных процедур и функций являются константами процедурного типа, и их можно присваивать однотипным процедурным переменным – такие переменные становятся синонимами соответствующих подпрограмм. При этом должно соблюдаться ограничение по модели памяти.
В Турбо Паскале приняты две модели памяти – дальняя и ближняя. Компилятор по умолчанию придерживается ближней модели памяти для простых программ. В этом случае машинный код получается более быстрый по исполнению и занимает меньший объём памяти. Однако для процедурного типа по умолчанию используется дальняя модель. Поэтому для полного соответствия подпрограммы процедурному типу она должна определяться в дальней модели памяти.
Для этого после её заголовка ставится стандартная директива far; (точка с запятой – обязательно!). Возможен и другой способ определения дальней модели памяти уже для целой группы подпрограмм: перед определением первой подпрограммы ставится директива компилятору {$F+} (включить компиляцию дальней модели). После конца текста последней подпрограммы можно, наоборот – поставить директиву {$F-} (возобновить компиляцию ближней модели).
Процедурный тип обычно необходим при передаче имён одних подпрограмм в качестве параметров других подпрограмм. Например, в задаче численного нахождения определённого интеграла от какой-то функции удобнее запрограммировать подынтегральную функцию отдельно и передавать её имя в качестве параметра. Тогда подпрограмма нахождения интеграла получает свойство массовости, то есть не привязана к конкретной функции. И в этом случае передаваемая подпрограмма должна быть откомпилирована в дальней модели памяти. Запрещается в качестве параметра передавать имя стандартной функции, в этом случае можно написать свою вспомогательную функцию и в ней обратиться к стандартной, а передавать имя вспомогательной функции.
Рекурсия – это обращение к подпрограмме из тела самой этой же подпрограммы. В языке Паскаль рекурсия разрешена. Рекурсивный алгоритм выглядит изящней при решении математических задач, сама формулировка которых имеет рекурсивный характер. В этом случае задача может быть разложена на совокупность подзадач того же типа, но меньшей размерности. Классический пример – вычисление факториала: N! = N*(N - 1)! для
N > 0 и 0! = 1! = 1. Здесь исходная задача размерности N разложена на произведение N и решения подзадачи размерности N - 1.
Методика создания рекурсивных алгоритмов содержит три этапа:
1) параметризация задачи;
2) поиск тривиального случая и его решение;
3) декомпозиция общего случая.
При каждом вызове подпрограммы её локальные переменные и адрес возврата из подпрограммы заносятся в специальную область памяти, называемую стеком. По окончании выполнения подпрограммы и выходе из неё эта область стека освобождается. В случае рекурсивного вызова локальная память не освобождается, а впадает в "зимнюю спячку", в стеке выделяется новая область под новые значения локальных переменных и новый адрес возврата. Доступ к стеку производится по принципу "последним пришёл – первым ушёл" (Last In, First Out – LIFO), поэтому при выходе из подпрограммы возврат производится в точку её последнего вызова. Таким образом, организация стека обеспечивает реализацию рекурсии.
Рекурсия может быть косвенной: подпрограмма A вызывает подпрограмму B, а та, в свою очередь, вызывает A. В этом случае нарушается принцип сильной типизации языка Паскаль: подпрограмма должна быть определена до обращения к ней. В такой ситуации выносят заголовок подпрограммы, определённой ниже, перед первой подпрограммой, а вместо тела, после заголовка, указывают стандартную директиву forward; (точка с запятой – обязательно!)
Модуль – это автономно компилируемая программная единица, включающая в себя любые компоненты раздела описаний (обычно, прежде всего – подпрограммы) и, возможно, какие-то инструкции. Модуль, в отличие от программы, не может быть запущен на выполнение самостоятельно: он может только участвовать в построении программы или другого модуля.
Текст модуля размещается в отдельном.pas файле, например gauss.pas. Результатом компиляции модуля является двоичный файл с расширением.tpu (Turbo Pascal Unit), например gauss.tpu. Чтобы подключить модуль к программе или к другому модулю, необходимо указать имя модуля в соответствующем разделе uses.
Общий вид модуля:
unit Имя_модуля;
Дата добавления: 2015-07-15; просмотров: 156 | Нарушение авторских прав
<== предыдущая страница | | | следующая страница ==> |
Безусловного перехода, | | | Interface |