Инициализация массивов
При инициализации объекта типа массив, инициализатор должен быть либо строковой литерал (необязательно заключённой в фигурные скобки), либо список инициализаторов для элементов массива в фигурных скобках:
= строковая_литераль | (1) | |
= { выражение , ... } | (2) | (до C99) |
= { спецификатор(необязательно) выражение , ... } | (2) | (с C99) |
= { } | (3) | (с C23) |
[ константное_выражение ] = (с C99)
Массивы известного размера и массивы неизвестного размера могут быть инициализированы, но не ВЛА(с C99)(до C23). ВЛА может быть только пусто инициализирован.(с C23)
Все элементы массива, которые не инициализированы явно, пусто инициализируются.
Инициализация из строк
Строковая литерал (необязательно заключённая в фигурные скобки) может использоваться в качестве инициализатора для массива соответствующего типа:
- обычные строковые литералы и UTF-8 строковые литералы(с C11) могут инициализировать массивы любого типа символов (
char,signed char,unsigned char) - строковые литералы с префиксом L могут быть использованы для инициализации массивов любого совместимого типа (без учета квалификаторов cv)
wchar_t
| (с C11) |
Последовательные байты строковой литералы или широкие символы широкой строковой литералы, включая завершающий нулевой байт/символ, инициализируют элементы массива:
char str[] = "abc"; // str has type char[4] and holds 'a', 'b', 'c', '\0' wchar_t wstr[4] = L"猫"; // str has type wchar_t[4] and holds L'猫', '\0', '\0', '\0'
Если размер массива известен, он может быть на один меньше, чем размер строковой литералы, в этом случае завершающий нулевой символ игнорируется:
char str[3] = "abc"; // str has type char[3] and holds 'a', 'b', 'c'
Обратите внимание, что содержимое такого массива может быть изменено, в отличие от прямого доступа к строковой литерале с помощью char* str = "abc";.
Инициализация из списков в фигурных скобках
Когда массив инициализируется списком инициализаторов в фигурных скобках, первый инициализатор в списке инициализирует элемент массива с индексом ноль (если не указан спецификатор)(с C99), а каждый последующий инициализатор без спецификатора(с C99) инициализирует элемент массива с индексом на единицу больше, чем тот, который инициализировался предыдущим инициализатором.
int x[] = {1,2,3}; // x has type int[3] and holds 1,2,3
int y[5] = {1,2,3}; // y has type int[5] and holds 1,2,3,0,0
int z[4] = {1}; // z has type int[4] and holds 1,0,0,0
int w[3] = {0}; // w has type int[3] and holds all zeroesОшибка возникнет, если предоставлено больше инициализаторов, чем элементов при инициализации массива известного размера (за исключением инициализации массивов символов из строковых литералов).
| Спецификатор заставляет следующий инициализатор инициализировать элемент массива, описанный спецификатором. Инициализация затем продолжается в порядке, начиная с следующего элемента после описанного спецификатором. int n[5] = {[4]=5,[0]=1,2,3,4}; // holds 1,2,3,4,5
int a[MAX] = { // starts initializing a[0] = 1, a[1] = 3, ...
1, 3, 5, 7, 9, [MAX-5] = 8, 6, 4, 2, 0
};
// for MAX=6, array holds 1,8,6,4,2,0
// for MAX=13, array holds 1,3,5,7,9,0,0,0,8,6,4,2,0 ("sparse array") | (с C99) |
При инициализации массива неизвестного размера наибольший индекс, для которого указан инициализатор, определяет размер объявляемого массива.
Вложенные массивы
Если элементы массива являются массивами, структурами или объединениями, соответствующие инициализаторы в списке инициализаторов в фигурных скобках — это любые инициализаторы, которые допустимы для этих элементов, за исключением того, что их фигурные скобки могут быть опущены следующим образом:
Если вложенный инициализатор начинается с открывающей фигурной скобки, весь вложенный инициализатор до закрывающей фигурной скобки инициализирует соответствующий элемент массива:
int y[4][3] = { // array of 4 arrays of 3 ints each (4x3 matrix)
{ 1 }, // row 0 initialized to {1, 0, 0}
{ 0, 1 }, // row 1 initialized to {0, 1, 0}
{ [2]=1 }, // row 2 initialized to {0, 0, 1}
}; // row 3 initialized to {0, 0, 0}Если вложенный инициализатор не начинается с открывающей фигурной скобки, для учёта элементов или членов подмассива, структуры или объединения берётся только необходимое количество инициализаторов из списка; любые оставшиеся инициализаторы используются для инициализации следующего элемента массива:
int y[4][3] = { // array of 4 arrays of 3 ints each (4x3 matrix)
1, 3, 5, 2, 4, 6, 3, 5, 7 // row 0 initialized to {1, 3, 5}
}; // row 1 initialized to {2, 4, 6}
// row 2 initialized to {3, 5, 7}
// row 3 initialized to {0, 0, 0}
struct { int a[3], b; } w[] = { { 1 }, 2 }; // array of structs
// { 1 } is taken to be a fully-braced initializer for element #0 of the array
// that element is initialized to { {1, 0, 0}, 0}
// 2 is taken to be the first initialized for element #1 of the array
// that element is initialized { {2, 0, 0}, 0}| Вложенные массивы могут иметь спецификаторы; скобочное константное выражение для вложенных массивов следует за скобочным константным выражением для внешнего массива: int y[4][3] = {[0][0]=1, [1][1]=1, [2][0]=1}; // row 0 initialized to {1, 0, 0}
// row 1 initialized to {0, 1, 0}
// row 2 initialized to {1, 0, 0}
// row 3 initialized to {0, 0, 0} | (с C99) |
Примечания
Порядок вычисления подвыражений в инициализаторе массива не определён в C (но определён в C++ с C++11):
int n = 1;
int a[2] = {n++, n++}; // unspecified, but well-defined behavior,
// n is incremented twice (in arbitrary order)
// a initialized to {1, 2} and to {2, 1} are both valid
puts((char[4]){'0'+n} + n++); // undefined behavior:
// increment and read from n are unsequenced| В C список инициализаторов в фигурных скобках не может быть пустым. В C++ пустой список разрешен: | (до C23) |
| Пустой инициализатор может быть использован для инициализации массива: | (с C23) |
int a[3] = {0}; // valid C and C++ way to zero-out a block-scope array
int a[3] = {}; // valid C++ way to zero-out a block-scope array; valid in C since C23Как и при всех других инициализациях, каждое выражение в списке инициализаторов должно быть константным выражением при инициализации массивов статического или локального для потока срока хранения:
static char* p[2] = {malloc(1), malloc(2)}; // errorПример
int main(void)
{
// The following four array declarations are the same
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};
// Character names can be associated with enumeration constants
// using arrays with designators:
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 Инициализация
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/c/language/array_initialization