7.1. Массивы (Array) и работа с ними

We use cookies. Read the Privacy and Cookie Policy

Массив — это регулярная структура данных, объявляемая специальной конструкцией языка

Array [ диапазоны индексов ] of ТипКомпонентов

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

VAR

V : Array [ 1..3 ] of Real;

объявляя тем самым структуру из трех значений типа Real, проиндексированных заданным диапазоном целых чисел (V[1], V[2] и V[3]). Если индексация компонентов (элементов) массива задается числовым диапазоном, как в приведенном примере, то надо соблюдать лишь два требования: во-первых, диапазон не должен принадлежать типу LongInt, т.е. он обязан «уместиться» максимум в типе Word, a во-вторых, произведение количества компонентов массива, задаваемого диапазоном индексов, на размер компонента в байтах, не может превышать 65520 байт (почти 64K). Последнее требование является общим не только для всех массивов, но и для прочих структур данных. Таким образом, могут быть описаны массивы

- 133 -

Array [9..99] of Char; { массив из 91 элемента }

Array [-10.. 10] of LongInt; { массив из 21 элемента }

Это очень удобно, так как позволяет не заботиться о приведении индексов к диапазону 1..N, как, например, приходится поступать при работе с Фортраном или некоторыми версиями Бейсика.

В общем случае ничто не обязывает объявлять диапазон индексов массива числами. В качестве индексов можно использовать любые перечислимые типы, как встроенные, так и вводимые. Индексы могут задаваться по-прежнему диапазоном, а если диапазон соответствует всему типу, то можно вместо него просто записать имя этого перечислимого типа:

TYPE

Monthtype = ( January, February, March, April, May );

ComplectType = Array [ MonthType ] of Word;

SpringType = Array [ March..May ] of Word;

VAR

Complect : ComplectType; { пять элементов типа Word }

Spring : SpringType; { три элемента типа Word }

Alpha : Array [ 'A'..'z'] of Char;

Switch : Array [Boolean] of Byte; { два элемента }

Элементы массивов будут индексироваться значениями заданных перечислимых типов или их диапазонов: Complect [January] — первый, a Spring[May] — последний элементы в своих массивах; аналогичен смысл обращений Alpha [ 'А' ] и Switch [True].

Рассмотренные массивы — одномерные, т.е. такие, у которых компоненты — скаляры. Разрешено объявлять массивы массивов:

TYPE

VectorType = Array [ 1..3 ] of Real; { вектор }

MatrixType = Array [ 1..10] of VectorType; { матрица10x3 }

Описание типа двумерного массива MatrixType могло быть записано по-другому:

TYPE

MatrixType = Array [ 1..10] of Array [ 1..3 ] of Real;

или как

MatrixType = Array [ 1..10, 1..3 ] of Real;

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

- 134 -

Каждое измерение совершенно не зависит от остальных, и можно объявлять массивы с разными индексами:

VAR

M : Array [ -10..0, 'A'..'C', Boolean ] of Byte;

Эквивалентная запись:

M : Array [-10..0] of

Array [ 'A'..'C' ] of

Array [Boolean] of Byte;

Интересно, что тип элемента массива M зависит от числа указанных при нем индексов. Так,

M[0] — массив-матрица типа Array['A'..'C',Boolean] of Byte,

М[0, 'B'] — вектор типа Array[Boolean] of Byte,

M[0, 'B', False] — значение типа Byte.

Если будут использоваться различные уровни «детализации» многомерных массивов, то надо будет позаботиться о совместимости по типу. Так, при приведенном выше описании массива M нельзя реально поставить подмассив M[0] в оператор присваивания, так как это не по правилам совместимости. Надо переписать объявление типа примерно так:

TYPE

ArrayBType = Array[Boolean] of Byte;

ArrayCType = Array ['A'..'C' ] of ArrayBType;

ArrayMType = Array [-10..0] of ArrayCType;

VAR

B : ArrayBType;

C : ArrayCType;

M : ArrayMType;

и лишь после этого будут разрешены присваивания вида

M[ -1 ] := C;

B := M[ -1, 'A' ];

Подобные вопросы совместимости можно обойти, используя приведение типов, а также специальную процедуру Move Турбо Паскаля, но это будет не повышением эффективности программы, а скорее свидетельством непродуманного объявления типов в ней.

Турбо Паскаль позволяет записывать индексы не через запятую, а как бы изолировано:

M[ -3, 'B', True ] эквивалентно M[ -3 ][ 'B' ][ True ]

- 135 -

Компонентом массива может быть не только другой массив, но и запись, и указатель, и какой-либо другой тип. Если R — массив записей (RECORD), то доступ к полю каждой записи производится после указания индекса:

R[ i ].ПолеЗаписи

В памяти ПЭВМ массивы хранятся как сплошные последовательности компонентов, причем быстрее всего изменяется самый «дальний» индекс, если их несколько. В примере задания стартового значения многомерному массиву (см. разд. 5.2.2) порядок перечисления элементов (без учета скобок) соответствует порядку размещения значений в памяти. Адрес начала массива в памяти соответствует адресу его первого элемента (элемента с минимальными значениями индексов).

Турбо Паскаль имеет специальный режим компиляции, задаваемый ключом $R. Если вся программа или фрагмент ее компилировался в режиме {$R+}, то при обращении к элементам массивов будет проверяться принадлежность значения индекса объявленному диапазону, и в случае нарушения границ диапазона программа прервется с выдачей ошибки 201 (Range check Error). Напротив, в режиме {$R-} никаких проверок не производится, и некорректное значение индекса извлечет «как ни в чем не бывало» какое-нибудь значение — но, увы, не принадлежащее данному массиву. Обычно программу отлаживают в режимах $R+, а эксплуатируют при режиме $R-. Это несколько уменьшает размер ЕХЕ-файла и время его выполнения.

К двум совместимым массивам A и B применима только операция присваивания:

A := B;

которая копирует поэлементно массив B в массив A.

Всевозможные математические действия над массивами (матрицами) необходимо реализовывать самим или использовать специальные библиотеки (например, Turbo Numeric Toolbox).

Для совместимости с другими версиями Паскаля Турбо Паскаль допускает использование составных символов (. и .) вместо квадратных скобок:

M[ 0 ] эквивалентно M(. 0 .)

Кроме того, ключевое слово Array в описаниях массивов может предваряться зарезервированным словом PACKED (упакованный, сжатый):

- 136 -

VAR

X : PACKED Array [ 1..100 ] of Real;

В Турбо Паскале данные и так хранятся максимально плотно, и слово PACKED практически игнорируется. Мы рекомендуем избегать его включения в тексты программ.

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