Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Чернов Шафеева.doc
Скачиваний:
47
Добавлен:
21.05.2015
Размер:
1.39 Mб
Скачать

2.12. Указатели и динамическая память

Динамическая память - оперативная память персонального компьюте­ра, предоставляемая программе при ее работе, за вычетом сегмента дан­ных (64 Кб), стека (16 Кбайт) и собственно тела программы. Ее при­менение является фактически единственной возможностью обработки данных большой размерности. По умолчанию размер динамической памяти составля­ет не менее 200..300 Кб (вся доступная память ПК), однако может из­меняться настройкой среды Турбо Паскаля.

Для управления динамической памятью используются указатели. Ука­затель  это переменная, которая в качестве своего значения содержит адрес байта памяти (или номер ячейки оперативной памяти, состоящий из сегмента и смещения).

Указатели делятся на типизированные и нетипизированные. Они описыва­ются они в разделе VAR как

<имя переменной>: <тип_указателя>;

Для объявления типизированного указателя используется символ ^, который помещается перед соответствующим типом, например:

Var

p1,u: ^integer; {типизир.указатель на целое}

p2: ^real; {типизир.указатель на вещ.}

Нетипизированный помечается стандартным типом pointer, например:

Var

p: pointer; {объявляется переменная, значением которой является адрес}

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

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

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

NEW (<типизированный_указатель>;

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

BEGIN

new(p1); {выделяется 2 байта памяти, указатель смещается на 2 байта}

new(p2); {выделяется в памяти 6 байт, указатель смещается на 6 байт (тип READ)}

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

p1^:=20; {в область памяти p1 помещено значение 20}

p2^:=2*Pi; {в область памяти p2 - значение 6.28}

Для адресного типа разрешены операции присваивания между указате­лями одного типа. Например:

new(u); {выделяется 2 байта памяти под u}

u:=p1; {запрещены присваивания u:=p2 , p2:=u}

Для нетипизированных указателей же можно записать: p:=p1; и p2:=p;

Указатели можно сравнивать на равенство и неравенство.

В ТП можно передавать значения только между указателями, связан­ными с одним и тем же типом данных, например:

u^ := sqr(p1^) + u^ - 27 ;

Не допустимо в выражениях смешивать адреса (указатели) и значе­ния (данные).

Для освобождения динамической памяти (возврата динамической па­мяти в кучу) используется процедура

DISPOSE (<типизированный указатель>);

Данная процедура возвращает в кучу освобожденную память, напри­мер:

DISPOSE(u); DISPOSE(p1); DISPOSE(p); {3 оператора вернут 10 байт}.

Повторное применение процедуры DISPOSE к свободному указателю приведет к возникновению ошибки периода исполнения. Поэтому для помет­ки освободившегося указателя обычно используется зарезервированное слово NIL (пустой).

Пример фрагмента программы, в которой для объявления указателя использована типизированная константа с начальным значением, равным NIL:

Const i: ^integer = NIL; {объявление константы-указатель}

...

if i = NIL then {проверка указателя: "свободный?"}

NEW(i); {резервирование памяти}

... { обработка данных}

DISPOSE(i); {освобождение памяти}

i = NIL; {пометка свободным}

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

Для работы с нетипизированными указателями используют процедуры:

GETMEM(<нетип.указатель>, SIZE); для резервирования памяти, FREEMEM(<нетип.указатель>, SIZE); для освобождения памяти.

SIZE  размер в байтах требуемой или освобождаемой части кучи.

За одно обращение к куче процедурой GETMEM можно зарезервировать до 65521 байта динамической памяти.

При работе с динамической памятью необходимо соблюдать правило: освобождаться столько памяти, сколько ее было зарезервировано, и имен­но с того адреса, с которого она была зарезервирована. Например:

Var p: pointer;

Begin

Getmem(p,8);

...

FreeMEM(p,8);

End.