- •Технология программирования (pascal)
- •V. Структуры и организация данных
- •2. Динамические структуры данных
- •2.2. Указатели и их использование для работы с динамическими переменными.
- •1. Проверка наличия требуемого объема памяти в heap-области.
- •2.3. Динамический массив.
- •2.4. Линейные связанные структуры.
- •2.5. Линейные списки.
- •1. Объявление (описание) данных односвязного списка:
- •2. Создание первого элемента списка и заполнение полей:
- •3. Создание следующего элемента и связывание его с первым элементом:
- •4. Создание списка из n элементов:
- •5. Удаление элемента списка:
- •1. Объявление данных двусвязного списка:
- •2. Пример программы работы с двусвязным списком.
1. Проверка наличия требуемого объема памяти в heap-области.
Перед использованием стандартных процедур распределения динамической памяти необходимо проверить наличие требуемого объема памяти в HEAP-области.
FUNCTION CHECK(VAR P:POINTER; SIZE:WORD): BOOLEAN;
BEGIN
CHECK:=TRUE;
IF SIZE<=MAXAVAIL THEN
GETMEM(P,SIZE)
ELSE
CHECK:=FALSE;
END;
Функция возвращает значение TRUE, если запрашиваемый размер памяти меньше или равен размеру наибольшего непрерывного участка памяти в HEAP-области (функция MAXAVAIL), иначе – FALSE.
2. Использование функции указателя HeapError – стандартной функции, адрес которой при запуске программы содержит переменная HeapError; возвращает 0, что приводит к останову программы по ошибке периода счета с кодом 203.
Можно переопределить эту функцию и таким образом блокировать останов программы, для чего необходимо написать собственную функцию и поместить ее адрес в указатель HeapError.
{$F+}
FUNCTION HEAPFUNC(SIZE:WORD): INTEGER;
BEGIN
HEAPFUNC:=1;
END;
{$F-}
FUNCTION CHECK(VAR P: POINTER; SIZE: WORD): BOOLEAN;
VAR
OLDHEAPER: POINTER;
BEGIN
OLDHEAPER:= HEAPERROR;
HEAPERROR:=ADDR(HEAPFUNC);
GETMEM(P, SIZE);
HEAPERROR:= OLDHEAPER;
CHECK:= (P<>NIL);
END;
Функция HEAPFUNC принудительно возвращает указатель NIL, если невозможно выделить достаточно динамической памяти для распределения данных.
Функция CHECK пытается разместить динамическую переменную в памяти и возвращает значение TRUE, если операция выделения памяти прошла успешно.
Данный способ локализации ошибок распределения памяти в HEAP-области является наиболее предпочтительным.
2.3. Динамический массив.
Динамическим
массивом
ее
я вания за иской памятинеобходимое для
размещения требуемой
переменной.
Таким образом, в случае работы с динамическим массивом программист должен самостоятельно заботиться о резервировании памяти.
Необходимость использования средств работы с динамической памятью при обработке массивов возникает в случаях, когда статическая реализация неэффективна (например, размеры массивов заранее неизвестны, а резервирование памяти максимально возможного объема нерационально). При этом суть понятия массива сохраняется, т. е. массив – это совокупность однотипных элементов, которые расположены в определенном порядке и различаются индексами; над каждым элементом массива возможны любые операции, допускаемые типом элементов.
Перечисленные свойства достаточно просто моделируются средствами динамической памяти, которая является, фактически, единственной возможностью обработки массивов данных большой размерности, таких, которые настолько велики, что не могут быть размещены в сегменте данных размером в 64 Кбайт. Только в динамической памяти можно создать массив, размер которого заранее не определён.
Один из возможных вариантов получения динамического двумерного массива размерности n на m:
type
mas = array [1..1] of integer;
pmas = ^mas;
matr = array [1..1] of pmas;
pmatr = ^matr;
var
a: pmatr;
n, m: integer;
begin
readln(n, m);
GetMem (a, n*sizeof(pmas));
for i:=1 to n do
GetMem (a^[i], m*sizeof(integer));
. . .
{ обращение к отдельному элементу имеет вид a^[i]^[j] }
. . .
for i:=1 to n do
FreeMem (a^[i], m*sizeof(integer));
FreeMem (a, n*sizeof(pmas));
end.
Описание интерфейсов для статического и динамического массивов
Понятие массив используется на уровне постановки задачи: задается или должно быть сформировано множество однотипных данных.
При описании интерфейса подпрограммы – связи с программой или другими подпрограммами – необходимо знать перечень входных и выходных данных, их тип и способ размещения.
Вопросы использования статического или динамического массивов связаны с эффективностью реализации подпрограммы и не должны влиять на интерфейс, поэтому следует выбирать способ описания интерфейса, позволяющий отложить решение этих вопросов, по крайней мере, до этапа разработки схемы решения.
Входные и выходные данные при работе со статическим или динамическим массивом будут иметь один и тот же вид, но в случае работы с динамическим массивом его имя заменится на указатель с соответствующей спецификой его обработки.