Работа с динамическими переменными
Доступ, то есть обращение к динамическим переменным, возможен по двум схемам. Рассмотрим ситуацию, возникшую после присваивания:
p1:=@i;
Первый вариант очевиден:
i:=i+2;
Но, хотя на i ссылается указатель, переменная описана как статическая.
Для реализации косвенного доступа к переменной через указатель используется разыменование. То есть, чтобы по указателю получить доступ к переменной, необходимо после указателя поставить знак «^». Так, запись р1^ означает: «переменная, на которую ссылается р1». Поэтому операторы
i:=i+2 и p1^:=p1^+2
полностью эквивалентны. Разыменование имеет тип, совпадающий с базовым типом, в частности p1^ является переменной целого типа (по описанию выше).
Разыменование допустимо для любых ссылочных типов, например, возможны следующие конструкции:
j:=pp1^^;
f:=h.l^.g^.p;
При разыменовании может возникнуть некорректная ситуация, хотя и не приводящая к аварийному завершению, но дающая обычно неверное значение результата (это трудно обнаруживаемая ошибка). Это разыменование указателя со значением nil. За этим необходимо внимательно следить при составлении и отладке программы.
Основные действия над динамическими переменными — это их создание и уничтожение. Первое реализуется стандартной процедурой
New (<указатель>)
При выполнении этой процедуры происходят следующие действия:
1. В динамической области памяти отводится место для переменной по размеру базового типа указателя.
2. Указателю присваивается адрес этой переменной.
Пример.
Var I,J: ^integer; { определяем два указателя на целую переменную }
NEW (J); { выделяем память для целой переменной и присваиваем ее адрес указателю }
I:=J; { I и J указывают на одну и ту же переменную (J:=I —запрещено) }
J^:=5; { запись числа в выделенную память }
I^:=6; { стало и J^=6 }
I:=NIL; { I ни на что не указывает }
J:=NIL; { доступа к переменной больше нет, она не нужна }
При использовании динамических переменных происходит постоянный процесс изменения указателей. При этом некоторые переменные могут оказаться ненужными, ссылки на них уничтожаются. Но они занимают память, которую ни для каких других целей использовать нельзя, то есть образуют «мусор». Таким образом может возникнуть ситуация, что памяти более чем достаточно, но для размещения новой переменной в динамической области памяти, называемой «кучей», нет места. В этом случае значение указателя из параметра не изменится, но никаких сообщений выдано не будет, что может привести к непредсказуемым последствиям. Для повышения надежности программы следует проверять текущее состояние «кучи» перед каждым созданием новой переменной. Это можно сделать с помощью стандартной функции MaxAvail без параметров, возвращающей максимальный размер непрерывного участка свободной памяти, пригодного для размещения переменной. Например, для 4-байтовой переменной типа longint:
Var p:longint;
Begin
...
If MaxAvail >=4 then
New(p)
else
Writeln (‘Переполнение памяти’);
В общем случае для структурированных типов при определении размера выделяемой памяти можно использовать функцию SizeOf(определение размера переменной):
If MaxAvail >= SizeOf (TypeDat) then ...
Для освобождения памяти, выделенной под динамическую переменную, используется процедура, обратная по действию процедуре New:
Dispose (<указатель>);
Работа с динамическими переменными требует большой аккуратности, иначе «засорение» памяти ненужными переменными может привести к быстрому ее исчерпанию. Трудно обнаруживаемые ошибки могут возникать при использовании динамических переменных в подпрограммах: при выходе из них локальные ссылки на вновь созданные переменные теряются. Поэтому нужно придерживаться правила: при выходе из подпрограммы или освобождается память от вновь созданных в ней переменных, или ссылки сохраняются через параметры.
Дата добавления: 2016-06-29; просмотров: 1697;