Физический адрес любой переменной можно узнать при помощи стандартной функции:
addr(<имя_переменной>): <указатель>
или унарной операции
@<имя_переменной>.
Пример:
var
P: Pointer;
intP: ^integer;
x: integer;
…
P := addr(x);
P := @x;
intP := addr(x);
intP := @x;
Указатель – это лишь адрес ячейки памяти. Для обращения к содержимому такой ячейки используют операцию, называемую разыменованием. Записывается такая операция следующим образом:
<имя_указателя>^
Отметим, что операция разыменования применима лишь к типизированным указателям.
Пример:
var
intP: ^integer;
x: integer;
…
intP := @x;
intP^ := 10;
writeln(intP^);
В случае указателей при присваивании получают лишь новый адрес памяти. Содержимое самих ячеек памяти остается неизменным.
Пример:
var
intP1: ^integer;
intP2: ^integer;
…
x := 3;
intP1 := @x;
y := 4;
intP2 := @y;
intP1 := intP2; {оба указателя ссылаются на значение 4}
intP2^ := 7; {оба указателя ссылаются на значение 7}
В операции присваивания могут фигурировать только указатели, адресующие переменные одинаковых типов данных. Обойти эти ограничения позволяет универсальность нетипизированного указателя Pointer, совместимого с указателями любых типов:
Пример:
var
intP1: ^integer;
intP2: ^integer;
realP: ^real;
P: Pointer;
…
intP1 := intP2;
{нельзя realP := intP1}
P := intP1;
realP := P;
У указателей также существует свой "ноль", который означает, что указатель не указывает никуда:
p:= nil;
Для указателей определены две операции сравнения: равно (=) и не равно (<>).
Две переменные, описанные как указатели на один и тот же тип данных, считаются совпадающими, если они указывают на одну и ту же область памяти.
Для разнотипных указателей сравнения невозможны. Однако сравнивать типизированный и нетипизированный указатели можно.
Указатели – это лишь адрес ячейки памяти, а о состоянии самой ячейки должен позаботиться программист.
Вся динамическая память может располагаться как сплошной массив, состоящий из байтов и называемый кучей. Куча размещается в памяти компьютера следом за областью памяти, которую занимает тело программы.
Перед помещением данных в кучу программист должен подготовить участок памяти, куда данные собственно будут помещены. После завершения использования данных использованное место необходимо за собой очистить.
Процедура New(P) резервирует в памяти участок для значения того типа, на который ссылается указатель P, и устанавливает в указатель адрес зарезервированного участка.
Пример:
var
P1: ^Integer;
...
New(P1);
P1^:=5;
Процедура Dispose(P) освобождает участок памяти, на которую указывает типизированный указатель P.
Пример:
Dispose(P1);
P1:=nil;
Процедуры New и Dispose применимы только для типизированных указателей. При работе с нетипизированными указателями можно воспользоваться следующими процедурами.
Процедура GetMem(P, Size) выделяет из кучи блок памяти размером Size (максимум 64 Кбайта) и устанавливает в указатель P ссылку на неё.
Процедура FreeMem(P, Size) уничтожает в куче блок памяти размером Size по адресу P.