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

8.6. Динамические массивы

Необходимость работы с большими по числу элементов массивами явилась главной причиной для разработки методов работы с дополнительной динамической памятью. Одним из ее основных результатов явился тип данных "указатель", который в двух словах (по два байта каждое) содержит адрес одиночной величины или массива. Этот тип рассмотрен в Главе 3. Указатель на адрес величины a получается путем использования префикса ^ перед ней: ^a. Для засылки в указатель адреса уже существующей переменной применяют операцию получения адреса переменной (префикс @ перед ее именем или обращение к функции addr()), для обращения к значению переменной, адрес которой хранится в указателе, к нему примеряется операция разыменования, обозначаемая при помощи суффикса ^.

Выше были рассмотрены обычные массивы, у которых размер устанавливается при описании и не изменяется при выполнении программы, при этом фактически для работы может использоваться не все описанное количество элементов. Такие массивы называют статическими. Данный тип массивов всегда существовал в Паскале. Он удобен при относительно небольших числах элементов в массиве. Если переменная является статическим массивом, то она является хранилищем его данных и имеет размер, равный произведению количества элементов на их размер.

В отличие от статических, динамическими называют массивы, размер которых может изменяться во время исполнения программы. С одной стороны, это дает возможность работать с массивами, не ограничивая заранее их размер предельными объёмами. С другой стороны, более рационально используется память вычислительного устройства за счет выделения массивам реально необходимых ее объёмов. Динамические массивы появились в более поздних версиях Паскаля, с появлением Delphi 4. В отличие от статического случая, переменная динамического массива не содержит все элементы массива, а является указателем на область в памяти, где лежат данные элементы, т.е. на первый элемент массива. Использование динамических массивов освобождает от непосредственного использования указателей в простейших случаях работы с динамической памятью.

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

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

Пример 1. Описания динамических массивов:

type T1DByteArray : Array of Byte; {Предварительное описание одномерного динамического массива байтовых величин}

T1DIntArray = array of integer; {Предварительное описание одномерного динамического массива целых величин}

T2DStringArray : Array of Array of string; {Предварительное вложенное описание двумерного динамического массива строковых величин}

var B: T1DByteArray; {Присвоение переменной B типа одномерного динамического массива байтовых величин T1DByteArray }

StringMas: T2DStringArray; {Присвоение переменной StringMas типа двумерного динамического массива строковых величин T2DStringArray }

Ar_Int: array of integer; {Непосредственное описание переменной Ar_Int как одномерного динамического массива целых величин}

При объявлении динамического массива место под него не отводится. Переменная динамического массива представляет собой обычный указатель (4 байта) на начало массива. Если массив еще не объявлен либо количество элементов в нем равно 0 (массив пуст), то переменная равна nil.

Если динамический массив не пуст, то его действительный размер всегда на 8 байт больше того пространства памяти, которое занимают его элементы за счет двух дополнительных 4-байтовых величины. Сразу перед данными (по отрицательному смещению -4) в памяти помещается индикатор количества элементов в массиве. Перед ним (по смещению -8) находится счетчик ссылок на массив. Этот счетчик ссылок позволяет иметь несколько переменных, ссылающихся на одни и те же данные в массиве и не заботиться об управлении памятью. Компилятор самостоятельно следит за доступом к данным и при уменьшении счетчика ссылок до 0 освобождает всю память массива. Нумерация элементов в динамических массивах, в отличие от статических, начинается с 0 (как в языке С).

Присваивание динамических массивов вида Array_A:= Array_B по аналогии со статическими возможно, когда:

1) оба массива описаны как динамические и имеют одинаковый тип элементов,

2) размер массива Array_A не превышает (больше либо равен) размеру Array_B, либо Array_A=nil.

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

Удалить динамический массив можно несколькими способами: применением функции Finalize или установкой нулевой длины массива.

Помимо возможности описания массивов без указания их размерности, в Паскале введены следующие основные функции для работы с динамическими массивами:

1) SetLength (mas, number)- устанавливает новый размер массива mas равным number (число элементов);

2) Length (mas)- возвращает количество элементов в массиве mas;

3) Low (mas)_- возвращает индекс первого элемента в массиве mas (всегда 0 для динамических массивов);

4) High (mas)- возвращает индекс последнего элемента в массиве mas;

5) Copy(mas, start_imdex, number) - возвращает подмножество из number элементов массива mas, начиная с номера start_imdex;

6) Slice - используется при передаче динамического массива в процедуры в качестве открытого массива (open arrays).

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

Пример 2. Задание длины массива Ar_Int из примера 1:

SetLength(Ar_Int,10);

В результате в массиве будет задано 10 элементов - от Ar_Int[0] до Ar_Int[9].

Обращение к первому элементу динамического массива Dyn_Ar имеет вид Dyn_Ar[0] или Dyn_Ar[Low (Dyn_Ar)].

Пример 3. Обнуление всех элементов динамического массива Dyn_Ar типа integer:

FillChar(Dyn_Ar [0],Length(Dyn_Ar)*sizeof(integer));

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

Пример 4 с использованием динамических массивов А,В и статического С:

var A,B: array of integer;

C: array[0..10] of integer;

Len, i: Integer;

begin

Len:=4; SetLength (A,Len); //Создание дин. массива А(0,0,0,0)

for i:=0 to Len-1 do A[i]:=2*i; // Создание дин. массива А (0,2,4,6)

B:=A; // Копирование дин. массива А (0,2,4,6) в дин массив В

for i:=0 to Len-1 do C[i]:=A[i]; // Засылка значений в стат. массив С: C(0,2,4,6)

A[1]:=10; //Изменение значения первого элемента массива А: A[1]:=10

writeln (' Enter values of massiv elements:');

for i:=0 to Len-1 do

writeln (' A[',i,']=',A[i], ' B[',i,']=',B[i], ' C[',i,']=',C[i]);

A:=Copy(A,1,2); //Запись в 2 первых элемента (А[0],A[1]) массива А прежних значений А[1], A[2]

writeln (' Finish values of massiv elements:');

for i:=0 to Len-3 do

writeln (' A[',i,']=',A[i],' B[',i,']=',B[i], ' C[',i,']=',C[i]);

SetLength(A,0); SetLength(B,0); //Удаление динамических массивов А и В

end.

B итоге работы программы на экране пользователя выдается информация:

Первая выдача значений элементов массивов показывает, что присвоение B:=A в начале задает полную идентичность динамических массивов A и B - изменение A[1]:=10 автоматически вызвало такое же изменение в массиве В[1]:=10. Статический массив, в который поэлементно были засланы элементы A, не изменился.

Вторая выдача значений массивов показывает, что применение функции Copy к массиву A вызвало разрыв связи динамических массивов A и B.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]