Основным механизмом для организации динамических данных является выделение в специальной области памяти, называемой «кучей», непрерывного участка (блока) подходящего размера и сохранения адреса начала этого участка в специальной переменной. Такие переменные называют ссылочными переменными или просто ссылками (reference). Часто используется синоним этого термина — «указатель» (pointer), но в Турбо Паскале это название имеет особый смысл.

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

TYPE

ИмяСсылочногоТипа = ^ИмяБазовогоТипа;

где ИмяБазовогоТипа — любой идентификатор типа. В результате

- 195 -

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

TYPE { БАЗОВЫЕ ТИПЫ }

DimType = Array [1..10000] of Real; { массив }

RecType = RECORD { запись }

...

END;

ObjType = OBJECT { объект }

...

| END;

{ ССЫЛОЧНЫЕ ТИПЫ }

IntPtr = ^Integer; { ссылка на целое значение }

DimPtr = ^DimType; { ссылка на массив данных }

RecPtr = ^RecType; { ссылка на запись }

ObjPtr = ^ObjТуре; { ссылка на объект }

XXXPtr = Pointer; { ссылка вообще — указатель }

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

Все ссылочные переменные имеют одинаковый размер, равный 4 байтам, и содержат адрес начала участка оперативной памяти, в котором размещена динамическая структура данных. Отношение между ссылочной переменной и объектом, на который она указывает, наглядно представлено на рис. 11.1. Здесь J — ссылочная переменная, указывающая на значение целого типа (VAR J : ^Integer). Сравните с простой переменной I типа Integer на том же рисунке.

Рис. 11.1

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

J := nil;

Это предопределенная константа типа Pointer, соответствующая адресу 0000:0000.

- 196 -

<p>11.2. Операция разыменования</p>

Основной операцией при работе со ссылочными переменными является операция разыменования. Суть ее состоит в переходе от ссылочной переменной к значению, на которое она указывает. Эта операция обозначается указанием символа «^» следом за ссылочной переменной. Результатом операции является значение объекта, на который указывала ссылочная переменная, или, что то же самое, динамическая переменная. Так, пусть мы имеем две ссылочные переменные I и J, указывающие на объекты целого типа, значения которых равны 2 (I^) и 4 (J^) соответственно. Для того чтобы скопировать содержимое переменной I^ в переменную J^, необходимо выполнить оператор

J^ := I^;

Следует отметить, что нужно писать именно I^ и J^, поскольку оператор вида

J := I;

приведет к копированию адреса значения, на которое указывает I, в ссылочную переменную J. В этом случае мы получим две ссылки на одно и то же значение. Значение, на которое раньше указывала переменная J, будет потеряно. На рис. 11.2 показан результат выполнения этих двух операторов (а — ситуация до (слева) и после выполнения оператора J^:=I^; б — ситуация до (слева) и после выполнения оператора J:=I). После выполнения оператора J:=I ссылка на значение 4 теряется (рис. 11.2, б, справа), и к нему больше нет доступа.

Рис. 11.2

- 197 -

Само значение теперь будет просто пассивно занимать память, т.е. превратится в «мусор».

Ссылочные переменные и указатели совместимы между собой по типу, т.е. нет ошибки в присваивании

DimPtr := RecPtr;

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

DimPtr^ := RecPtr^;

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

Ссылки могут сравниваться между собой. Под этим понимается сравнение соответствующих сегментов и смещений адресов, хранимых в них. Имеют смысл лишь проверки на равенство и на неравенство ссылок или указателей:

if DimPtr = XXXPtr then ... ;

if DimPtr <> XXXPtr then ... ;

Сравнения ссылок не всегда работают корректно. Если две ссылки указывают на один и тот же адрес в памяти, но этот адрес записан в них различными значениями (что вполне возможно), то они считаются различными. Процедуры New и GetMem всегда возвращают ссылки, приведенные к такому виду, что смещения адреса имеют значения от 0 до 15 ($F), и они будут сравниваться корректно. А специальные функции типа Addr, Ptr этого не делают, и сравнивать их результаты с чем-либо надо с большой осторожностью.

Разыменованные ссылки на структуры индексируются (массивы) или разделяются на поля (записи, объекты) обычным образом. Для определенных выше ссылок это выглядит следующим образом:

DimPtr^ [i] — доступ к элементу i динамического массива,

RecPtr^.Поле — доступ к полю динамической записи,

ObjPtr^.Метод — доступ к методу динамического объекта.

Перейти на страницу:

Поиск

Похожие книги