Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекция 23.doc
Скачиваний:
7
Добавлен:
11.07.2019
Размер:
55.3 Кб
Скачать

3. Тип данных - Указатель.

Для работы с динамической памятью в Турбо Паскале используется специальный тип данных - Указатель. Переменная типа Указатель имеет значением адрес оперативной памяти. Адрес приписан каждому байту оперативной памяти (от 0 до max) и состоит из двух частей: сегмента и смещения. Сегмент - непрерывный участок оперативной памяти длиной 64кбайт, начинающийся с физического адреса, кратного 16. Смещение указывает относительный адрес внутри сегмента. Как сегмент, так и смещение являются данными типа word. Таким образом, по своей внутренней структуре указатель состоит из двух слов типа word. С помощью указателя можно размещать в хип-памяти любой тип данных Турбо Паскаля (кроме файла). В случае, когда размещаемый тип данных имеет длину более 1 байта, указатель указывает на начало соответствующей структуры (на первый байт данных).

В Турбо-Паскале имеется два вида указателей:

типизированный указатель, указывающий на заданный тип данных;

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

Форма описания указателя зависит от вида указателя. Типизированный указатель описывается в следующей синтаксической форме:

type <имя типа-указателя> = ^ <имя базового типа >;

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

Например: type pint = ^integer; - тип-указатель на данные типа integer.

Синтаксическая форма описания нетипизированного указателя имеет вид:

type <имя типа-указателя> =pointer;

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

Например: var pp:pint; { переменная типа pint (типизированный указатель)}

np:pointer; {переменная нетипизированного указателя}

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

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

Например: type refer = ^ inf; inf = record name,adr,tel:string;next:refer end;

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

4. Принципы работы с указателями.

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

Создание указателя на структуру, по сути, является особым способом именования этой структуры, отличным от имён, принятых для статических переменных. Необходимо помнить, что обращаясь к указателю, мы обращаемся не непосредственно к структуре данных (не к её значению !), а лишь к адресу начала размещения этой структуры.

В тех случаях, когда необходимо обратиться к значению представленной структуры данных, следует выполнить операцию разыменования, которая в Турбо Паскале имеет специальное обозначение: если p - указатель, то p^ - значение, на которое указывает p. (Обратите внимание, что символ ^ при разыменовании записывается после переменной-указателя, а не до него, как при описании типизированного указателя).

Над указателями (т.е. адресами) допустимы операторы присваивания вида:

p1:=p2; - где p1,p2 - только указатели одного и того же типа.

p:= nil; - где р - переменная типа указатель, а nil - нулевой указатель (не являющийся ни одним из адресов хип-памяти), т.е. "нулевая" константа типа указатель.

Для работы с указателями в Турбо Паскале предусмотрен ряд стандартных процедур и функций. Важнейшими из них являются процедуры выделения (резервирования) хип-памяти под структуры, на которые указывают указатели.

Выделение хип-памяти под структуры, именуемые типизированными указателями, выполняет следующая процедура:

new(<переменная типизированного указателя>);

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

Для нетипизированных указателей память выделяется другой процедурой:

getmem(<нетипизированный указатель>, < размер памяти >);

где: <размер памяти> указывается в байтах.

Действие процедуры getmem аналогично процедуре new, различие лишь в том, что размер структуры задаётся явно вторым параметром этой процедуры (для new он определялся неявно по описанию типа указателя).

Заметим, что работа с нетипизированными указателями сложнее, т.к. всю ответственность за размещение структуры и её "наполнение" значением несёт только сам программист. В то же время этот вид указателей обладает большей гибкостью и способен размещать в одном и том же фрагменте памяти различные типы структур, создавая предпосылки для более эффективного использования памяти. Начинающим программистам не рекомендуется, тем не менее, работать с нетипизированными указателями.

Оператор присваивания, процедуры выделения хип-памяти и разыменование переменной-указателя составляют основной арсенал средств работы с указателями. Кроме того, для указателей (как для адресов) допустимы обычные отношения сравнения: =, <>, <, >, <=, >=. Проиллюстрируем эти средства на примере - программе работы с линейным списком - списком телефонов:

program list_tel;{создание списка телефонов}

uses CRT;

type refer=^info; {тип - Указатель на запись}

info= record name,adr,tel:string;

next:refer

end;

var first,p,pp:refer; {указатели на начало списка и текущие}

s:string;

procedure write_list(start:refer);{вывод всех элементов списка}

begin repeat with start^ do

begin writeln(name);

writeln(adr);

writeln(tel);

end; start:=start^.next

until start=nil;

end{write_list};

BEGIN TextBackground(cyan);TextColor(white);ClrScr;

window(10,5,40,20);TextBackground(green); ClrScr;

new(first);p:=first;pp:=nil;

repeat if pp<>nil then {образование очередного элемента}

begin new(p);pp^.next:=p end;

with p^ do { заполнение элемента списка}

begin write('Ф.И.О.:'); readln(name);

write('Адрес:'); readln(adr);

write('Телефон:');readln(tel);

next:=nil

end; pp:=p;readln(s)

until (s=' ');

writeln('Список телефонов создан');

write_list(first);writeln('Вывод списка завершен');

END{list_tel}.

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

Для возврата освободившегося участка хип-памяти используется процедура dispose (p), где p – типизированный указатель, и процедура freemem(p,k), где к – размер в байтах освобождаемого участка для нетипизированного указателя p.

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

Процедура mark(ptr) - запоминает в ptr текущее значение указателя HeapPtr.

Процедура release(ptr) - освобождение участка хип-памяти от текущего указателя, сохраненного процедурой mark(ptr), до конца хип-памяти.

Функции maxavail и memavail - возвращают размер (в байтах) наибольшего непрерывного участка или общего свободного пространства хип-памяти соответственно.

Функция addr(x) - возвращает указатель, содержащий адрес аргумента x (имя переменной, процедуры, функции). Эту же функцию выполняет операция @x.

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