Тип указатель определяет адрес памяти для переменной базового типа.

Тип_указатель::= ("^" базовый_тип) | "Pointer"

Базовый_тип::= ИД типа.

Указатель может быть типированным, то есть указывать на переменную некоторого типа, и может быть нетипированным (pointer), то есть указывать на переменную произвольного типа. Если указатель имеет нулевое значение, его значение равно nil. В независимости от типа указателя, его размер в памяти компьютера постоянен и равен 4 байтам. Для обращения к переменной, адрес которой хранится в указателе, требуется после имени указателя ставить знак "^".

В ТП существует специальная операция @ (см. параграф 1.4.3.6), с помощью которой можно получить указатель на любую переменную, процедуру или функцию

Пример:

var a:integer;

pa1,pa2:^integer;

begin

pa1:=@a; {получаем адрес переменной a и присваиваем его
указателю
Pa1}

pa2:=pa1; {присвоили указателю Pa2 значение указателя Pa1. Теперь Pa1 и Pa2 указывают на одну и ту же область памяти}

pa1^:=7;

pa2^:=6;

writeln(a,' ',pa1^,' ',pa2^);

end.

В результате работы программы на экране появятся три числа 6.

Оперативная память компьютера, выделенная операционной системой для программы, делится на несколько частей:

1) Область кода, где хранится исполняемая часть программы (максимум 64К на модуль).

2) Область стека, где хранятся вызовы и локальные переменные процедур и функций (максимум 64К).

3) Область статических данных, где хранятся все глобальные переменные и размер которой равен 64К.

4) Область динамических данных или куча (вся оставшаяся память, запрошенная программой у операционной системы и объем которой в реальном режиме может в 8-10 раз превышать объем области статических данных, а в защищенном - достигать 16 мегабайт). ТП позволяет произвольно выделять память из кучи блоками любого размера до 64К, а после использования - возвращать обратно.

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

Процедуры для работы с динамической памятью

Выделение памяти для динамических переменных

procedure New(var P: Pointer);

Процедура New выделяет память для динамической переменной P. Объем выделяемой памяти рассчитывается на основе типа переменной. Таким образом, требуется, чтобы переменная P была типированным указателем.

procedure GetMem(var P: Pointer; Size: Word);

Процедура GetMem выделяет память объемом в Size байт для динамической переменной P, которая может быть указателем любого типа.

Процедуры New и GetMem могут стать причиной аварийной остановки программы, если размер затребованной памяти превышает размер максимального свободного блока.

Освобождение памяти, выделенной ранее для динамических
переменных

procedure Dispose(var P: Pointer);

Процедура Dispose освобождает динамическую переменную P. Используется в паре с процедурой New.

procedure FreeMem (var P: Pointer; Size: Word);

Процедура FreeMem освобождает динамическую переменную P объемом в Size байт. Используется в паре с процедурой GetMem.

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

Альтернативный метод освобождения динамической памяти

procedure Mark (var p: pointer);

Процедура Mark сохраняет состояние кучи в указателе P. Используется совместно с процедурами New и GetMem.

procedure Release(var p: pointer);

Процедура Release освобождает все динамические переменные, память для которых была выделена после использования Mark с указателем P.

Процедуры Mark и Release не должны использоваться совместно с Dispose и FreeMem. Мы вообще не советуем пользоваться этими процедурами, как устаревшими и включенными в язык только для совместимости с предыдущими версиями.

Состояние динамической памяти

function MemAvail: Longint;

Процедура Memavail возвращает объем свободной памяти в куче.

function MaxAvail: Longint;

Процедура MaxAvail возвращает объем максимального свободного блока памяти в куче.

В идеальном случае значения, возвращаемые процедурами MemAvail и MaxAvail, равны. Однако при частом выделении и освобождении блоков возможна дефрагментация кучи. В самом худшем случае может оказаться. что нет возможности выделить память для указателя, несмотря на то, что общий объем кучи превышает затребованный в несколько десятков раз.

Адресация памяти

ТП позволяет напрямую взаимодействовать с адресами памяти компьютера. Каждый байт памяти IBM PC адресуется в реальном режиме с помощью двух значений - сегмента и смещения. Следующие функции преобразовывают адреса переменных в сегмент и смещение, а сегмент и смещение - в указатели. Получение сегмента и смещения любого объекта ТП может оказаться полезным при прямом обращении к памяти с помощью предопределенных массивов Mem, MemW и MemL (см. параграф 1.7.2.1)

function Seg(X): Word;

Функция Seg возвращает сегментную часть адреса объекта X

function Ofs(X): Word;

Функция Ofs возвращает смещение объекта X

function Ptr(Seg, Ofs: Word): Pointer;

Функция Ptr возвращает указатель, сформированный из сегмента и смещения

function Addr(X): pointer;

Функция Addr возвращает указатель на объект X

Этапы работы с динамической переменной:

1) Определение ДП.

2) Выделение памяти для ДП или присваивание ей адреса некоторого объекта (переменной, процедуры или функции, произвольной области памяти и т.д.).

3) Работа с динамической переменной.

4) Освобождение памяти, выделенной для динамической переменной.

Например:

type Arr=Array[1..20000] of integer; {определяем тип массива размером в 40000 байт }

var a:array[1..10000]of ^arr;{определяем массив указателей на массив}

i,n:integer;

begin

n:=0;

writeln('Исходный объем динамической памяти: ', MemAvail,

' байт');

while MaxAvail>=sizeof(arr) do begin {пока объем кучи достаточен}

incno;{переходим к следующему элементу массива}

New(a[n]);{выделяем память}

end;

writeln('Удалось выделить память только для ', n,

' элементов массива');

writeln('Осталось памяти ', MemAvail, ' байт');

for i:=1 to n do dispose(a[i]);{освобождаем массив динамических переменных}

readln;

end.

<- Предыдущая страница | Следующая страница ->
Последнее изменение: Вторник 1 Март 2011, 17:24