Array initialization
При инициализации объекта массива , инициализатор должен быть либо строковым литералом (опционально заключенным в фигурные скобки), либо списком в фигурных скобках с инициализаторами для элементов массива:
=
строковый-литерал
|
(1) | ||||||||
=
{
выражение
,
...
}
|
(2) | (до C99) | |||||||
=
{
дескриптор
(необязательно)
выражение
,
...
}
|
(2) | (с C99) | |||||||
=
{
}
|
(3) | (с C23) | |||||||
[
constant-expression
]
=
(начиная с C99)
Массивы известного размера и массивы неизвестного размера могут быть инициализированы , но не VLA (since C99) (until C23) . VLA может быть только пусто-инициализирован. (since C23)
Все элементы массива, которые не инициализированы явно, пусто-инициализированы .
Содержание |
Инициализация из строк
Строковый литерал (опционально заключенный в фигурные скобки) может использоваться в качестве инициализатора для массива соответствующего типа:
- обычные строковые литералы и UTF-8 строковые литералы (начиная с C11) могут инициализировать массивы любого символьного типа ( char , signed char , unsigned char )
- L-префиксные широкие строковые литералы могут использоваться для инициализации массивов любого типа, совместимого с (игнорируя cv-квалификаторы) wchar_t
|
(начиная с C11) |
Последовательные байты строкового литерала или широкие символы широкого строкового литерала, включая завершающий нулевой байт/символ, инициализируют элементы массива:
char str[] = "abc"; // str имеет тип char[4] и содержит 'a', 'b', 'c', '\0' wchar_t wstr[4] = L"猫"; // str имеет тип wchar_t[4] и содержит L'猫', '\0', '\0', '\0'
Если размер массива известен, он может быть на единицу меньше размера строкового литерала, и в этом случае завершающий нулевой символ игнорируется:
char str[3] = "abc"; // str имеет тип char[3] и содержит 'a', 'b', 'c'
Обратите внимание, что содержимое такого массива можно изменять, в отличие от прямого доступа к строковому литералу с помощью char * str = "abc" ; .
Инициализация списками в фигурных скобках
Когда массив инициализируется списком инициализаторов в фигурных скобках, первый инициализатор в списке инициализирует элемент массива с индексом ноль (если не указан дезигнатор) (since C99) , и каждый последующий инициализатор без дезигнатора (since C99) инициализирует элемент массива с индексом на единицу большим, чем инициализированный предыдущим инициализатором.
int x[] = {1,2,3}; // x имеет тип int[3] и содержит 1,2,3 int y[5] = {1,2,3}; // y имеет тип int[5] и содержит 1,2,3,0,0 int z[4] = {1}; // z имеет тип int[4] и содержит 1,0,0,0 int w[3] = {0}; // w имеет тип int[3] и содержит все нули
Это ошибка — предоставлять больше инициализаторов, чем элементов при инициализации массива известного размера (за исключением инициализации символьных массивов строковыми литералами).
|
Дескриптор приводит к тому, что следующий инициализатор инициализирует элемент массива, описанный дескриптором. Затем инициализация продолжается последовательно, начиная со следующего элемента после описанного дескриптором. int n[5] = {[4]=5,[0]=1,2,3,4}; // содержит 1,2,3,4,5 int a[MAX] = { // начинает инициализацию a[0] = 1, a[1] = 3, ... 1, 3, 5, 7, 9, [MAX-5] = 8, 6, 4, 2, 0 }; // для MAX=6, массив содержит 1,8,6,4,2,0 // для MAX=13, массив содержит 1,3,5,7,9,0,0,0,8,6,4,2,0 ("разреженный массив") |
(начиная с C99) |
При инициализации массива неизвестного размера, наибольший индекс, для которого указан инициализатор, определяет размер объявляемого массива.
Вложенные массивы
Если элементы массива являются массивами, структурами или объединениями, соответствующие инициализаторы в списке инициализаторов в фигурных скобках — это любые инициализаторы, допустимые для этих членов, за исключением того, что их фигурные скобки могут быть опущены следующим образом:
Если вложенный инициализатор начинается с открывающей фигурной скобки, весь вложенный инициализатор до его закрывающей скобки инициализирует соответствующий элемент массива:
int y[4][3] = { // массив из 4 массивов по 3 целых числа каждый (матрица 4x3) { 1 }, // строка 0 инициализирована как {1, 0, 0} { 0, 1 }, // строка 1 инициализирована как {0, 1, 0} { [2]=1 }, // строка 2 инициализирована как {0, 0, 1} }; // строка 3 инициализирована как {0, 0, 0}
Если вложенный инициализатор не начинается с открывающей фигурной скобки, из списка берётся только достаточное количество инициализаторов для элементов или членов подмассива, структуры или объединения; любые оставшиеся инициализаторы используются для инициализации следующего элемента массива:
int y[4][3] = { // массив из 4 массивов по 3 int каждый (матрица 4x3) 1, 3, 5, 2, 4, 6, 3, 5, 7 // строка 0 инициализирована как {1, 3, 5} }; // строка 1 инициализирована как {2, 4, 6} // строка 2 инициализирована как {3, 5, 7} // строка 3 инициализирована как {0, 0, 0} struct { int a[3], b; } w[] = { { 1 }, 2 }; // массив структур // { 1 } воспринимается как полностью заключенный в фигурные скобки инициализатор для элемента #0 массива // этот элемент инициализируется как { {1, 0, 0}, 0} // 2 воспринимается как первый инициализатор для элемента #1 массива // этот элемент инициализируется как { {2, 0, 0}, 0}
|
Обозначения массивов могут быть вложенными; заключенное в скобки константное выражение для вложенных массивов следует за заключенным в скобки константным выражением для внешнего массива: int y[4][3] = {[0][0]=1, [1][1]=1, [2][0]=1}; // строка 0 инициализирована как {1, 0, 0} // строка 1 инициализирована как {0, 1, 0} // строка 2 инициализирована как {1, 0, 0} // строка 3 инициализирована как {0, 0, 0} |
(начиная с C99) |
Примечания
Порядок вычисления подвыражений в инициализаторе массива является неопределённо упорядоченным в C (но не в C++, начиная с C++11):
int n = 1; int a[2] = {n++, n++}; // неопределённое, но корректное поведение, // n инкрементируется дважды (в произвольном порядке) // инициализация a значениями {1, 2} или {2, 1} допустима puts((char[4]){'0'+n} + n++); // неопределённое поведение: // инкремент и чтение из n не упорядочены
|
В языке C список в фигурных скобках инициализатора не может быть пустым. C++ допускает пустой список: |
(until C23) |
|
Пустой инициализатор может использоваться для инициализации массива: |
(since C23) |
int a[3] = {0}; // допустимый способ обнуления массива с блочной областью видимости в C и C++ int a[3] = {}; // допустимый способ обнуления массива с блочной областью видимости в C++; допустим в C начиная с C23
Как и во всех остальных случаях инициализации , каждое выражение в списке инициализации должно быть константным выражением при инициализации массивов со статической или thread-local длительностью хранения :
Пример
int main(void) { // Следующие четыре объявления массивов эквивалентны short q1[4][3][2] = { { 1 }, { 2, 3 }, { 4, 5, 6 } }; short q2[4][3][2] = {1, 0, 0, 0, 0, 0, 2, 3, 0, 0, 0, 0, 4, 5, 6}; short q3[4][3][2] = { { { 1 }, }, { { 2, 3 }, }, { { 4, 5 }, { 6 }, } }; short q4[4][3][2] = {1, [1]=2, 3, [2]=4, 5, 6}; // Имена символов могут быть связаны с константами перечисления // с использованием массивов с дескрипторами: enum { RED, GREEN, BLUE }; const char *nm[] = { [RED] = "red", [GREEN] = "green", [BLUE] = "blue", }; }
Ссылки
- Стандарт C17 (ISO/IEC 9899:2018):
-
- 6.7.9/12-39 Инициализация (стр. 101-105)
- Стандарт C11 (ISO/IEC 9899:2011):
-
- 6.7.9/12-38 Инициализация (стр. 140-144)
- Стандарт C99 (ISO/IEC 9899:1999):
-
- 6.7.8/12-38 Инициализация (стр. 126-130)
- Стандарт C89/C90 (ISO/IEC 9899:1990):
-
- 6.5.7 Инициализация