- •Часть II Оглавление
- •Строки. Процедуры и функции для работы со строками.
- •Множества. Операции над множествами.
- •Подпрограммы для работы со всеми типами файлов
- •Текстовые файлы
- •Бестиповые файлы
- •Типизированные файлы
- •Прямой доступ
- •Оператор with.
- •Вариантная запись.
- •Динамические структуры данных
- •Процедуры и функции. Рекурсия. Модули.
- •Основы объектно-ориентированного программирования
- •Графика
Процедуры и функции. Рекурсия. Модули.
В программировании часто возникает такая ситуация, когда одну и ту же группу операторов, реализующих определенную цель, требуется повторить без изменений в нескольких местах программы. Для избавления от столь нерациональной траты времени была предложена концепция подпрограммы.
Подпрограмма - это фрагмент кода, к которому можно обратиться по имени. Она описывается один раз, а вызываться может столько раз, сколько необходимо. Одна и та же подпрограмма может обрабатывать различные данные, переданные ей в качестве аргументов.
В языке 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.
Задания для самостоятельной работы.
Найти сумму чисел от одного до n. Для решения использовать процедуру и функцию.
Написать функции для вычисления площадей геометрических фигур:
2.1. прямоугольник (по двум сторонам);
2.2. треугольник (по трем сторонам);
2.3. круг (по радиусу).
Найти минимальное среди 4-х чисел, используя функцию нахождения минимального среди двух чисел.
Написать программу, которая вычисляет значение x в степени n. Решить нужно двумя способами:
4.1. используя функцию;
4.2. используя рекурсивный алгоритм.
Создать модуль шифровки/дешифровки данных в файле.
