11 Declarators [dcl.decl]

11.3 Meaning of declarators [dcl.meaning]

11.3.4 Arrays [dcl.array]

В декларации, T D где D есть форма

D1 [ constant-expressionopt ] attribute-specifier-seqopt

и тип идентификатора в объявлении T D1 - «derived-declarator-type-list T», тогда тип идентификатора D является типом массива; если тип идентификатора D содержит , значит, программа сформирована неправильно. называется массивом ; этот тип не должен быть ссылочным типом , типом функции или типом абстрактного класса. Если присутствует, это должно быть преобразованное постоянное выражение типа, и его значение должно быть больше нуля. Постоянное выражение определяет из (количество элементов в) массива. Если значение константного выражения равно , массив имеет элементы, пронумерованные до , а тип идентификатора - « массив из ». Объект типа массив содержит непрерывно выделенный непустой набор подобъектов типа . За исключением случаев, указанных ниже, если постоянное выражение опущено, тип идентификатора - « массив с неизвестной границей », неполный тип объекта. Тип « массив » отличается от типа « массив с неизвестной границей », см . Любой тип формы « массив » настраивается на «массив » и аналогично для «массив неизвестной границы ». Необязательный элемент принадлежит массиву. [ auto type-specifierTelement type cv voidconstant-expression std​::​size_­t boundNN0N-1Dderived-declarator-type-list N TNTDderived-declarator-type-list Tderived-declarator-type-list N Tderived-declarator-type-list T [basic.types]cv-qualifier-seqN TN cv-qualifier-seq TTattribute-specifier-seqExample:

typedef int A[5], AA[2][3];
typedef const A CA;             // type is “array of 5 const inttypedef const AA CAA;           // type is “array of 2 array of 3 const int

end example] [ Note: «Массив » имеет тип с квалификацией cv; см . ]N cv-qualifier-seq T [basic.type.qualifier]end note

Массив может быть построен из одного из основных типов (кроме void), из указателя, из указателя на член, из класса, из типа перечисления или из другого массива.

Когда несколько «массивов» спецификаций являются смежными, создается многомерный массив; может быть опущено только первое из константных выражений, определяющих границы массивов. В дополнение к объявлениям, в которых разрешен неполный тип объекта, в некоторых случаях при объявлении параметра функции ([dcl.fct]) может быть опущена граница массива . Связь с массивом также может быть опущена, если за декларатором следует initializerили когда за декларатором для статического члена данных следует brace-or-equal-initializer([class.mem]). В обоих случаях граница вычисляется из числа исходных элементов (скажем, N) предоставленных ([dcl.init.aggr]), а тип идентификатора D - «массив N T». Кроме того, если есть предыдущее объявление объекта в той же области, в которой была указана привязка, пропущенная граница массива считается такой же, как в этом более раннем объявлении, и аналогично для определения статического члена данных объекта класс.

[Example:

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

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

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

объявляет статический трехмерный массив целых чисел с рангом 3×5×7. В полной мере, x3d это массив из трех элементов; каждый элемент представляет собой массив из пяти массивов; каждый из последних массивов представляет собой массив из семи целых чисел. Любое из выражений x3d, x3d[i], x3d[i][j], x3d[i][j][k] может разумно появиться в выражении. Наконец-то,

extern int x[10];
struct S {
  static int y[10];
};

int x[];                // OK: bound is 10
int S::y[];             // OK: bound is 10

void f() {
  extern int x[];
  int i = sizeof(x);    // error: incomplete object type
}

end example]

[ Note: Преобразования, влияющие на выражения типа массива, описаны в [conv.array]. Объекты типов массивов не могут быть изменены, см [basic.lval]. ]end note

[ Note: За исключением случаев, когда он был объявлен для класса ([over.sub]), оператор нижнего индекса [] интерпретируется таким же образом, что E1[E2] и *((E1)+(E2)) ([expr.sub]). Из-за правил преобразования, которые применяются к +, if E1 является массивом и E2 целым числом, то E1[E2] относится к E2-ому члену E1. Таким образом, несмотря на асимметричный вид, индексирование является коммутативной операцией. ]end note

[ Note: Для многомерных массивов соблюдается единое правило . Если E является n-мерным массивом ранга i×j××k, то, E появляющееся в выражении, которое подлежит array-to-pointer conversion , преобразуется в указатель на (n1)-мерный массив с рангом j××k. Если * оператор, явно или неявно в результате индексации, применяется к этому указателю, результатом является указанный на (n1)размерный массив, который сам немедленно преобразуется в указатель. [ Example: Учтите

int x[3][5];

Вот x это 3×5 массив целых чисел. Когда x появляется в выражении, оно преобразуется в указатель на (первый из трех) пятичленный массив целых чисел. В выражении, x[i] которое эквивалентно *(x+i), x сначала преобразуется в указатель, как описано; then x+i преобразуется в тип x, который включает умножение i на длину объекта, на который указывает указатель, а именно пяти целочисленных объектов. Результаты складываются, и косвенное обращение применяется для получения массива (из пяти целых чисел), который, в свою очередь, преобразуется в указатель на первое из целых чисел. Если есть другой нижний индекс, тот же аргумент применяется снова; на этот раз результат - целое число. ] ]end exampleend note

[ Note: Из всего этого следует, что массивы в C ++ хранятся построчно (последний индекс изменяется быстрее всего) и что первый индекс в объявлении помогает определить объем памяти, потребляемой массивом, но не играет никакой другой роли в вычислениях индекса. ]end note