
- •Лабораторная работа № 1 Процедурные типы данных
- •Теоретическая часть
- •Процедурные типы
- •Процедурные переменные
- •Параметры процедурного типа
- •Практическая часть
- •Приближенное решение алгебраических и трансцендентных уравнений
- •Cпособ половинного деления
- •Cпособ пропорциональных частей (метод хорд)
- •Способ Ньютона (метод касательных)
- •Способ итераций
- •Приближенное интегрирование функций
- •Формула прямоугольников
- •Формула трапеций
- •Формула Симпсона
- •Задания Написать программу, реализующую итерационные вычислительные процессы, с использованием процедурных типов данных.
Лабораторная работа № 1 Процедурные типы данных
Теоретическая часть
Процедурные типы
В Borland Pascal допускается интерпретация процедур и функций, как объектов, которые можно присваивать переменным и передавать в качестве параметров. Такие действия можно выполнять с помощью процедурных типов.
Синтаксис записи процедурного типа в точности совпадает с записью заголовка процедуры или функции, только опускается идентификатор после ключевого слова procedure или function.
Примеры.
type
Proc = procedure;
SwapProc = procedure(var X, Y: Integer);
StrProc = procedure(S: String);
MathFunc = function(X: Real): Real;
DeviceFunc = function(var F: text): Integer;
MaxFunc = function(A, B: Real; F: MathFunc): Real;
Имена параметров в описании процедурного типа играют чисто декоративную роль - на смысл описания они не влияют.
Borland Pascal не позволяет описывать функции, которые возвращают значения процедурного типа. Результат функции должен быть строкового, вещественного, целого, символьного, булевского типа, указателем или иметь перечислимый тип, определенный пользователем.
Процедурные переменные
После определения процедурного типа появляется возможность описывать переменные этого типа. Такие переменные называют процедурными переменными. Например, с учетом описаний типа из предыдущего примера, можно объявить следующие переменные:
var
P: SwapProc;
F: MathFunc;
Как и целая переменная, которой можно присвоить значение целого типа, процедурной переменной можно присвоить значение процедурного типа. Таким значением может быть, конечно, другая процедурная переменная, но оно может также представлять собой идентификатор процедуры или функции. В таком контексте описания процедуры или функции можно рассматривать, как описание особого рода константы, значением которой является процедура или функция. Например, пусть имеется следующие описания процедуры и функции:
procedure Swap(var A,B: integer);
var
Temp: integer;
begin
Temp := A;
A := B;
B := Temp;
end.
function Tan(Angle: real): real;
begin
Tan := Sin(Angle) / Cos(Angle);
end.
Описанным ранее переменным P и F теперь можно присвоить значения:
P := Swap;
F := Tan;
После такого присваивания обращение P(i,j) эквивалентно Swap(i,j) и F(X) эквивалентно Tan(X).
Как и при любом другом присваивании, значения переменной в левой и в правой части должны быть совместимы по присваиванию. Процедурные типы, чтобы они были совместимы по присваиванию, должны иметь одно и то же число параметров, а параметры на соответствующих позициях должны быть одинакового типа.
Кроме того, для обеспечения совместимости по присваиванию процедура и функция, если ее нужно присвоить процедурной переменной, должна удовлетворять следующим требованиям:
Это не должна быть стандартная процедура или функция.
Такая процедура или функция не может быть вложенной.
Такая процедура не должна быть процедурой типа inline.
Она не должна быть процедурой прерывания (interrupt).
Использование процедурных типов не ограничивается просто процедурными переменными. Как и любой другой тип, процедурный тип может участвовать в описании структурного типа.
Примеры.
type
GotoProc = procedure(X,Y: integer);
ProcList = array[1..10] of GotoProc;
WindowPtr = ^WindowRec;
Window = record
Next: WindowPtr;
Header: string[31];
Top,Left,Bottom,Right: integer;
SetCursor: GotoProc;
end;
var
P: ProcList;
W: WindowPtr;
С учетом этих описаний допустимы следующие вызовы процедур:
P[3](1,1);
W.SetCursor(10,10);
Когда процедурной переменной присваивается значение процедуры, то на физическом уровне происходит следующее: адрес процедуры сохраняется в переменной. Фактически, процедурная переменная весьма напоминает переменную-указатель, только вместо ссылки на данные она указывает на процедуру или функцию. Как и указатель, процедурная переменная занимает 4 байта (два слова), в которых содержится адрес памяти. В первом слове хранится смещение, во втором - сегмент.
При применении к процедурной переменной, идентификатору процедуры или функции операции получения адреса @, эта операция предотвращает вызов компилятором процедуры и в то же время преобразует аргумент в указатель.
Примеры.
if @P <> nil then P(I, J);
Здесь операции @ используется для указания того, что P проверяется, а не вызывается.
if @F = @Tan then WriteLn('Equal');
Здесь выполняется сравнение процедурного значения в F с процедурным значением в Tan.
Чтобы получить адрес в памяти процедурной переменной, а не адрес, в ней записанный, необходимо использовать двойную операцию @ (@@). Например, @P означает преобразование P в нетипизированный указатель-переменную, а @@P означает возвращение физического адреса переменной P.