Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
freePascal 2.0_0.doc
Скачиваний:
13
Добавлен:
01.05.2025
Размер:
343.55 Кб
Скачать

Процедуры и функции. Рекурсия. Модули.

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

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

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

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

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

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

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

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

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

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

•каждая переменная, константа или тип должны быть описаны перед использованием;

•областью действия переменной, константы или типа является та подпрограмма, в которой они описаны;

•все имена в пределах подпрограммы, в которой они объявлены, должны быть уникальными и не должны совпадать с именем самой подпрограммы;

•одноименные локальные и глобальные переменные - это разные переменные, обращение к таким переменным в подпрограмме трактуется как обращение к локальным переменным (глобальные переменные недоступны);

•при обращении к подпрограмме доступны объекты, которые объявлены в ней и до ее описания.

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

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

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

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

Формальные параметры процедуры можно разделить на два класса: параметры – переменные и параметры – значения.

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

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

Параметр - константа указывается в заголовке подпрограммы подобно параметру - значению, но перед его именем записывается зарезервированное слово const, действие которого распространяется до ближайшей точки с запятой. Параметр - константа передаётся в подпрограмму как параметр - переменная, но компилятор блокирует любые присваивания параметру - константе нового значения в теле подпрограммы.

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

Процедуры

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

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

разделы описаний (label, const, type, var)

begin

операторы

end;

В основной программе вызов процедуры осуществляется следующим образом:

begin

имя процедуры [(список параметров)];

end.

Для примера вычислим значение факториала n! с использованием процедуры.

procedure fact1(a:integer);

var i,p:integer;

begin

p:=1;

for i:=1 to a do

p:=p*i;

writeln(a,'!=',p);

end;

var n,x:integer;

begin

write('введите n:');

readln(n);

fact1(n);

readln;

end.

Функции

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

function имя [(список параметров)] : тип;

разделы описаний (label, const, type, var)

begin

операторы

имя := выражение;

end;

В основной программе вызов процедуры осуществляется следующим образом:

var переменная : тип;

begin

операторы

переменная:=Имя процедуры [(список параметров)];

end.

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

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

Для примера вычислим значение факториала n! с использованием функции:

function fact2(a:integer):integer;

var i,p:integer;

begin

p:=1;

for i:=1 to a do

p:=p*i;

fact2:=p;

end;

var n,x:integer;

begin

write('введите n:');

readln(n);

x:=fact2(n);

writeln(n,'!=',x);

readln;

end.

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

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

тип процедура и тип функция:

type

тип процедура = procedure (список параметров);

тип функция = function (список параметров ): тип;

Также, в программе могут быть объявлены переменные процедурного типа:

var

переменная 1 : тип процедура;

переменная 2 : тип функция;

Например:

type

Func=function ( x , y : integer) : integer;

Proc=procedure ( x , y : real ; var c , z : real );

var

f1 : Func;

p1: Proc ;

a : array [1 .. 10 ] of Proc;

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

type ypr=procedure(a:integer);

procedure fact3(a:integer);

var i,p:integer;

begin

p:=1;

for i:=1 to a do

p:=p*i;

writeln('n!= ',p);

end;

var proc:ypr;

n:integer;

begin

writeln('n!=');

readln(n);

proc:=@fact3; // данное выражение однозначно

// трактуется компилятором как адрес переменной,

// а не процедуры, на которую она ссылается!

proc(n);

readln;

end.

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

type fact=function(a:integer):integer;

procedure Printfact(f:fact);

var n,s:integer;

begin

writeln('N');

readln(n);

s:=f(n);

writeln(s);

end;

function fact3(a:integer):integer;

var i,p:integer;

begin

p:=1;

for i:=1 to a do

p:=p*i;

fact3:=p;

end;

begin

Printfact(@fact3);

readln;

end.

Данным способ удобно использовать в первую очередь для контроля типов (исключения ошибок распределения памяти уже на этапе компиляции).

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

Рекурсия

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

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

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

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

Для примера вычислим значение факториала n! с использованием рекурсивного алгоритма.

function fact4(n:integer):longint;

begin

if n<=1 then fact4:=1

else fact4:=n*fact4(n-1);

end;

var i:integer;

begin

write('n=');

readln(i);

writeln(i,' != ',fact4(i));

readln;

end.

Модули

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

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

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

Модули можно разделить на стандартные, которые входят в состав системы программирования, и пользовательские, то есть создаваемые программистом. Чтобы подключить модуль к программе, его требуется предварительно скомпилировать. Результатом компиляции подключаемого модуля в Free Pascal являются два файла: *.ppu – файл, содержащий интерфейсную часть модуля, и файл *.o - объектный файл, содержащий часть реализаций. Файл в расширением *.o необходим для компоновки приложения.

Описание модулей

Исходный текст каждого модуля хранится в отдельном файле с расширением .pas. Общая структура модуля:

unit имя; // заголовок модуля

interface // интерфейсная секция модуля

// описание глобальных элементов модуля (видимых

// извне).

implementation // секция реализации модуля

// описание локальных (внутренних) элементов модуля

begin // тело модуля (может отсутствовать)

initialization // секция инициализации (может

// отсутствовать). Нельзя использовать совместно с

// телом модуля.

finalization // секция финализации (может

// отсутствовать). Нельзя использовать совместно с

// телом модуля.

end.

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

Интерфейсная секция – область подключаемого модуля, начинающаяся с ключевого слова interface и заканчивающаяся ключевым словом implementation, которая может содержать:

  • список подключаемых модулей;

  • константы;

  • пользовательские типы данных;

  • переменные;

  • прототипы процедур и функций,доступные из места подключения данного модуля.

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

Если в данном разделе объявляются прототипы процедур или функций, то их реализации обязательно должны присутствовать в разделе implementation.

Секция реализаций – область подключаемого модуля, начинающаяся с ключевого слова implementation и заканчивающаяся телом модуля (если таковое имеется) или ключевым словом end. В данной секции располагаются реализации процедур и функций, объявленных в интерфейсной секции, которая может содержать:

  • список подключаемых модулей;

  • константы;

  • пользовательские типы данных;

  • переменные;

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

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

Тело модуля может отсутствовать. В таком случае ключевое слово begin не пишется, а end. сигнализирует о конце модуля.

Основное назначение: инициализация переменных модуля, выделение ресурсов, необходимых для его работы и т.д.

В языке Free Pascal также могут присутствовать секции инициализации и финализации.

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

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

Программный код, размещенный в секциях инициализации и финализации, исполняется один раз. Код секции инициализации выполняется до начала исполнения кода главной программы, код секций финализации – после.

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

Задача.

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

Напишем текст модуля, в котором определим процедуры сложения, вычитания, умножения и деления.

unit math2;

interface

procedure sum2(a,b:real);

procedure razn2(a,b:real);

procedure pr2(a,b:real);

procedure del2(a,b:real);

implementation

procedure sum2(a,b:real);

begin

writeln(a+b:0:4);

end;

procedure razn2(a,b:real);

var r:real;

begin

r:=a-b;

writeln(r:0:4);

end;

procedure pr2(a,b:real);

var r:real;

begin

r:=a*b;

writeln(r:0:4);

end;

procedure del2(a,b:real);

var r:real;

begin

r:=a/b;

writeln(r:0:4);

end;

end.

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

uses math2;

var x,y:real;

begin

writeln('Введите x и y');

readln(x,y);

sum2(x,y);

razn2(x,y);

pr2(x,y);

del2(x,y);

readln;

end.

Задания для самостоятельной работы.

    1. Найти сумму чисел от одного до n. Для решения использовать процедуру и функцию.

    2. Написать функции для вычисления площадей геометрических фигур:

2.1. прямоугольник (по двум сторонам);

2.2. треугольник (по трем сторонам);

2.3. круг (по радиусу).

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

  1. Написать программу, которая вычисляет значение x в степени n. Решить нужно двумя способами:

4.1. используя функцию;

4.2. используя рекурсивный алгоритм.

  1. Создать модуль шифровки/дешифровки данных в файле.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]