Студопедия — УКАЗАТЕЛИ И ДИНАМИЧЕСКАЯ ПАМЯТЬ
Студопедия Главная Случайная страница Обратная связь

Разделы: Автомобили Астрономия Биология География Дом и сад Другие языки Другое Информатика История Культура Литература Логика Математика Медицина Металлургия Механика Образование Охрана труда Педагогика Политика Право Психология Религия Риторика Социология Спорт Строительство Технология Туризм Физика Философия Финансы Химия Черчение Экология Экономика Электроника

УКАЗАТЕЛИ И ДИНАМИЧЕСКАЯ ПАМЯТЬ






7.4.1. Динамическая память

Динамическая память - это оперативная память ПК, предоставляемая программе при ее работе. Динамическое размещение данных означает использование динамической памяти непосредственно при работе программы. В отличие от этого статическое размещение осуществляется компилятором Object Pascal в процессе компиляции программы. При динамическом размещении заранее не известны ни тип, ни количество размещаемых данных.

7.4.2. Указатели

Оперативная память ПК представляет собой совокупность ячеек для хранения информации - байтов, каждый из которых имеет собственный номер. Эти номера называются адресами, они позволяют обращаться, к любому байту памяти. Object Pascal предоставляет в распоряжение программиста гибкое средство управления динамической памятью - так называемые указатели. Указатель - это переменная, которая в качестве своего значения содержит адрес байта памяти. С помощью указателей можно размещать в динамической памяти любой из известных в Object Pascal типов данных. Лишь некоторые из них (Byte, Char, ShortInt, Boolean) занимают во внутреннем представлении один байт, остальные - несколько смежных. Поэтому на самом деле указатель адресует лишь первый байт данных.

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

Var

p1: ^Integer;

р2: ^Real;

Type

PerconPointer = "PerconRecord;

PerconRecord = record Name: String;

Job: String;

Next: PerconPointer,

End;

Обратите внимание: при объявлении типа PerconPointer мы сослались на тип PerconRecord, который предварительно в программе объявлен не был. Как уже отмечалось, в Object Pascal последовательно проводится в жизнь принцип, в соответствии с которым перед использованием какого-либо идентификатора он должен быть описан. Исключение сделано только для указателей, которые могут ссылаться на еще не объявленный тип данных.

В Object Pascal можно объявлять указатель и не связывать его при этом с каким-либо конкретным типом данных. Для этого служит стандартный тип pointer, например:

Var

р: Pointer;

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

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

Если, например,

Var

pI1,pI2: ^integer;

pR: ^Real;

p: Pointer;

то присваивание

pI1:= pI2;

вполне допустимо, в то время как

pl1:=pR;

запрещено, поскольку pI1 и pR указывают на разные типы данных. Это ограничение, однако, не распространяется на нетипизированные указатели, поэтому мы могли бы записать

p:= pR;

pI1:= p;

и тем самым достичь нужного результата.

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

Вся динамическая память в 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, как и вообще вся работа диамияесжой памятью, требует особой осторожности и тщателвного солюдения простого правила: освобождать нужно ровно столько пайти, сколько её было зарезервировано, и именно с того адреса, с которого она была зарезёрвирована.

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

В табл. 7.14 приводится описание как уже рассмотренных процедур и функций Object Pascal, так и некоторых других, которые могут оказаться полезными при обращении к динамической памяти.

Таблица 7.14. Средства Object Pascal для работы с памятью

Function Addr(X): Pointer; Возвращает адрес аргумента X. Аналогичный результат возвращает операция @
Procedure Dispose (var P: Pointer); Возвращает в кучу фрагмент динамической памяти, который ранее был зарезервирован за типизированным указателем P
Procedure Free-Mem(var P: Pointer; Size: Integer); Возвращает в кучу фрагмент динамической памяти, который ранее был зарезервирован за нетипизированным указателем Р  
Procedure Get-Mem(var P: Pointer; Size: Integer); Резервирует за нетипизированным указателем Р фрагментдинамической памяти требуемого размера Size
Procedure New(var P: Pointer); Резервирует фрагмент кучи для размещения переменной и помещает в типизированный указатель Р адрес первого байта
Function SizeOf(X): Integer; Возвращает длину в байтах внутреннего представления указанного объекта Х

 

Windows имеет собственные средства работы с памятью. В табл. 7.15 перечислены соответствующие API-функции и даны краткие пояснения. За более полной информацией обращайтесь к справочной службе в файлах WIN32. hlp или WIN32S. hlp.

Таблица 7.15. Средства Windows для работы с памятью

CopyMemory   Копирует содержимое одного блока памяти в другой блок. Блоки не должны перекрываться хотя бы частично
FillMemory Заполняет блок памяти указанным значением
GetProcessHeap Возвращает дескриптор кучи для текущей программы
GetProcessHeaps Возвращает дескрипторы куч для всех работающих программ
GlobalAlloc Резервирует в куче блок памяти требуемого размера
GlobalDiscard Выгружает блок памяти
GlobalFlags Возвращает информацию об указанном блоке памяти
GlobalFree Освобождает блок памяти и возвращает его в общий пул памяти
GlobalHandle Возвращает дескриптор блока памяти, связанного с заданным указателем
GlobalLock Фиксирует блок памяти и возвращает указатель на его первый байт
GlobalMemoryStatus   Возвращает информацию о доступной памяти (как физической, так и виртуальной)
GlobalReAlloc Изменяет размер и атрибуты ранее зарезервированного блока памяти
GlobalSize Возвращает размер в байтах блока памяти
GlobalUnlock Снимает фиксацию блока памяти и делает его перемещаемым
HeapAlloc Резервирует в куче неперемещаемый блок памяти
HeapCompact Удаляет фрагментацию кучи
HeapCreate Создает для программы новую кучу
HeapDestroy Возвращает кучу в общий пул памяти
HeapFree   Освобождает блок памяти, зарезервированный функциями HeapAlloc или HeapReAlloc
HeapLock Делает указанную кучу доступной только для текущего потока
HeapReAlloc Изменяет размер и/или свойства кучи
HeapSize Возвращает размер кучи в байтах
HeapUnlock Делает указанную кучу доступной для любых потоков текущего процесса
HeapValidate Проверяет состояние кучи или размещенного в ней блока памяти
IsBadCodePtr   Сообщает, может ли вызывающая программа читать данные из указанного адреса памяти (но не из блока памяти)
IsBadHugeReadPtr   Сообщает, может ли вызывающая программа читать данные из указанного блока памяти
IsBadHugeWritePtr Сообщает, может ли вызывающая программа изменять содержимое указанного блока памяти
IsBadReadPtr Сообщает, может ли вызывающая программа читать данные из указанного блока памяти
IsBadStringPtr Сообщает, может ли программа читать содержимое строки, распределенной в куче
IsBadWritePtr Сообщает, может ли вызывающая программа изменять содержимое указанного блока памяти
LocalAlloc Аналогична GlobalAlloc
:: LocalDiscard Аналогична GloalDiscard
'LocalFlags Аналогична GlobalFlags
LocalFree Аналогична Global Free
LocalHandle Аналогична GlobalHandle
LocalLock Аналогична GlobalLock
LocalReAlloc Аналогична GlobalReAlloc
LocalSize Аналогична GlobalSize
LocalUnlock Аналогична GlobalUnlock
MoveMemory Копирует один блок памяти в другой. Блоки могут перекрываться
VirtualAlloc Резервирует блок виртуальной памяти
VirtualFree Освобождает блок виртуальной памяти
VirtualLock Фиксирует блок виртуальной памяти
VirtualProtect Изменяет права доступа текущей программы к виртуальному блоку памяти
VirtualProtectEx Изменяет права доступа указанной программы к виртуальному блоку памяти
VirtualQuery Возвращает свойства виртуального блока памяти по отношению к вызывающей программе
VirtualQueryEx Возвращает свойства виртуального блока памяти по отношению к указанной программе
VirtualUnloc'k Снимает фиксацию блока виртуальной памяти
ZeroMemory Заполняет блок памяти нулями

 







Дата добавления: 2015-10-18; просмотров: 596. Нарушение авторских прав; Мы поможем в написании вашей работы!



Аальтернативная стоимость. Кривая производственных возможностей В экономике Буридании есть 100 ед. труда с производительностью 4 м ткани или 2 кг мяса...

Вычисление основной дактилоскопической формулы Вычислением основной дактоформулы обычно занимается следователь. Для этого все десять пальцев разбиваются на пять пар...

Расчетные и графические задания Равновесный объем - это объем, определяемый равенством спроса и предложения...

Кардиналистский и ординалистский подходы Кардиналистский (количественный подход) к анализу полезности основан на представлении о возможности измерения различных благ в условных единицах полезности...

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

Правила наложения мягкой бинтовой повязки 1. Во время наложения повязки больному (раненому) следует придать удобное положение: он должен удобно сидеть или лежать...

ТЕХНИКА ПОСЕВА, МЕТОДЫ ВЫДЕЛЕНИЯ ЧИСТЫХ КУЛЬТУР И КУЛЬТУРАЛЬНЫЕ СВОЙСТВА МИКРООРГАНИЗМОВ. ОПРЕДЕЛЕНИЕ КОЛИЧЕСТВА БАКТЕРИЙ Цель занятия. Освоить технику посева микроорганизмов на плотные и жидкие питательные среды и методы выделения чис­тых бактериальных культур. Ознакомить студентов с основными культуральными характеристиками микроорганизмов и методами определения...

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

Закон Гука при растяжении и сжатии   Напряжения и деформации при растяжении и сжатии связаны между собой зависимостью, которая называется законом Гука, по имени установившего этот закон английского физика Роберта Гука в 1678 году...

Характерные черты официально-делового стиля Наиболее характерными чертами официально-делового стиля являются: • лаконичность...

Studopedia.info - Студопедия - 2014-2024 год . (0.011 сек.) русская версия | украинская версия