Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
К2_Допматериалы_15апр.doc
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
2.99 Mб
Скачать

Использование динамической памяти

В отличие от ранее использовавшегося статического размещения данных, когда область памяти под данные выделялась на этапе компиляции, при динамическом размещении память выделяется/освобождается при выполнении программы.

  • Динамические структуры данных - структуры, размер которых заранее неизвестен или меняется при работе программы.

  • ПОРЯДОК РАБОТЫ С ДИНАМИЧЕСКИМИ ПЕРЕМЕННЫМИ:

ШАГ 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.

  • ПРЕИМУЩЕСТВА ИСПОЛЬЗОВАНИЯ ДИНАМИЧЕСКИХ ПЕРЕМЕННЫХ

  1. Данные используются только там, где они необходимы.

  2. Несколько переменных могут совместно использовать одну область памяти.

  3. Возможно использование структур с изменяющимся размером.

  4. Снимаются ограничения на размер памяти, отводимой под данные.

  • ТЕМА. ДИНАМИЧЕСКИЕ СТРУКТУРЫ ДАННЫХ. ЛИНЕЙНЫЕ СПИСКИ