Инициализация массива 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 (и С++ с ним) был заперт в раннем выборе синтаксиса, и если вы хотите оставаться совместимым с устаревшим кодом, вероятно, не так много.