logo
volkov / C++ / Бьерн Страуструп-Справочное руководство по С++

R.8.2.4 Массивы

В описании T D, в котором D имеет вид

D1 [ выражение-константа opt ]

описывается идентификатор типа " ... массив T". Если

выражение-константа присутствует ($$R.5.19), то оно должно иметь

целочисленный тип и значение, большее 0. Это выражение задает число

элементов массива. Если значение выражения-константы есть N, то

массив имеет N элементов с индексами от 0 до N-1.

Массив можно образовывать из: одного из основных типов (за исключением

void), указателя, указателя на члены, класса, перечисления или из

другого массива.

Если подряд идут несколько спецификаций "массив ...", образуется

многомерный массив, причем выражение-константа, задающее границы

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

полезно в случае параметров функции типа массив, а также когда массив

является внешним, а его определение, с которым связано резервирование

памяти, находится в другом месте. Первое выражение-константа может

быть пропущено и в том случае, если за описателем следует

список-инициализаторов ($$R.8.4). Тогда размер массива определяется

числом элементов, приведенных в инициализаторе ($$R.8.4.1).

В описании

float fa[17], *afp[17];

описаны массив чисел типа float и массив указателей на числа типа float,

а в описании

static int x3d[3][5][7];

описан статический трехмерный массив целых размера 3x5x7. Строго

говоря, x3d является массивом из трех элементов, каждый из которых

есть массив из пяти массивов, а каждый из последних является массивом

из семи целых. В выражении допустимо появление любого из следующих

выражений: x3d, x3d[i], x3d[i][j], x3d[i][j][k].

Если в выражении участвует идентификатор типа массив, то, исключая

случаи операнда в операциях sizeof или & и инициализатора для

ссылки ($$R.8.4.3), его тип преобразуется в указатель на первый

элемент массива. Несмотря на это преобразование, массивы не являются

изменяемыми адресами. Если не считать случай использования массива

при описании класса ($$R.13.4.5), операция индексации определяется

так, что E1[E2] совпадает с *((E1) + (E2)). С учетом правил

преобразования типов для операции +, если E1 есть массив, а E2

целое, то E1[E2] указывает на E2-элемент из E1. Поэтому, несмотря

на свой асиметричный вид, индексация - коммутативная операция.

Аналогичное правило действует и для многомерных массивов. Если

E - n-мерный массив размера ixjx...xk, то в выражении он

преобразуется в указатель на (n-1)-мерный массив размера jx...xk.

Если к этому указателю явно или неявно в результате индексации применяется

операция *, указуемый (n-1)-мерный массив сам немедленно преобразуется

в указатель.

Например, рассмотрим описание

int x[3][5];

Здесь описан массив из 3x5 целых. Если в выражении появляется x, то

оно преобразуется в указатель на первый массив из пяти целых.

Если в выражении появляется x[i], что эквивалентно *(x+i), в начале

x преобразуется в указатель, как было сказано выше, затем x+i

преобразуется к типу x, для чего необходимо i умножить на размер объекта,

на который указывает x, т.е. на размер пяти целых. Затем происходит

сложение и применяется косвенность, после чего получим массив (из пяти

целых), который в свою очередь преобразуется в указатель на первое из

целых. Если есть еще одна индексация, процесс повторяется, и на этот раз

мы получим в результате целое.

Из всего этого следует, что массивы В С++ хранятся по строкам

(последний индекс изменяется быстрее всего), а значение первого

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

для массива, однако при вычислении индексного выражения первый индекс

роли не играет.