Помощничек
Главная | Обратная связь


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

С помощью стандартной процедуры GetMem



GetMem ( P, size );

где P - переменная типа «указатель» требуемого типа.

size - целочисленное выражение размера запрашиваемой памяти в байтах, здесь также может использоваться функция SizeOf(тип_данных).

 

Эта процедура создает новую динамическую переменную требуемого размера и свойства, а также помещает адрес этой созданной переменной в переменную Ртипа «указатель». Доступ к значению созданной переменной можно получить с помощью P^.

Например:

Type

Rec =record

Field1:string[30];

Field2:integer;

end;

ptr_rec = ^ rec;

Var

p : ptr_rec;

Begin

GetMem ( Р, SizeOf (Rec)); { Выделение памяти;

адрес выделенного участка фиксируется в Р;

размер этой памяти в байтах определяет и возвращает стандартная функция SizeOf, примененная к описанному типу данных; однако, зная размеры внутреннего представления используемых полей, можно было бы подсчитать размер памяти «вручную» и записать в виде константы вместо SizeOf (Rec) }

...

{использование памяти}

...

FreeMem ( p, SizeOf (Rec)); {освобождение уже ненужной памяти}

...

 

 

Динамическая память может быть освобождена следующими способами

1. С помощью стандартной процедуры Dispose

(употребляется в паре с New(…)).

Dispose (P);

где P - переменная типа «указатель»

(типизированный).

В результате работы процедуры Dispose(P) участок памяти, связанный с указателем P, помечается как свободный для возможных дальнейших размещений. При этом физической чистки указателя P и связанной с ним памяти нe происходит, поэтому, даже удалив этот экземпляр записи, можно все же получить значения ее полей, однако использовать это обстоятельство категорически не рекомендуется.

 

2. С помощью стандартной процедуры FRееМеm.

(употребляется в паре с GetMem (…)).

 

FreeMem (P, size);

где P - переменная типа «указатель»,

size - целочисленное выражение размера памяти в байтах для освобождения.

Эта процедура помечает память размером, равным значению выражения size, связанную с указателем P, как свободную (см. пример для GetMem).

 

3. Автоматически по завершении всей программы.

 

Управлять распределением и освобождением оперативной памяти можно следующей парой процедур

Mark (P);

Release (P);

где P - переменная типа «указатель»;

Mark - запоминает в переменной-указателе р состояние

динамической области в данный момент;

Release - освобождает всю динамическую память,

которая выделена процедурами New или Getmem после запоминания текущего значения указателя р с помощью процедуры Mark.

 

 

Следует распределять и освобождать память «парными» процедурами:

· GetMem – FreeMem,

· New – Dispose,

· Mark – Release.

Обращения к Mark и Release нельзя чередовать с обращениями к Dispose и Frееmem ввиду различий в их реализации.

 

Например:

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.

Стандартные функции обработки динамической памяти.

 

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

Для этих целей Турбо Паскаль предоставляет две функции (без параметров).

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.


Организация списков.

 

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

 

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

 

 




Поиск по сайту:

©2015-2020 studopedya.ru Все права принадлежат авторам размещенных материалов.