Ссылочные типы и указатели.
Ссылочные или указательные типы занимают промежуточное положение между скалярными и составными типами: с одной стороны, значения ссылочных типов являются атомарными (неразделимыми), с другой стороны, эти типы определяются через другие (в том числе и ссылочные) типы.
Любой ссылочный тип определяет множество значений, которые являются указателями на значение некоторого определенного типа.
Type
P = ^integer;
Var
P1, p2 : p;
OneMan : ^Person;
Значение переменной OneMan ссылается (указывает) на некоторое значение типа Person.
Описание ссылочных типов - единственное исключение из общего правила, согласно которому все идентификаторы должны быть описаны перед использованием.
Type
PtrType = ^BaseType;
BaseType = record
X, y :real;
End;
Рисунок 15.1 - Ссылочный тип
Реально значения ссылочных типов содержат адреса расположения в памяти конкретных значений базового типа. Чтобы присвоить переменной ссылочного типа некоторое значение, необходимо воспользоваться унарной операцией взятия указателя, которая строится из знака этой операции - символа '@' и одного операнда - переменной любого типа.
Var
I : integer;
То применение этой операции к переменной i : @i дает в качестве результата значение типа 'указатель на целое':
P1 :=@i;
Правомочен, т. к. в обеих его частях стоят конструкции одного и того же типа. В результате такого присваивания p1 получит в качестве своего нового значения указатель на переменную i (или адрес переменной i).
Операция взятия указателя допустима для любых переменных в том числе для элементов массива, полей записей и т. д.
Над значениями ссылочных типов допускаются две операции сравнения на равенство и неравенство; эти операции проверяют, ссылаются ли два указателя на одно и то же место в памяти.
S := p1 = p2;
If p1<>nil then …
Nil - служебное слово, обозначает, что указатель ссылается на место в адресном пространстве, в котором заведомо не может быть размещена никакая переменная.
P1 := @i;
Эта схема показывает, что для доступа к переменной i имеются две возможности: использовать для доступа идентификатор i, вторая - воспользоваться адресом этой переменной, который содержится в p1. Первый путь очевиден:
I: = i+2;
Для реализации второго, косвенного доступа к переменной через указатель (ссылку) на ней используется конструкция, называемая разыменованием. Общее правило: для того, чтобы по указателю на переменную получить доступ к самой этой переменной, необходимо после указателя поставить знак '^'.
P1^ - переменная, на которую ссылается p1.
P1^ :=P1^+2;
Разыменование считается не корректным, если ссылочная переменная имеет значение nil. В этом случае не существует переменной, на которую ссылается указатель.
P1:=nil
P1^ :=2 - является недопустимым.
До сих пор мы имели дело с переменными, которые размещаются в памяти согласно вполне определенным правилам. Для локальных переменных, описанных подпрограмме, память отводится при вызове подпрограммы: при выходе из нее эта память освобождается, а сами переменные прекращают существование. Глобальным переменным программы, память отводится в начале ее выполнения : эти переменные существуют в течение всего периода работы программы. Распределение памяти во всех этих случаях производится полностью автоматически и подчинено стековой дисциплине.
15.2 Статические переменные.
Pascal допускает возможность образовывать новые переменные в любой момент работы программы без учета ее статической структуры и допускается уничтожение созданных переменных в произвольный момент выполнения.
Переменные, созданием и уничтожением которых может явно управлять программист, называются динамическими переменными.
Динамические переменные, количество которых и место расположения в памяти заранее не известно, невозможно обозначит идентификаторами. Поэтому единственным средством доступа к динамическим переменным является указатель на место их текущего расположения в памяти. На принципе обращения к динамическим переменным посредством указателей (ссылок) на них и основаны все соответствующие средства языка Pascal.
Для распределения памяти под локальные переменные отводится специальный сегмент оперативной памяти (сегмент стека). Образование динамических переменных реализуется в другой области памяти, которая существует отдельно от стекового сегмента и называется кучей (heap) или динамической памятью.