Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Программирование / WORD / Лекции по ЯП (часть 2).doc
Скачиваний:
98
Добавлен:
15.04.2015
Размер:
2.24 Mб
Скачать

Указатели на процедуры и функции

Указатель на подпрограмму определяется как переменная процедурного типа, например:

type

fun = function(x : real) : real: { процедурный тип }

var

pf : fun; { указатель на функции типа fun }

Указателю на подпрограмму можно присвоить NIL, значение другого указателя того же типа или имя конкретной подпрограммы. Присваивание имени выполня­ется без использования операции взятия адреса @, поскольку имя подпрограммы представляет собой адрес точки входа, то есть является константой процедурного (функционального) типа:

type

fun = function(x : real) : real: { функциональный тип }

var

pf : fun: { указатель на функции типа fun }

function f(x : real) : real; far: { конкретная функция }

begin

<тело функции>

end;

begin

pf:=f;

end.

После выполнения этого фрагмента программы в переменной pf будет храниться адрес точки входа в функцию f. Теперь функцию f можно вызвать через пере­менную pf обычным образом, например:

у := pf(x);

Обратите внимание, что функция, адрес которой присваивается переменной, должна компилироваться в режиме дальней адресации. Для этого в заголовке указывается директива far или задается ключ компиляции {$F+}.

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

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

program mas_fun;

type

fun = function(x : real) : real;

function fl(x : real) : real; far;

begin

fl := sin(x);

end;

function f2(x : real) : real; far;

begin

f2 := cos(x);

end;

function f3(x : real) : real; far;

begin

f3 := arctan(x);

end;

const

pf : array[1..3] of fun = (fl, f2, f3);

var

y : real;

i : integer;

begin

for i := 1 to 3 do

writeln(' Результат функции ', i:2, ' : ', pf[i](PI));

end.

  1. Динамические структуры данных

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

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

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

Элемент динамической структуры описывается в виде записи, например:

type

pnode = ^node;

node = record

d : word; { информационная }

s : char; { часть }

p : pnode; { указатель на следующий элемент }

end;

Примечание. Обратите внимание, что тип указателя pnode на запись node определен раньше, чем сама запись. Это не противоречит принципу «использование только после описания», поскольку для описания переменной типа pnode информации вполне достаточно.

Рассмотрим принципы работы с основными динамическими структурами.

Стеки

Стек является простейшей динамической структурой. Добавление элементов в стек и выборка из него выполняются из одного конца, называемого вершиной стека. Другие операции со стеком не определены. При выборке элемент исклю­чается из стека.

Стек реализует принцип обслуживания LIFO (last in — first out, по­следним пришел — первым обслужен). Стеки широко применяются в системном программном обеспечении, ком­пиляторах, в различных рекурсивных алгоритмах.

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

var

top,

p : pnode;

Тип указателей должен соответствовать типу элементов стека. Мы будем стро­ить стек из элементов, тип которых описан в предыдущем разделе.

Занесение первого элемента в стек выполняется в два приема: сначала выделяется место в памяти и адрес его начала заносится в указатель на вершину стека (опера­тор 1), а затем заполняются все поля элемента стека (операторы 2):

new(top); { 1 }

top^.d := 100; { 2 }

top^.s : = 'а';

top^.p := nil;

Значение nil в поле указателя на следующий элемент говорит о том, что этот элемент в стеке является последним (см. рис.).

При добавлении элемента в стек кроме создания элемента и заполнения его ин­формационной части (операторы 1 и 2) требуется связать его с предыдущим элементом (оператор 3) и обновить указатель на вершину стека (оператор 4), по­тому что теперь в вершине стека находится новый элемент:

new(p); { 1 }

p^.d := 10; p^.s := 'b'; { 2 }

р^.р := top; { 3 }

top := р; { 4 }

Стек, состоящий из трех элементов, изображен на следующем рисунке.

Выборка из стека состоит в получении информационной части элемента (опера­тор 1), переносе указателя на вершину стека на следующий элемент (оператор 2) и освобождении памяти из-под элемента (оператор 3):

with top^ do writeln (d. s); { 1 }

p := top; top := top^.p: { 2 }

dispose(p); { 3 }

Рассмотренные операции удобно оформить в виде отдельных функций. Ниже приведена программа, которая формирует стек из пяти целых чисел и их текстового представления и выводит его на экран. Функция занесения в стек по тради­ции называется push, а функция выборки — pop.

program stack;

const

n = 5;

type

pnode = ^node;

node = record { элемент стека }

d : word;

s : string;

p : pnode;

end:

var

top : pnode; { указатель на вершину стека }

i : word;

s : string;

const text : array [1.. n] of string =

('one', 'two', ' three', 'four', 'five');

{---------------------------------- занесение в стек ------------------------------------}

function push(top var p : pnode; const s : string): pnode;

var p : pnode;

begin

new(p);

p^.d := d; p^.s :=s; p^.p := top;

push := p;

end;

{---------------------------------- выборка из стека ------------------------------------}

function pop(top : pnode; var d : word; var s : string): pnode;

var p : pnode;

begin

d := top^.d; s := top^.s;

pop := top^.p;

dispose(top);

end;

{---------------------------------- главная программа ------------------------------------}

begin

top := nil;

{ занесение в стек }

for i := 1 to n do top := push(top, i, text[i]);

{ выборка из стека }

while top <> nil do

begin

top := pop(top, i, s);

writeln(i:2, s);

end;

end.

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

Соседние файлы в папке WORD