- •Адресные типы
- •Использование динамической памяти
- •Линейные списки
- •Формы представления линейных списков в оперативной памяти
- •Стеки, очереди, деки
- •Представление стека в непрерывной памяти (в виде массива)
- •Представление стека в связанной памяти (в виде односвязного списка)
- •Очереди
- •Представление очереди в непрерывной памяти (в виде массива)
- •Представление очереди в связанной памяти (в виде односвязного списка)
- •Односвязный список
- •Двусвязный список
- •Кольцевые списки
- •Сортировка с помощью прямого выбора
- •Сортировка с помощью прямого обмена (пузырьковая)
- •Оценка затрат на поиск элемента
Использование динамической памяти
В отличие от ранее использовавшегося статического размещения данных, когда область памяти под данные выделялась на этапе компиляции, при динамическом размещении память выделяется/освобождается при выполнении программы.
Динамические структуры данных - структуры, размер которых заранее неизвестен или меняется при работе программы.
ПОРЯДОК РАБОТЫ С ДИНАМИЧЕСКИМИ ПЕРЕМЕННЫМИ:
ШАГ 1. Описание переменных-ссылок для хранения адресов данных.
ШАГ 2. Выделение под динамическую переменную непрерывного участка памяти заданного размера в области кучи и сохранение ее адреса в переменной адресного типа.
ШАГ 3. Работа с динамической переменной с помощью ссылки (используется операция разыменования, см. рис. 1-3).
ШАГ 4. Освобождение памяти, занимаемой динамической переменной.
ПРОЦЕДУРЫ УПРАВЛЕНИЯ ОБЛАСТЬЮ КУЧИ*
*Общие для Borland Pascal, Delphi, Free Pascal. Об использовании других подпрограмм см. в справке выбранной среды разработки.
-
РАЗМЕЩЕНИЕ ДИНАМИЧЕСКИХ ПЕРЕМЕННЫХ
New(var P:Pointer)
Только для ссылок. Отводит место в куче для хранения новой динамической переменной p^ ипа T и присваивает её адрес ссылке p.
Var p:^T;
…
New(p);
…
GetMem(var P:Pointer; Size:Integer)
Выделяет Size байт в куче и присваивает адрес его начала указателю или ссылке P.
GetMem(p, SizeOf(T))
ОСВОБОЖДЕНИЕ ДИНАМИЧЕСКИХ ПЕРЕМЕННЫХ
Dispose(var P:Pointer)
Освобождает область, занимаемую динамической переменной P^, и уничтожает связь между ссылкой P и значением, на которое она указывала.
Должна быть парна New, не должна применяться к неразмещенным ссылкам.
New(P);
…
Dispose(P);
FreeMem(var P:Pointer; Size:Integer)
Освобождает Size байт в куче, начиная с адреса, записанного в указателе или ссылке P, и уничтожает связь между P и значением. Должна соответствовать размеру, указанному в GetMem, или размеру типа переменной в New.
GetMem(p, SizeOf(T));
…
FreeMem(p,SizeOf(T));
Процедуры вызывают ошибку при использовании с неразмещенными ссылками или ссылками, указывающими на область памяти вне кучи.
ПРИМЕР 2. Поменять местами значения двух переменных (a - статических, b, c - динамических).
-
var a)
I,J,temp:Integer;
begin
I:=1;
J:=2;
temp:=J;
J:=I;
I:=temp;
…
end.
var b)
pI, pJ : ^Integer;
temp:Integer;
begin
new(PI);
new(PJ);
…
pI^:=1;
pJ^:=2;
temp:=pJ^;
pJ^:=pI^;
pI^:=temp;
…
Dispose(PI);
Dispose(PJ);
end.
var c)
pI, pJ, temp : ^Integer;
begin
new(PI);
new(PJ);
…
pI^:=1;
pJ^:=2;
temp:=pJ;
pJ:=pI;
pI:=temp;
…
Dispose(PI);
Dispose(PJ);
end.
Можно связать ссылку с областью статической памяти (не только с областью кучи). При этом выделять/освобождать память под динамическую переменную не надо. Обращение программы к такой области иногда приводит к непредсказуемым результатам.
ПРИМЕР 3. Обращение к элементам статического массива по заданной на него ссылке.
Type
arr=array [1..10] of integer;
var
a:arr;
p:^arr;
i:integer;
begin
For i:=1 to 10 do a[i]:=i;
p:=@a; // Cсылке p передается адрес массива a
for i:=1 to 10 do writeln(p^[i]); // На экран будут выведены числа от 1 до 10
readln;
end.
ПРИМЕР 4. Объявление и примеры использования ссылок (см. также презентацию "К2_Динамическая память.ppt")
TYPE ARR=ARRAY[1..5] of Integer;{базовый тип - массив} Var PInt: ^Integer; {ссылка на целое, 4 байта; рис. 2a} pa:^ARR; {ссылка на массив целых, 4 байта; рис. 2c} ap: Array[1..5] of ^Integer; {массив ссылок на целые, 20 байтов; рис. 2d} I:Integer; p: Pointer; Begin {1. Выделение памяти под динамические переменные} New(pInt); GetMem(pA,SizeOf(ARR)); For I:=1 to 5 do New(ap[I]);
{2. Работа с данными. Если память под динамические переменные не выделена, произойдет ошибка при записи значений в произвольную область памяти} pInt^:=2; For I:=1 to 5 do ap[i]^:=i; For I:=1 to 5 do pA^[i]:=5-i+1; ... { Ниже: использование переменной p типа Pointer для обмена данными между ссылками различных типов. Где кроется причина возможной ошибки???} p:=pInt; p:=ap[1]; pA:=P; ... {3. Освобождение памяти} Dispose(pInt); FreeMem(pA,SizeOf(ARR)); For I:=1 to 5 do Dispose(ap[I]); End. |
Рис. 3. Работа с динамическими переменными |
СРАВНЕНИЕ СТАТИЧЕСКИХ И ДИНАМИЧЕСКИХ ПЕРЕМЕННЫХ
Статические
Динамические
Текст программы
1) Описание типов в разделе TYPE
2) Определение переменных:
VAR a,b :Integer;
3) Доступ к данным - с помощью имен переменных
1) Описание типов в разделе TYPE
2) Определение переменных-ссылок для хранения адресов динамических переменных (а не их значений):
VAR pa,pb :^Integer;
3) В тексте программы для размещения/освобождения динамических переменных используются процедуры NEW(GetMem)/Dispose(FreeMem).
4) Доступ к данным - при разыменовании ссылки (^).
Компиляция
Выделение фиксированного объема памяти, равного суммарному объему всех объявленных переменных и типизированных констант.
Выделение фиксированного объема памяти для хранения адресов динамических переменных (а не их значений).
Выполнение
Размер памяти под переменными не меняется.
Переменные существуют до конца выполнения программы
Выделение/освобождение памяти для хранения динами-ческих переменных (New|GetMem / Dispose|FreeMem).
Эти переменные существуют до тех пор, пока для них не будет выполнен оператор Dispose или FreeMem.
ПРЕИМУЩЕСТВА ИСПОЛЬЗОВАНИЯ ДИНАМИЧЕСКИХ ПЕРЕМЕННЫХ
Данные используются только там, где они необходимы.
Несколько переменных могут совместно использовать одну область памяти.
Возможно использование структур с изменяющимся размером.
Снимаются ограничения на размер памяти, отводимой под данные.
ТЕМА. ДИНАМИЧЕСКИЕ СТРУКТУРЫ ДАННЫХ. ЛИНЕЙНЫЕ СПИСКИ
