Читайте также: |
|
Динамические переменные
Переменная ссылочного типа (указатель) содержит в качестве своего значения адрес (ссылку) начала какой-то ячейки оперативной памяти. В зависимости от способа описания различают два вида указателей – типизированные и нетипизированные:
Var
P: ^ T; {типизированный указатель}
Q: Pointer; {нетипизированный указатель}
здесь T – имя любого типа, а Pointer – стандартный тип. При этом для типизированных указателей сделано важное исключение: тип T может быть сконструирован после ссылки на него.
Можно применять специальную константу nil типа Pointer, которая не указывает никуда. На самом деле, она указывает на нулевой адрес, который обычно не используется.
Указатели разрешено присваивать друг другу, при этом типизированные указатели должны ссылаться на один и тот же тип. Зато нетипизированные указатели совместимы с любыми – им можно присваивать значения любых типизированных указателей и их можно присваивать любым типизированным указателям.
Для доступа к указываемому объекту используют разыменование типизированного указателя, которое обозначается символом "^". Разыменование аналогично доступу к элементу массива или к полю записи, а его результат является переменной, из которой можно читать значение и в которую можно записывать значение (к примеру, присваиванием). Например, для указателя
PA: ^Integer;
результатом разыменования будет переменная с именем PA^ типа Integer. Конечно, сама переменная-указатель PA к этому моменту должна быть определена, то есть в ней должен находиться какой-то адрес, иначе результат разыменования будет не определён.
Операции, связанные со ссылочным типом:
@ – взятие адреса переменной любого типа (например @A), тип результата – Pointer.
Операции = (равно) и <> (не равно) применимы к однотипным указателям либо к нетипизированному и любому типизированному указателю.
Динамические переменные – это переменные, память для которых может отводиться и освобождаться произвольно, в ходе выполнения программы, в специальной области, называемой кучей. Для доступа к ним используются указатели.
Захват и освобождение памяти производится обращениями к стандартным процедурам New(P) и Dispose(P) или процедурам GetMem(Q, Size) и FreeMem(Q, Size) соответственно. Здесь P – всегда типизированный указатель, Q может быть любым указателем, но обычно используется нетипизированный указатель. Size – это целочисленное выражение, указывающее размер захватываемой или освобождаемой памяти в байтах. Хороший стиль программирования предполагает освобождение такого же объёма динамической памяти, сколько было захвачено ранее, – когда в этой памяти отпадает необходимость. Это позволит использовать её для других переменных.
При выполнении процедуры New:
1) захватывается область динамической памяти, размер которой равен числу байтов, занимаемых переменной P^;
2) переменная P, после успешного захвата, будет иметь в качестве своего значения адрес начала этой области, имя же динамической переменной станет P^.
При выполнении процедуры Dispose:
1) освобождается область динамической памяти, на которую указывает P и размер которой равен числу байтов, занимаемых переменной P^;
2) значение переменной P после этого будет не определено, повторное освобождение этой же области памяти запрещено и считается ошибкой.
Если "потерять" ссылку на динамическую переменную (например присвоить указателю новое значение), то эта область также будет "потеряна" и останется недоступной до конца работы программы. Одна из ошибок при работе с динамическими переменными – это появление "висячих" ссылок:
Var
PA, PB: ^Real;
Begin
New(PA); New(PB);
PA^ := 4; PB^ := 8;
PA := PB; {1}
Dispose(PB); {2}
Dispose(PA); {3}
В этом фрагменте до строки {1} ошибок нет. В строке {1} безвозвратно теряется связь с динамической переменной, адрес которой находился в PA. Другая динамическая переменная, кроме имени PB^, приобретает ещё одно – PA^. В строке {2} эта переменная удаляется из памяти, но как раз в PA и остаётся "висячая" ссылка. Попытка освободить уже освобождённую динамическую память в строке {3} является ошибочной.
Для определения размера свободного пространства в куче используются две стандартные функции – MaxAvail и MemAvail. Для определения размера в байтах внутримашинного представления произвольной переменной можно применять универсальную функцию SizeOf(X), где X – имя переменной или даже имя типа.
Дата добавления: 2015-07-15; просмотров: 120 | Нарушение авторских прав
<== предыдущая страница | | | следующая страница ==> |
Interface | | | Лекция 14. Алгоритмы поиска и выборки. |