- •Динамическая память.
- •Указатель.
- •Стандартные процедуры размещения и освобождения динамической памяти.
- •Стандартные функции обработки динамической памяти.
- •Примеры и задачи.
- •Работа с динамическими массивами.
- •Организация списков.
- •Задачи включения элемента в линейный однонаправленный список без головного элемента.
- •Формирование пустого списка.
- •Формирование очередного элемента списка.
- •Подсчет числа элементов списка.
- •Вставка элемента в начало списка.
- •Включение элемента в конец списка.
- •Включение в середину (после I-ого элемента).
- •Задачи на удаление элементов из линейного однонаправленного списка без головного элемента.
- •Удаление элемента из начала списка.
- •Удаление элемента из конца списка.
- •Удаление элемента из середины списка (I-ого элемента).
- •Удаление всего списка с освобождением памяти.
- •Задачи на замену элементов в линейном однонаправленном списке без головного элемента.
- •Стеки, деки, очереди.
- •Использование рекурсии при работе со списками.
- •Бинарные деревья.
- •Действия с бинарными деревьями.
- •Решение задач работы с бинарным деревом.
Стандартные процедуры размещения и освобождения динамической памяти.
Вся динамическая память в Паскале рассматривается как сплошной массив байтов, который называется кучей. Физически куча располагается в старших адресах сразу за областью памяти, которую занимает тело программы.
Расположение кучи в памяти ПК
Начало кучи хранится в стандартной переменной HEAPORG, конец - в переменнойHEAPEND. Текущую границу незанятой динамической памяти указывает указательHEAPPTR.
Куча(heap) занимает всю или часть свободной памяти, оставшейся после загрузки программы. Размер кучи можно установить с помощью директивы компилятораМ:
{$М <стек>, <минимум кучи>, <максимум кучи>}
где <стек> - специфицирует размер сегмента стека в байтах. По умолчанию размер стека 16 384 байт, а максимальный размер стека 65 538 байт;
<минимум кучи>- специфицирует минимально требуемый размер кучи в байтах; по умолчанию минимальный размер 0 байт;
<максимум кучи>- специфицирует максимальное значение памяти в байтах для размещения кучи; по умолчанию оно равно 655 360 байт, что в большинстве случаев выделяет в куче всю доступную память; это значение должно быть не меньше наименьшего размера кучи.
Все значения задаются в десятичной или шестнадцатеричной формах. Например, следующие две директивы эквивалентны:
{$М 16384,0,655360}
{$M $4000, $0, $A000}
Если указанный минимальный объем памяти недоступен, то программа выполняться не будет.
Управление размещением в динамической памяти осуществляет администратор кучи, являющийся одной из управляющих программ модуля System.
При выполнении программы наступает момент, когда необходимо использовать динамическую память, т.е. выделить её в нужных видах, разместить там какие-то данные, поработать с ними, а после того, как в данных отпадет необходимость - освободить выделенную память.
Динамическая память может быть выделенадвумя способами:
1. С помощью стандартной процедуры new:
new (P);
где р- переменная типа «типизированный указатель».
Эта процедура создает новую динамическую переменную (выделяет под нее участок памяти) и устанавливает на нее указатель P(вPзаписывается адрес выделенного участка памяти). Размер и структура выделяемого участка памяти задается размером памяти для того типа данных, с которым связан указательP. Доступ к значению созданной переменной можно получить с помощьюP^.
2. С помощью стандартной процедуры GetMem.
GetMem (p,size);
где P- переменная типа «указатель» требуемого типа.
size- целочисленное выражение размера запрашиваемой памяти в байтах.
Эта процедура создает новую динамическую переменную требуемого размера и свойства, а также помещает адрес этой созданной переменной в переменную Р типа «указатель». Доступ к значению созданной переменной можно получить с помощьюP^.
Динамическая память может быть освобожденачетырьмя способами.
Автоматически по завершении всей программы.
С помощью стандартной процедуры dispose.
Dispose (P);
где P- переменная типа «указатель» (типизированный).
В результате работы процедуры dispose(p)участок памяти, связанный с указателемP, помечается как свободный для возможных дальнейших размещений. При этом физической чистки указателяPи связанной с ними памяти нe происходит, поэтому, даже удалив этот экземпляр записи, можно все же получить значения ее полей, однакоиспользовать это обстоятельство не рекомендуется.
Ввиду различия в способах реализации процедуру dispose не следует использовать совместно с процедурами mark и release.
С помощью стандартной процедуры frеемеm.
FreeMem (P, size);
где P- переменная типа «указатель»,
size- целочисленное выражение размера памяти в байтах для освобождения.
Эта процедура помечает память размером, равным значению выражения size, связанную с указателемP, как свободную(см. пример для getmem).
Например:
type
Trec =record
field1:string[30];
field2:integer;
end;
ptr_rec = ^ Trec;
var
p : ptr_rec;
begin
GetMem(р, sizeof (Trec)); { выделение памяти, адрес выделенного участка фиксируется в р; размер этой памяти в байтах определяет и возвращает стандартная функция sizeof , примененная к описанному типу данных; однако, зная размеры внутреннего представления используемых полей, можно было бы подсчитать размер памяти «вручную» и записать в виде константы вместо sizeof (Trec) }
...
{использование памяти}
...
FreeMem(p, sizeof(Trec)); {освобождение уже ненужной памяти}
...
4. С помощью стандартных процедур маrkиrelease.
Mark (P);
Release (P);
где P - переменная типа «указатель»;
mark- запоминает состояние динамической области в переменной-указателер;
release- освобождает всю динамическую память, которая выделена процедурамиnewилиgetmemпосле запоминания текущего значения указателярпроцедуройmark.
Обращения к mark иReleaseнельзя чередовать с обращениями кDisposeиFRееМеmввиду различий в их реализации.
Например:
var
p:pointer;
p1, p2, p3:^integer;
begin
New(p1);
p1^ := 10;
Mark(p); {пометка динамической области}
New(p2);
p2^ := 25;
New(p3);
p3^ := p2^ + p1^;
Writeln ( p3^);
Release(p); {память, связанная с p2^ и p3^, освобождена, а p1^ может использоваться}
end.