Связь и интернет Архив Программирование
   
Сделать стартовойСделать закладку            
   ПОИСК  
   
Главная / Pascal и Delphi / Иллюстрированный самоучитель по Delphi 6 / Часть II . Язык Object Pascal / Типы данных /
8  Perl
8  PHP
8  JavaScript
8  HTML
8  DHTML
8  XML
8  CSS
8  C / C++
8  Pascal и Delphi
8  Турбо Ассемблер
8  MySQL
8  CASE-технологии
8  Алгоритмы
8  Python
8  Обратная связь
8  Гостевая книга
Новости о мире


Указатели и динамическая память - Программирование от RIN.RU
Указатели и динамическая память



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


Вся динамическая память в Object Pascal рассматривается как сплошной массив байтов, который называется кучей.


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


var
pI,pJ: ^Integer;
pR: ^Real;
begin
New (pI) ;
New (pR) ;
end;


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


pJ^ := 2; // В область памяти pJ помещено значение 2
pl^ := 2*pi; // В область памяти pR помещено значение 6.28


Таким образом, значение, на которое указывает указатель, т. е. собственно данные, размещенные в куче, обозначаются значком ^, который ставится сразу за указателем. Если за указателем нет значка ^ , то имеется в виду адрес, по которому размещены данные. Имеет смысл еще раз задуматься над только что сказанным: значением любого указателя является адрес, а чтобы указать, что речь идет не об адресе, а о тех данных, которые размещены по этому адресу, за указателем ставится ^ (иногда об этом говорят как о разыменовании указателя).


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


рR^ := Sqr(pR") + I^ - 17;


Разумеется, совершенно недопустим оператор


pR := Sqr(pR") + I^ - 17;


так как указателю pR нельзя присвоить значение вещественного выражения. Точно так же недопустим оператор


pR ^ := Sqr(pR) ;


поскольку значением указателя pR является адрес и его (в отличие от того значения, которое размещено по этому адресу) нельзя возводить в квадрат. Ошибочным будет и такое присваивание:


pR^' := pJ;


так как вещественным данным, на которые указывает pR, нельзя присвоить значение указателя (адрес).


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


Dispose(pJ);
Dispose(pR);


вернут в кучу память, которая ранее была закреплена за указателями pJ и pR (см. выше).


Замечу, что процедура Dispose (pPtr) не изменяет значения указателя pPtr, а лишь возвращает в кучу память, ранее связанную с этим указателем. Однако повторное применение процедуры к свободному указателю приведет к возникновению ошибки периода исполнения. Освободившийся указатель программист может пометить зарезервированным словом nil. Помечен ли какой-либо указатель или нет, можно проверить следующим образом:


const
pR: ^Real = NIL;
begin
if pR = NIL then
New (pR) ;
Dispose(pR) ;
pR := NIL;
end;


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


Приведенный выше фрагмент иллюстрирует предпочтительный способ объявления указателя в виде типизированной константы с одновременным присвоением ему значения nil. Следует учесть, что начальное значение указателя (при его объявлении в разделе переменных) может быть произвольным. Использование указателей, которым не присвоено значение процедурой New или другим способом, не контролируется Delphi и вызовет исключение.


Как уже отмечалось, параметром процедуры New может быть только типизированный указатель. Для работы с нетипизированными указателями используются Процедуры GetMem И FreeMem:


GetMem(P, Size); // резервирование памяти;
FreeMem(P, Size); // освобождение памяти.


Здесь р - нетипизированный указатель; size - размер в байтах требуемой или освобождаемой части кучи.


Примечание

Испoльзoвaние прцeдyp GetMem/FreeMemMem, как и вообще вся работа диамияесжой памятью, требует особой осторожности и тщателвного солюдения простого правила: освобождать нужно ровно столько пайти, сколько её было зарезервировано, и именно с того адреса, с которого она была зарезёрвирована.




<<<  НазадВперед  >>>
 1  2  3 


 8  Комментарии к статье  8 8  Обсудить в чате

 
  
  
    Copyright ©  RIN 2003 - 2004      * Обратная связь