Размещение динамических переменных в куче

Процедуры для работы со ссылками

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

New(var p: тип указателя); – создает новую динамическую переменную и устанавливает на нее указатель p. Параметром обращения к этой процедуре является типизированный указатель. В результате обращения указатель приобретает значение, соответствующее адресу, начиная с которого, можно разместить данные.

Dispose(var p: тип указателя); – освобождает память, занимаемую динамической переменной.

Getmem (var p:pointer, Size:) – создает новую динамическую переменную размером Size и устанавливает на нее указатель p.

Freemem (var p:pointer, Size:word)– освобождение памяти, занятой динамической переменной p размером Size байт.

Процедуры Getmem и Freemem можно использовать для работы с нетипизированными указателями.

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

Динамическая область памяти

Начало кучи хранится в стандартной переменной Heaporg, конец – в переменной Heapend. Текущую границу незанятой динамической памяти указывает указатель Heapptr.

Системная область Программа ######## Куча Системная область

Heaporg
Heapptr
Heapend

При очередном обращении к процедуре new или getmem система отыскивает наименьший свободный фрагмент, в котором может разместиться требуемая переменная. Перед выделением большого объема в динамически распределяемой памяти полезно убедиться, что такой объем памяти имеется. Для этого можно использовать функцию MaxAvail, которая возвращает размер наибольшего доступного блока непрерывной памяти в динамически распределяемой области. Существует еще функция MemAvail, возвращающие общее число байтов, доступных для распределения в динамической памяти. Первоначально при запуске программы MaxAvail равно MemAvail, поскольку вся динамически распределяемая область памяти является доступной и непрерывной.

Освободить фрагмент кучи можно при использовании процедур Mark и Release. Процедура Mark(varp : pointer) запоминает состояние динамической памяти в тот момент, когда эта процедура вызывается. В указателе р сохраняется адрес первого байта свободной области памяти. Далее можно несколько раз выделить память. Процедура Release(varp : pointer) возвращает динамическую память в состояние, которое было запомнено ранее при помощи процедуры Mark.

Использование переменных ссылочного типа

Наиболее часто ссылочные переменные используются в следующих случаях:

1. Использование одной области данных для представления разными типами.

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

3. Программа во время компиляции использует данные, для которых заранее неизвестен необходимый объем памяти. Если расположить переменные в динамически распределяемой области памяти во время выполнения программы, то для хранения данных будет выделено столько байтов памяти, сколько потребуется.

4. В программе необходимо использовать массив большой размерности, не помещающийся в сегменте стека.

5. Возможность построения объектов со сложной, меняющейся структурой. Примерами таких структур являются списки, стеки, деревья

Пример 4. Дано 10000 целых чисел a1, а2, ..., а10000, значения которых лежат в диапазоне от -9000 до 9000, и 9000 вещественных чисел b1, b2, , b9000. Вывести минимальное из чисел a1, а2, ..., а10000. Вывести число bk, номер которого k равен абсолютному значению этого минимального.

program Prog10_2;

type ar=array[1..10000] of integer; {определяем массив}

br=array[1..9000] of real; {определяем массив}

var a:^ar; { a указатель на массив типа ar }

b:^br; { b указатель на массив типа br }

k,i:integer;

Begin

new(a); {выделение памяти под массив a }

randomize;

k:=9000;

fori:= 1to10000do begin

a^[i]:=random(18000)-9000; {формируем массив a с помощью генератора случайных чисел}

if a^[i]< k then k:= a^[i]; {находим минимальное }

end;

dispose(a); {освобождаем память}

new(b); {выделение памяти под массив b }

fori:= 1to9000do

readln(b^[i]);

writeln(’мин а ’,k,’ b[k]= ’, b[abs(k)])

dispose(b); {освобождаем память}

End.

Пример 5. Найти сумму элементов массива d, состоящего из 200 строк и 200 столбцов.

Под элементы двумерного массива такого размера потребуется 200´200´6 байтов памяти, что составит более 234К. Нужно реорганизовать массив так, чтобы он распался на части, не превышающие по отдельности 64К (сегмент данных).

program Prog10_3;

type d200=array[1..200] of real; {определяем массив}

dPtr =^d200;{объявлен тип ссылки на строку}

dPtr200=array[1..200] of dPtr;{тип для массива указателей}

var d:dPtr200; {объявили массив указателей, каждый элемент которого указывает на одномерный массив d200}

s:real; i, j:integer;

Begin

randomize;

s:=0;

fori:= 1to200do begin

new(d[i]); {выделили память под строку из 200 элементов, на которую указывает ссылка d[i]}

forj:= 1to200do begin

d[i]^[j]:=random(20); {формируем массив с помощью генератора случайных чисел}

s:=s+d[i]^[j]; {находим сумму }

end;

dispose(d[i]); {освобождаем память}

end;

writeln(’s= ’,s)

End.

Пример 6. Создание массива с переменной верхней границей[1].

program Prog10_4;

type d=array[1..2] of real;

var a:^d; {a указатель на массив типа d }

n,i:word;

Begin

writeln(‘введите размер массива’);

readln(n);

getmem(a,n*6); {выделение памяти под n вещественных чисел}

fori:= 1tondoa^[i]:=sqr(i);

freemem(a,n*6); {освобождаем память}

End.

Наши рекомендации