Размещение динамических переменных в куче
Процедуры для работы со ссылками
Под динамические переменные память выделяется в куче во время выполнения программы с помощью процедур 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.