Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Программирование на языке Delphi_1.doc
Скачиваний:
43
Добавлен:
28.03.2015
Размер:
710.14 Кб
Скачать
      1. 2.9.4. Уплотнение структурных данных в памяти

С целью экономии памяти, занимаемой массивами и другими структурными данными, вы можете предварять описание типа зарезервированным словом packed, например:

var

A: packed array[1..10] of Byte;

Ключевое слово packed указывает компилятору, что элементы структурного типа должны храниться плотно прижатыми друг к другу, даже если это замедляет к ним доступ. Если структурный тип данных описан без ключевого слова packed, компилятор выравнивает его элементы на 2- и 4-байтовых границах, чтобы ускорить к ним доступ.

Заметим, что ключевое слово packed применимо к любому структурному типу данных, т.е. массиву, множеству, записи, файлу, классу, ссылке на класс.

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

Одним из мощнейших средств языка Delphi являются динамические массивы. Их основное отличие от обычных массивов заключается в том, что они хранятся в динамической памяти. Этим и обусловлено их название. Чтобы понять, зачем они нужны, рассмотрим пример:

Var

N: Integer;

A: array[1..100] of Integer; // обычный массив

begin

Write('Введите количество элементов: ');

ReadLn(N);

...

end.

Задать размер массива A в зависимости от введенного пользователем значения невозможно, поскольку в качестве границ массива необходимо указать константные значения. А введенное пользователем значение никак не может претендовать на роль константы. Иными словами, следующее объявление будет ошибочным:

Var

N: Integer;

A: array[1..N] of Integer; // Ошибка!

begin

Write('Введите количество элементов: ');

ReadLn(N);

...

end.

На этапе написания программы невозможно предугадать, какие именно объемы данных захочет обрабатывать пользователь. Тем не менее, придется ответить на два важных вопроса:

  • На какое количество элементов объявить массив?

  • Что делать, если пользователю все-таки понадобится большее количество элементов?

Можно поступить следующим образом. В качестве верхней границы массива установить максимально возможное (?) количество элементов, а реально использовать только часть массива. Если пользователю потребуется большее количество элементов, чем зарезервировано, то ему можно попросту вежливо отказать. Например:

Const

MaxNumberOfElements = 100;

var

N: Integer;

A: array[1.. MaxNumberOfElements] of Integer;

begin

Write('Введите количество элементов (не более ', MaxNumberOfElements, '): ');

ReadLn(N);

if N > MaxNumberOfElements then

begin

Write('Извините, программа не может работать ');

Writeln('с количеством элементов больше , ' MaxNumberOfElements, '.');

end

else

begin

... // Инициализируем массив необходимыми значениями и обрабатываем его

end;

end.

Такое решение проблемы является неоптимальным. Если пользователю необходимо всего 10 элементов, программа работает без проблем, но всегда использует объем памяти, необходимый для хранения 100 элементов. Память, отведенная под остальные 90 элементов, не будет использоваться ни Вашей программой, ни другими. А теперь представьте, что все программы поступают таким же образом. Эффективность использования оперативной памяти резко снижается.

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

Динамический массив объявляется без указания границ:

array of baseType

Например:

var

DynArray: array of Integer;

Работа с динамическими массивами:

1. Переменная DynArray представляет собой ссылку на размещаемые в динамической памяти элементы массива.

2. Изначально память под массив не резервируется, количество элементов в массиве равно нулю, а значение переменной DynArray равно nil.

3. Создание динамического массива (выделение памяти для его элементов) осуществляется процедурой SetLength.

SetLength(DynArray, 50); // Выделить память для 50 элементов

4. Изменение размера динамического массива производится этой же процедурой:

SetLength(DynArray, 100); // Теперь размер массива 100 элементов

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

При уменьшении размера динамического массива лишние элементы теряютяся.

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

5. Определение количества элементов производится с помощью функции Length:

N := Length(DynArray); // N получит значение 100

6. Элементы динамического массива всегда индексируются от нуля.

7. Доступ к ним ничем не отличается от доступа к элементам обычных статических массивов:

DynArray[0] := 5; // Присвоить начальному элементу значение 5

DynArray[High(DynArray)] := 10; // присвоить конечному элементу значение 10

8. К динамическим массивам, как и к обычным массивам, применимы функции Low и High, возвращающие минимальный и максимальный индексы массива соответственно. Для динамических массивов функция Low всегда возвращает 0.

9. Освобождение памяти, выделенной для элементов динамического массива, осуществляется установкой длины в значение 0 или присваиванием переменной-массиву значения nil (оба варианта эквивалентны):

SetLength(DynArray, 0); // Эквивалентно: DynArray := nil;

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

10. При присваивании одного динамического массива другому, копия уже существующего массива не создается.

Var

A, B: array of Integer;

begin

SetLength(A, 100); // Выделить память для 100 элементов

A[0] := 5;

B := A; // A и B указывают на одну и ту же область памяти!

B[1] := 7; // Теперь A[1] тоже равно 7!

B[0] := 3; // Теперь A[0] равно 3, а не 5!

End.

В приведенном примере, в переменную B заносится адрес динамической области памяти, в которой хранятся элементы массива A (другими словами, ссылочной переменной B присваивается значение ссылочной переменной A).

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

var

A, B: array of Integer;

begin

SetLength(A, 100); // Выделить память для 100 элементов

A[0] := 10;

B := A; // B указывает на те же элементы, что и A

A := nil; // Память еще не освобождается, поскольку на нее указывает B

B[1] := 5; // Продолжаем работать с B, B[0] = 10, а B[1] = 5

B := nil; // Теперь ссылок на блок памяти нет. Память освобождается

End;

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

12. Для многомерных динамических массивов:

Var

A: array of array of Integer;

begin

SetLength(A, 100); // Выделить память для 100 элементов

for I := Low(A) to High(A) do

SetLength(A[I], I);

End.

То есть память выделяется для каждой размерности.