Выбрать главу

Например, в следующем фрагменте

struct S {int a; char* b; int c;}

S ss = {1, "asdf"};

ss.a инициализируется значением 1, ss.b - "asdf", а ss.c - 0.

Кроме того, агрегат, являющийся классом, можно инициализировать объектом этого класса или класса, являющегося общим производным от него (§R.12.8).

Фигурные скобки разбираются следующим образом. Если список-инициализаторов начинается левой фигурной скобкой, то список инициализаторов, разделенных запятыми, задает значения членам агрегата, причем считается ошибкой, если инициализаторов больше, чем членов. Иначе, если список-инициализаторов или вложенный агрегат не начинается левой фигурной скобкой, то из списка используется такое число элементов, которое нужно для инициализации членов текущего агрегата; все оставшиеся элементы используются для инициализации членов следующего агрегата, в который вложен текущий агрегат.

Например, в определении

int x[] = {1, 3, 5};

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

Приведем пример инициализации с полной скобочной структурой.

float y[4][3] = {

 {1, 3, 5},

 {2, 4, 6},

 {3, 5, 7},

};

Здесь значения 1, 3, 5 инициализируют первую строку массива y[0], т.е. y[0][0], y[0][1] и y[0][2]. Аналогично, следующие две строки инициализируют y[1] и y[2]. Инициализаторы приведены не полностью, поэтому y[3] инициализируется нулями. Точно такого же результата можно достичь с помощью такой инициализации:

float y[4][3] = {

 1, 3, 5, 2, 4, 6, 3, 5, 7,

};

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

В последнем примере инициализатор для y начинается левой фигурной скобкой, но для y[0] скобки не задано, поэтому из списка используется три элемента, также по три последовательных элемента используется для y[1] и y[2]. В следующем примере

float y[4][3] = {

 {1}, {2}, {3}, {4}

};

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

Инициализация массива объектов типа класс с помощью конструкторов описывается в §R.12.6.1.

Инициализатор для объединения без конструктора должен быть или отдельным выражением типа объединения, или заключенным в фигурные скобки, инициализатором первого члена объединения, например,

union u {i nt a; char* b; };

u a = {1};

u b = a;

u c = 1; // ошибка

u d = {0, "asdf"}; // ошибка

u e = {"asdf"}; // ошибка

Число инициализаторов не должно превышать числа членов или элементов, которые инициализируются. Например, следующая инициализация ошибочна:

char cv[4] = {'a', 's', 'd', 'f', 0}; // ошибка

R.8.4.2 Символьные массивы

Массив символов (неважно, знаковых или беззнаковых) можно инициализировать строкой-литералом: символы строки последовательно инициализируют элементы массива. Следующее определение дает пример символьного массива, элементы которого инициализируются строкой:

char msg[] = "Syntax error on line %s\n";

Заметим, что поскольку '\n' задает один символ, и поскольку добавляется завершающий символ '\0', sizeof(msg) равно 25.

Нельзя задавать больше инициализаторов, чем есть элементов в массиве, поэтому следующий пример ошибочен: здесь нет места для подразумевающегося символа конца строки ('\0'):

char cv[4] = "asdf"; // ошибка

R.8.4.3 Ссылки

Переменная, описанная как T&, т.е. "ссылка на тип T" (§R.8.2.2), должна инициализироваться объектом типа T или объектом, который можно преобразовать к типу T, например,

void f()

{

 int i;

 int& r = i; // `r' ссылается на `i'

 r = 1; // `i' принимает значение 1

 int* p = &r; // `p' указывает на `i'

 int& rr = r; // `rr' ссылается на то, на что ссылалось `r',

  // т.е. на `i'

};

Ссылку после инициализации нельзя изменять так, чтобы она обозначала другой объект. Отметим, что инициализация ссылки трактуется совсем не так, как присваивание ссылке. Передача параметра (§R.5.2.2) и операция возврата значения функции (§R.6.6.3) считаются инициализацией.

Инициализатор для ссылки можно опускать только в описании параметра (§R.8.2.5), в описании возвращаемого функцией типа, в описании члена класса при описании самого класса (§R.9.2) и там, где явно использована спецификация extern, например,

int& r1; // ошибка: нет инициализации

extern int& r2; // нормально