C Language
инициализация
Поиск…
Инициализация переменных в C
При отсутствии явной инициализации внешние и static
переменные гарантированно инициализируются до нуля; автоматические переменные (включая register
переменные) имеют неопределенные начальные значения 1 (т. е. мусор).
Скалярные переменные могут быть инициализированы, когда они определены, следуя имени с знаком равенства и выражением:
int x = 1;
char squota = '\'';
long day = 1000L * 60L * 60L * 24L; /* milliseconds/day */
Для внешних и static
переменных инициализатор должен быть константным выражением 2 ; инициализация выполняется один раз, концептуально до начала выполнения программы.
Для автоматических и register
переменных инициализатор не ограничивается константой: это может быть любое выражение, включающее ранее определенные значения, даже вызовы функций.
Например, см. Фрагмент кода ниже
int binsearch(int x, int v[], int n)
{
int low = 0;
int high = n - 1;
int mid;
...
}
вместо
int low, high, mid;
low = 0;
high = n - 1;
По сути, инициализация автоматических переменных является просто сокращением для операторов присваивания. Какая форма предпочтительнее во многом зависит от вкуса. Обычно мы используем явные присваивания, потому что инициализаторы в объявлениях сложнее видеть и удаляться от точки использования. С другой стороны, переменные должны быть объявлены только тогда, когда они будут использоваться, когда это возможно.
Инициализация массива:
Массив может быть инициализирован, следуя его объявлению с помощью списка инициализаторов, заключенных в фигурные скобки и разделенных запятыми.
Например, чтобы инициализировать дни массива с количеством дней в каждом месяце:
int days_of_month[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
(Обратите внимание, что январь в этой структуре закодирован как нулевой месяц.)
Когда размер массива опущен, компилятор будет вычислять длину, подсчитывая инициализаторы, из которых в этом случае 12.
Если для массива меньше инициализаторов, чем указанный размер, остальные будут равны нулю для всех типов переменных.
Ошибка слишком много инициализаторов. Нет стандартного способа указать повторение инициализатора, но GCC имеет расширение для этого.
В C89 / C90 или более ранних версиях C не было возможности инициализировать элемент в середине массива без предоставления всех предыдущих значений.
С C99 и выше назначенные инициализаторы позволяют инициализировать произвольные элементы массива, оставляя любые неинициализированные значения нулями.
Инициализация массивов символов:
Массивы символов - это особый случай инициализации; вместо привязок и запятой можно использовать строку:
char chr_array[] = "hello";
является сокращением длинного, но эквивалентного:
char chr_array[] = { 'h', 'e', 'l', 'l', 'o', '\0' };
В этом случае размер массива составляет шесть (пять символов плюс завершающий '\0'
).
1 Что происходит с объявленной, неинициализированной переменной в C? Имеет ли это значение?
2 Обратите внимание, что константное выражение определяется как то, что может быть оценено во время компиляции. Итак, int global_var = f();
является недействительным. Другое распространенное заблуждение думает о const
квалифицированного переменных в качестве постоянного выражения. В C, const
означает «только для чтения», а не «время компиляции постоянная». Итак, глобальные определения, такие как const int SIZE = 10; int global_arr[SIZE];
и const int SIZE = 10; int global_var = SIZE;
не являются законными в C.
Инициализация структур и массивов структур
Структуры и массивы структур могут быть инициализированы рядом значений, заключенных в фигурные скобки, по одному значению на члена структуры.
struct Date
{
int year;
int month;
int day;
};
struct Date us_independence_day = { 1776, 7, 4 };
struct Date uk_battles[] =
{
{ 1066, 10, 14 }, // Battle of Hastings
{ 1815, 6, 18 }, // Battle of Waterloo
{ 1805, 10, 21 }, // Battle of Trafalgar
};
Обратите внимание, что инициализация массива может быть записана без внутренних фигурных скобок, а в прошлом (до 1990 года, скажем, часто) было бы написано без них:
struct Date uk_battles[] =
{
1066, 10, 14, // Battle of Hastings
1815, 6, 18, // Battle of Waterloo
1805, 10, 21, // Battle of Trafalgar
};
Хотя это работает, это не очень хороший современный стиль - вы не должны пытаться использовать эту нотацию в новом коде и должны исправлять предупреждения компилятора, которые он обычно дает.
См. Также назначенные инициализаторы .
Использование назначенных инициализаторов
В C99 была введена концепция назначенных инициализаторов. Они позволяют указать, какие элементы массива, структуры или объединения должны быть инициализированы следующими значениями.
Обозначенные инициализаторы для элементов массива
Для простого типа, такого как обычный int
:
int array[] = { [4] = 29, [5] = 31, [17] = 101, [18] = 103, [19] = 107, [20] = 109 };
Термин в квадратных скобках, который может быть любым константным целочисленным выражением, указывает, какой элемент массива должен быть инициализирован значением члена после знака =
. Необычные элементы инициализируются по умолчанию, что означает, что определены нули. В этом примере показаны назначенные инициализаторы по порядку; они не должны быть в порядке. В примере показаны пробелы; они являются законными. В примере не показаны две разные инициализации для одного и того же элемента; что также допускается (ИСО / МЭК 9899: 2011, §6.7.9 Инициализация, ¶19 Инициализация должна выполняться в порядке списка инициализаторов, причем каждый инициализатор предоставил конкретный подобъект, переопределяющий любой ранее указанный инициализатор для того же подобъекта ).
В этом примере размер массива не определен явно, поэтому максимальный индекс, указанный в назначенных инициализаторах, определяет размер массива - который будет 21 элементом в примере. Если размер был определен, инициализация записи за пределами конца массива была бы ошибкой, как обычно.
Назначенные инициализаторы для структур
Вы можете указать, какие элементы структуры инициализируются с помощью .
обозначение element
:
struct Date
{
int year;
int month;
int day;
};
struct Date us_independence_day = { .day = 4, .month = 7, .year = 1776 };
Если элементы не указаны, они по умолчанию инициализируются (обнуляются).
Назначенный инициализатор для объединений
Вы можете указать, какой элемент объединения инициализируется назначенным инициализатором.
До стандарта C не было возможности инициализировать union
. Стандарт C89 / C90 позволяет вам инициализировать первый член union
- поэтому выбор, который перечисляется в списке, имеет первостепенное значение.
struct discriminated_union
{
enum { DU_INT, DU_DOUBLE } discriminant;
union
{
int du_int;
double du_double;
} du;
};
struct discriminated_union du1 = { .discriminant = DU_INT, .du = { .du_int = 1 } };
struct discriminated_union du2 = { .discriminant = DU_DOUBLE, .du = { .du_double = 3.14159 } };
Обратите внимание, что C11 позволяет использовать анонимные члены объединения внутри структуры, так что вам не нужно имя du
в предыдущем примере:
struct discriminated_union
{
enum { DU_INT, DU_DOUBLE } discriminant;
union
{
int du_int;
double du_double;
};
};
struct discriminated_union du1 = { .discriminant = DU_INT, .du_int = 1 };
struct discriminated_union du2 = { .discriminant = DU_DOUBLE, .du_double = 3.14159 };
Назначенные инициализаторы для массивов структур и т. Д.
Эти конструкции могут быть объединены для массивов структур, содержащих элементы, которые являются массивами и т. Д. Использование полных наборов фигурных скобок гарантирует, что обозначение однозначно.
typedef struct Date Date; // See earlier in this example
struct date_range
{
Date dr_from;
Date dr_to;
char dr_what[80];
};
struct date_range ranges[] =
{
[3] = { .dr_from = { .year = 1066, .month = 10, .day = 14 },
.dr_to = { .year = 1066, .month = 12, .day = 25 },
.dr_what = "Battle of Hastings to Coronation of William the Conqueror",
},
[2] = { .dr_from = { .month = 7, .day = 4, .year = 1776 },
.dr_to = { .month = 5, .day = 14, .year = 1787 },
.dr_what = "US Declaration of Independence to Constitutional Convention",
}
};
Определение диапазонов в инициализаторах массива
GCC предоставляет расширение , позволяющее указать диапазон элементов в массиве, которому должен быть присвоен одинаковый инициализатор:
int array[] = { [3 ... 7] = 29, 19 = 107 };
Тройные точки должны быть отделены от чисел, чтобы одна из точек не интерпретировалась как часть числа с плавающей запятой ( максимальное правило munch ).