Для организации динамических структур данных в качестве базовых элементов используются ссылочные указатели, при этом в динамической памяти (кучи) выделяются блоки памяти, необходимого размера, адреса которых хранятся в ссылках или указателях, связанных с этими блоками.
Для выделение памяти под динамические переменные используется функция NEW(<параметры>); (часто используются как процедура). Параметром этой функции являться ссылочная переменная на некоторый базовый или пользовательский тип данных. Данный тип определяет размер выделенного блока, адрес начала этого блока будет записан в ссылочный переменную параметр.
Пример выделение динамической памяти:
Var
I:byte;
P1,p2:^integer;
P3:^REAL;
Begin
{1}
I:=5;
New(p1);
New(p2); {2}
New(p3);
В данном случае после выполнения трех операторов NEW в динамической памяти последовательно выделятся два блока по два байта и один блок под шесть байт (реально выделенный объем будет несколько иным, смотри предопределенные указатели).
Адреса этих выделенных блоков будут находиться в ссылочных переменных Р1, Р2, Р3 соответственно. Последовательное выделение блоков из памяти не всегда означает, что блоки будут располагаться друг за другом, в ряде случаев они располагаются в различных местах памяти на момент выделении блоков. При последовательном выделении блоков, блоки размещаются в сторону увеличение адресов.
|
|
После выделение блоков в динамической памяти в них можно записать какую либо информацию используя оператор разадресации (^).
Пример применения разадрисации: в выделенные блоки помещаем
информацию.
P1^:=10;
P2^:=p1^-4;
I:=p1^;
P3^:=i+p1^+p2^;
Особенностью оператора New является то, что она в большей степени используется с ссылочными переменными, которые указывают необходимый для выделение объем памяти. В этом случае эта функция используется, как однако её можно использовать и при работе с указателями. Для этого устанавливается ссылочный тип данных, который будет использоваться для определения размеров блока.
Пример использования ссылочной переменной.
Type
I_int=^integer;
Var
P:pointer;
.
.
P:=new(i_int);
{$X+} - разрешён обособленный вызов функций т.е как процедур.
При выполнении функции New объем доступной динамической памяти уменьшается, блоки памяти выделенные с помощью этой процедуры считаются администратором кучи занятыми (связанными с некоторыми ссылками) даже если этот блок не заполняется, поэтому повторный запрос на выделение блока с помощью new не может привести к тому, чтобы занятый блок был связан с другой ссылкой или указателем.
Пример:
New(p1);
New(p2);
Р1- считается занятым если даже ничего там не записано.
|
|
1) Процедура освобождения памяти
Dispose (<ссылка>)
Данная процедура используется для работы с типизированными ссылочными переменными, является парной функции New, оказывает противоположенное ей действие, связанное с освобождением блока памяти, тип ссылки указывает блок какого размера необходимо освободить. Адрес освобождаемого блока находиться переменной. После выполнения данной процедуры оббьем доступной памяти увеличивается.
Пример:
Var
P1:^integer;
.
{1}
New(p1);
P1^:=5; {2}
Dispose(p1);{3}
HeapPtr - Предопределенный указатель, который содержит адрес нижней границы свободной области кучи. Считается что после выполнения процедуры Dispose блок памяти связанный с ссылочной переменной-параметром данной процедуры удаляется из памяти, при этом ссылочная переменная считается неопределенной и поэтому если необходимо воспользоваться ею выполняется операция её инициализации каким-либо адресом (new(p1)). Фактически после выполнения процедуры Dispose блок связанный с ссылочной переменной считается свободным. Он в любой момент времени может быть занят администратором кучи при запросе на выделение блока. Объём доступной динамической памяти увеличивается, данные находящиеся в блоке не удаляются, ссылка остается определена тем же адресом (но лучше её считать неопределенной).
Пример: выделение и заполнения динамических блоков.
Var
P1,p2:^integer;
.
.
New(p1);
P1^:=5;
Dispose(p1);
New(p2);
P2^:=10;
Write(p1^);
После выполнения команды Write(p1^); выведет на экран значение 10;
2) выделение блока памяти из кучи
Для этого используется еще одна процедура GetMem (<параметр1>,<параметр2>);
Параметр1 –это ссылка или указатель
Параметр2-значение типа word определяющее размер выделяемого блока.
Адрес выделяемого блока будет храниться в параметре1.
Данная процедура в основном используется для работы с указателями
Пример: выделение памяти с помощью процедуры GetMem.
Var
P:pointer;
.
.
Getmem(p,sizeof(real));
Getmem(p,1024);
Реально выделенный объем будет другим.
Пример работы с блоками памяти.
Var
P:^byte;
.
.
Getmem(p,4);
P1^:=300; больше чем байт!
P^:=3; - это сработает;