Инициализация массива C во время, отличное от объявления?
Я знаю в C, что могу сделать следующее.
int test[5] = {1, 2, 3, 4, 5};
Теперь это разрешено только при объявлении массива. Однако мне было интересно, почему это не законно делать позже? Но потом в программе не законно делать следующее.
test[5] = {10, 20, 30, 40, 50};
Или что-то подобное. Почему это? Я знаю, что это не законно, и я не жалуюсь, но может ли кто-нибудь дать мне более техническое объяснение, почему я не могу этого сделать? (т.е. не просто сказать, что C spec не позволяет это или что-то в этом роде)
Я предполагаю, что он должен что-то делать со временем, когда память распределяется в стеке для массива, поэтому в этот момент C может автоматически заполнить мои значения, но тогда почему это не может быть сделано позже?
Спасибо, ребята,
Ответы
Ответ 1
Это не просто массивы, вы не можете предоставить инициализатор для чего-либо в любой точке, кроме определения. Люди иногда ссылаются на второе утверждение чего-то типа int i; i = 0;
как "инициализация i
". Фактически он присваивает i
, который ранее имел неопределенное значение, потому что он не был инициализирован. Это очень редко сбивает с толку на эту "инициализацию", но, если речь идет о языке, там нет инициализатора.
Назначение и инициализация - это отдельные вещи для языка, хотя оба они используют символ =
. Массивы не могут быть назначены.
Массивы причин не назначаются, как это описано в другом месте, например Почему С++ поддерживает поэтапное назначение массивов внутри структур, но не в целом?. Короткий ответ - "исторические причины". Я не думаю, что есть какая-либо причина убийства, почему язык не может быть изменен для разрешения массива.
Есть вторичная проблема, что грамматически {1, 2, 3, 4, 5}
является инициализатором, а не литералом массива и, следовательно, не может использоваться в присваивании, даже если массивы были назначены. Я не уверен, почему именно C89 не имеет литералов массива, вероятно, только никто не стал их требовать. C99 представляет синтаксис для "составных литералов" в целом и литералов массива, в частности: (int[]) {1, 2, 3, 4, 5}
. Вы по-прежнему не можете назначить массив из него.
Ответ 2
Дело в том, что использование int array[]={ }
объявляет и инициализирует созданный объект.
Фактически вы можете присваивать значения массиву после его объявления:
int array[5];
array[0] = 1, array[1] = 2, ...
То, что вы делали, это присвоение нескольких значений одной записи массива:
array[5] = {1,2,3,4,5}; // array[5] can only contain one value
Вместо этого это будет законным:
array[5] = 6;
Надеюсь, это имеет смысл. Просто вопрос синтаксиса.
Ответ 3
Обратите внимание, что листинг C99-соединения позволяет вам передавать массивы в функции:
int your_func(int *test)
{
...use test as an array...
}
void other_func(void)
{
int x = rand();
if (your_func((int[]){ 0, 1, 2, x, 3, 4 }) > 0 ||
your_func((int[]){ 9, x, 8, 7, 6, 5 }) > 0)
...whatever...
}
Это не то же самое, что повторная инициализация массива с разными значениями, но он может быть достаточно близок к тому, что он работает для вас.
Ответ 4
Здесь Решение
//Declaration
int a[5];
int a_temp[5] = {1, 2, 3, 4, 5 };
memcpy(a, a_temp, sizeof(a));
//Now array a have values 1, 2, 3, 4, 5
Ответ 5
Причиной этого на поверхности является то, что массивы почти везде преобразуются в указатель на первый элемент. Если у вас есть два массива
double A[5];
double B[5];
в выражении, таком как
A = B;
оба уже конвертированы в указатели. A
слева, в частности, не является "lvalue", поэтому вы не можете назначить ему.
Это звучит как хромовое оправдание, но я предполагаю, что исторически это произошло именно так. C (и С++ с ним) был заперт в раннем выборе синтаксиса, и если вы хотите оставаться совместимым с устаревшим кодом, вероятно, не так много.