Инициализация агрегатных типов
Агрегатный тип — это тип структуры, объединения или массива. Если агрегатный тип содержит члены агрегатных типов, правила инициализации применяются рекурсивно.
Синтаксис
initializer
:
{
initializer-list
}
/* Для статистической инициализации */
{
initializer-list
, }
initializer-list
:
initializer
initializer-list
,
initializer
Список initializer-list
инициализаторов, разделенных запятыми. Каждый инициализатор в списке является константным выражением или списком инициализаторов. Поэтому списки инициализаторов могут быть вложенными. Эта форма полезна для инициализации агрегатных членов агрегатного типа, как показано в примерах этого раздела. Однако если инициализатор для автоматического идентификатора является одним выражением, оно не обязательно должно быть константным; достаточно, чтобы выражение имело соответствующий тип для назначения идентификатору.
В каждом списке инициализаторов значения константных выражений присваиваются соответствующим членам агрегатной переменной по порядку.
Если initializer-list
имеет меньше значений, чем агрегатный тип, остальные члены или элементы агрегатного типа инициализированы до 0. Начальное значение автоматического идентификатора, которое не инициализировано явно, не определено. Если initializer-list
имеется больше значений, чем агрегатный тип, результаты ошибки. Эти правила применяются к каждому встроенному списку инициализатора, а также к агрегату в целом.
Инициализатор структуры — это выражение одного типа или список инициализаторов для его членов, заключенных в фигурные скобки ({ }
). Неинициализированные элементы битового поля не инициализированы.
При инициализации объединения должен быть одним константным initializer-list
выражением. Значение константного выражения присваивается первому члену объединения.
Если размер массива неизвестен, количество инициализаторов определяет размер массива, а его тип становится полным. Невозможно указать повторение инициализатора в C или инициализировать элемент в середине массива без предоставления всех предыдущих значений. Если этот оператор требуется в программе, напишите подпрограмму на языке ассемблера.
Число инициализаторов может задать размер массива:
int x[ ] = { 0, 1, 2 }
Если указать размер и присвоить неверное количество инициализаторов, компилятор выдаст ошибку.
Блок, относящийся только к системам Майкрософт
Максимальный размер массива определяется size_t
.
Завершение блока, относящегося только к системам Майкрософт
Примеры
В следующем примере представлены инициализаторы массива.
int P[4][3] =
{
{ 1, 1, 1 },
{ 2, 2, 2 },
{ 3, 3, 3,},
{ 4, 4, 4,},
};
Эта инструкция объявляется P
как массив с четырьмя тремя и инициализирует элементы первой строки до 1, элементы второй строки до 2 и т. д. через четвертую строку. Список инициализатора для третих и четвертых строк содержит запятые после последнего выражения константы. За последним списком инициализаторов ({4, 4, 4,},
) также следует запятая. Эти дополнительные запятые разрешены, но не требуются. Требуются только запятые, которые отделяют выражения констант друг от друга, и запятые, разделяющие один список инициализаторов от другого.
Если у агрегатного элемента нет встроенного списка инициализатора, значения назначаются каждому элементу подагрегата. Поэтому инициализация в предыдущем примере эквивалентна следующему примеру:
int P[4][3] =
{
1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4
};
Фигурные скобки также могут отображаться вокруг отдельных инициализаторов в списке и помочь уточнить пример.
При инициализации агрегатной переменной фигурные скобки и списки инициализаторов следует использовать с осторожностью. В следующем примере подробно показано то, как компилятор интерпретирует фигурные скобки.
typedef struct
{
int n1, n2, n3;
} triplet;
triplet nlist[2][3] =
{
{ { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }, /* Row 1 */
{ { 10,11,12 }, { 13,14,15 }, { 16,17,18 } } /* Row 2 */
};
В этом примере параметр nlist
объявлен как массив структур, состоящий из двух строк и трех столбцов, где каждая структура имеет три члена. Строка 1 инициализации присваивает значения первой строке nlist
следующим образом.
Первая открывающая фигурная скобка в строке 1 сообщает компилятору, что начинается инициализация первого агрегатного члена
nlist
(то естьnlist[0]
).Вторая открывающая фигурная скобка указывает, что начинается инициализация первого агрегатного члена
nlist[0]
(то есть структурыnlist[0][0]
).Первая закрывающая фигурная скобка завершает инициализацию структуры
nlist[0][0]
. Следующая открывающая фигурная скобка начинает инициализациюnlist[0][1]
.Процесс будет продолжать до конца строки, где последняя закрывающая фигурная скобка завершит инициализацию
nlist[0]
.
Строка 2 присваивает значения второй строке nlist
аналогичным образом. Внешние наборы фигурных скобок, включающие инициализаторы на строки 1 и 2, требуются. В следующей конструкции внешние фигурные скобки отсутствуют, и это привело бы к ошибке.
triplet nlist[2][3] = /* THIS CAUSES AN ERROR */
{
{ 1, 2, 3 },{ 4, 5, 6 },{ 7, 8, 9 }, /* Line 1 */
{ 10,11,12 },{ 13,14,15 },{ 16,17,18 } /* Line 2 */
};
В этой конструкции первая открывающая фигурная скобка в строке 1 запускает инициализацию nlist[0]
, который является массивом из трех структур. Значения 1, 2 и 3 присваиваются трем членам первой структуры. При обнаружении следующей закрывающей фигурной скобки (после значения 3) инициализация nlist[0]
завершается, и две оставшиеся структуры в массиве из трех структур автоматически инициализируются значением 0. Аналогичным образом { 4,5,6 }
инициализирует первую структуру во второй строке nlist
. Оставшимся двум структурам nlist[1]
присваивается значение 0. Когда компилятор обнаруживает следующий список инициализаторов ({ 7,8,9 }
), он выполняет попытку инициализировать nlist[2]
. Поскольку nlist
имеет только две строки, эта попытка завершится с ошибкой.
В следующем примере три элемента x
с типом int
инициализируются значениями 1, 2 и 3 соответственно.
struct list
{
int i, j, k;
float m[2][3];
} x = {
1,
2,
3,
{4.0, 4.0, 4.0}
};
list
В структуре три элемента в первой строке m
инициализированы до 4,0; элементы оставшейся строки m
инициализируются до 0,0 по умолчанию.
union
{
char x[2][3];
int i, j, k;
} y = { {
{'1'},
{'4'}
}
};
В данном примере инициализируется переменная объединения y
. Первый элемент объединения — это массив, поэтому инициализатор является агрегатным инициализатором. Список инициализаторов {'1'}
присваивает значения первой строке массива. Поскольку только одно значение отображается в списке, элемент в первом столбце инициализируется символом 1
, а оставшиеся два элемента в строке инициализируются значением 0 по умолчанию. Аналогичным образом, первый элемент второй строки x
инициализируется символом 4
, а оставшиеся два элемента в строке инициализируются значением 0.