
- •Динамическая память.
- •Указатель.
- •Стандартные процедуры размещения и освобождения динамической памяти.
- •1. С помощью стандартной процедуры New:
- •2. С помощью стандартной процедуры GetMem.
- •С помощью стандартной процедуры Dispose
- •С помощью стандартной процедуры fRееМеm.
- •Стандартные функции обработки динамической памяти.
- •Примеры и задачи.
- •Организация списков.
- •Задачи включения элемента в линейный однонаправленный список без головного элемента.
- •Формирование пустого списка.
- •Формирование очередного элемента списка.
- •Подсчет числа элементов списка.
- •Вставка элемента в начало списка.
- •Включение элемента в конец списка.
- •Включение в середину (после I-ого элемента).
- •1.1Задачи на удаление элементов из линейного однонаправленного списка без головного элемента.
- •Удаление элемента из начала списка.
- •Удаление элемента из конца списка.
- •Удаление элемента из середины списка (в данном случае I-ого элемента).
- •Удаление всего списка с освобождением памяти.
- •Задачи на замену элементов в линейном однонаправленном списке без головного элемента.
- •Стеки, деки, очереди.
- •Использование рекурсии при работе со списками.
Стандартные функции обработки динамической памяти.
В процессе выполнения программы можно наблюдать за состоянием динамической области для оценки возможности очередного выделения динамической области требуемого размера.
Для этих целей Турбо Паскаль предоставляет две функции (без параметров).
MaxAvail;
Тип возвращаемого значения - longint.
Функция возвращает размер в байтах наибольшего свободного в данный момент участка в динамической области. По этому размеру можно судить о том, какую наибольшую динамическую память можно выделить.
type
zap=record
field1: string [20];
field2: real;
end;
var
p: pointer;
begin
...
if MaxAvail < SizeOf (zap)
then Writeln ('He хватает памяти!')
else GetMem ( р, SizeOf(zap));
...
Вторая функция:
MemAvail;
Тип возвращаемого значения - longint.
Эта функция возвращает общее число свободных байтов динамической памяти, то есть суммируются размеры всех свободных участков и объем свободной динамической области.
...
Writeln( 'Доступно', MemAvail, ' байтов' );
Writeln('Наибольший свободный участок=', MaxAvail,
'байтов' );
...
Динамическая область размещается в специально выделяемой области, которая носит название «куча» (heap). Куча занимает всю или часть свободной памяти, оставшейся после загрузки программы. Размер кучи можно установить с помощью директивы компилятора М:
{$М <стек>, <минимум кучи>, <максимум кучи>}
где <стек> - специфицирует размер сегмента стека в байтах. По умолчанию размер стека 16 384 байт, а максимальный размер стека 65 538 байт;
<минимум кучи> - специфицирует минимально требуемый размер кучи в байтах; по умолчанию минимальный размер 0 байт;
<максимум кучи> - специфицирует максимальное значение памяти в байтах для размещения кучи; по умолчанию оно равно 655 360 байт, что в большинстве случаев выделяет в куче всю доступную память; это значение должно быть не меньше наименьшего размера кучи.
Все значения задаются в десятичной или шестнадцатеричной формах. Например, следующие две директивы эквивалентны:
{$М 16384,0,655360}
{$M $4000, $0, $A000}
Если указанный минимальный объем памяти недоступен, то программа выполняться не будет.
Управление размещением в динамической памяти осуществляет администратор кучи, являющийся одной из управляющих программ модуля System.
Примеры и задачи.
Рассмотрим пример размещения и освобождения разнотипных динамических переменных в куче.
type
st1=string[7];
st2=string[3];
var
i,i1,i2,i3,i4 : ^integer;
r^ : real;
s1 : ^st1;
s2 : ^st2;
begin
New (i) ;
i1^:=1;
New(i2);
i2^ := 2 ;
New ( i3 );
i3^=3;
New(i4);
i4^ := 4 ; {1}
Disроsе ( i2 ) ; {освобождается второе размещение}
New ( i ); {память нужного размера (в данном случае два байта)
выделяется на первом свободном месте от начала кучи,
достаточном для размещения данной переменной;
в этом примере - это участок, который занимала
переменная i2^, ее адрес остался в указателе i2 }
i^ := 5 ; {2}
Dispose ( i3 ) ; {освобождается третье размещение}
New ( r ) ; {память под переменную типа real выделяется
в вершине кучи, так как размер дырки с адресом i3
(2 байта) мал для размещения переменной типа real,
для которой необходимо 6 байт }
r^ := 6 ; {3}
writeln ( r^ ) ; { ВЫВОД: 6.0000000000E+00}
END.
В следующем примере используется массив указателей.
uses Crt;
var
r: array [1..10] of ^real;
i : 1..10 ;
begin
Randomize; {инициализация генератора случайных чисел}
for i :=1 to 10 do
begin
New ( r [ i ] );
r [ i ]^ := Random; {генерация случайных вещественных чисел
в диапазоне 0 <= r[i]^ < 1}
writeln ( r [ i ]^ ); {Вывод случайных чисел
в экспоненциальной форме}
end;
end.