Помилка компіляції C: "Об'єкт змінного розміру не може бути ініціалізований"


97

Чому я отримую помилку "Об'єкт змінного розміру не може бути ініціалізований" із наступним кодом?

int boardAux[length][length] = {{0}};

Як зазначається у чудовій відповіді Девіда Родрігеса: якщо довжина є змінною, вам потрібна пам’ятка, але якщо довжина - константа часу компіляції, то виписка складається просто чудово.
Кейсі

ffwd до 2020 -enum {length = 0xF } ; int boardAux[length][length] = {0};
Chef Gladiator

Відповіді:


121

Я припускаю, що ви використовуєте компілятор C99 (з підтримкою масивів динамічного розміру). Проблема у вашому коді полягає в тому, що в той момент, коли компілятори бачать вашу змінну декларацію, вона не може знати, скільки елементів є в масиві (я також припускаю тут, з помилки компілятора, яка lengthне є постійною часом компіляції).

Ви повинні вручну ініціалізувати цей масив:

int boardAux[length][length];
memset( boardAux, 0, length*length*sizeof(int) );

Я можу використовувати для цієї мети також malloc, що стосується другого питання, я написав його після відповіді Павла
helloWorld

@helloWorld: зі стеком, виділеним масивами, printf( "%d", boardAux[1][2] )складено штраф. Компілятор знає розміри і знає, в якому положенні в пам'яті знаходиться (1,2) -й елемент. Якщо ви використовуєте динамічне розподілення, масив є одновимірним, і ви повинні виконати математику самостійно:printf("%d", boardAux[ 1*length + 2 ])
Девід Родрігес - дрибеа

@AndreyT: Дякую за вказівку на помилку у memsetвиклику. Я щойно це виправив.
Девід Родрігес - дрибес

Чому я отримую цю помилку в компіляторі C99, коли я встановив, що lengthбуде static? У C ++ 14 це чудово працює.
Мухаммед Цічак

25

Ви отримуєте цю помилку, оскільки мовою C ви не можете використовувати ініціалізатори з масивами змінної довжини. Повідомлення про помилку, яке ви отримуєте, в основному каже все це.

6.7.8 Ініціалізація

...

3 Тип об'єкта, який ініціалізується, повинен бути масивом невідомого розміру або типом об'єкта, який не є масивом змінної довжини.


де ви це знайшли, чи можете ви мені надати посилання?
helloWorld

1
@helloWorld: Це з мовного стандарту (C99). Ви можете отримати «робочу» копія з ТС3 оновлює тут open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf
ANT

5
Є теми, щодо яких деякі завжди вам невірять, якщо ви лише надасте неформальне пояснення. Масиви змінної довжини - одна з цих тем. +1 для цитування стандарту.
Паскаль Куок

15

Це дає помилку:

int len;
scanf("%d",&len);
char str[len]="";

Це також дає помилку:

int len=5;
char str[len]="";

Але це працює чудово:

int len=5;
char str[len]; //so the problem lies with assignment not declaration

Потрібно поставити значення таким чином:

str[0]='a';
str[1]='b'; //like that; and not like str="ab";

2

Після оголошення масиву

int boardAux[length][length];

найпростіший спосіб призначити початкові значення, як нуль, використовується для циклу, навіть якщо він може бути трохи тривалим

int i, j;
for (i = 0; i<length; i++)
{
    for (j = 0; j<length; j++)
        boardAux[i][j] = 0;
}

2
memsetпростіше і швидше.
Cacahuete Frito

1

На питання вже відповіли, але я хотів би вказати на інше рішення, яке швидко і працює, якщо довжина не повинна змінюватися під час виконання. Використовуйте макрос #define перед main (), щоб визначити довжину, а main () ваша ініціалізація буде працювати:

#define length 10

int main()
{
    int boardAux[length][length] = {{0}};
}

Макроси запускаються до фактичної компіляції, а довжина буде константою часу компіляції (на що вказує Девід Родрігес у своїй відповіді). Він фактично замінить довжину на 10 перед компіляцією.


0

Просто оголосіть довжину як мінус, якщо її немає, то вам слід динамічно розподіляти пам'ять


2
Я думаю, вам потрібно шукати, що означає const!
Холгер

@Holger: Ви впевнені? Якщо змінна, яка містить довжину (не сам масив, а довжина масиву), є постійною, то компілятор знає довжину, яку використовувати для ініціалізації масиву. Наприклад, "int length = 5; масив int [length];" дає помилку, але " const int length = 5; int масив [length];" компілює просто чудово.
Кейсі

0
int size=5;
int ar[size ]={O};

/* This  operation gives an error -  
variable sized array may not be 
initialised.  Then just try this. 
*/
int size=5,i;
int ar[size];
for(i=0;i<size;i++)
{
    ar[i]=0;
}

1
Ласкаво просимо до переповнення стека! Прочитайте, будь ласка, посібник про те, як написати гарну відповідь: stackoverflow.com/help/how-to-answer Ваша поточна відповідь здається розпливчастою і не має до неї ніяких пояснень
gybandi

-5

Для C ++ роздільне оголошення та ініціалізація, як це ..

int a[n][m] ;
a[n][m]= {0};

1
Не питання C ++
Cacahuete Frito

Вище лише ініціалізується A [n] [m], а не весь масив. int a [n] [m]; memset (a, 0, (n m sizeof (int)); // очищати mem масиву більшості компіляторів це дозволяють: int a [n] [m] = {0}; // ініціалізувати всіх членів до 0
Chris Reid

-9

Ви не можете цього зробити. Компілятор C не може зробити таку складну річ у стеці.

Ви повинні використовувати купу та динамічне розподіл.

Що вам справді потрібно зробити:

  • обчислити розмір (n m sizeof (елемент)) потрібної пам'яті
  • виклик malloc (розмір) для розподілу пам'яті
  • створити аксесуар: int * access (ptr, x, y, rowSize) {return ptr + y * rowSize + x; }

Використовуйте * доступ (boardAux, x, y, розмір) = 42 для взаємодії з матрицею.


ще одне запитання: чому я отримую помилку щодо недійсного використання масиву з невизначеними межами? printf ("% d", дошка [i] [j]);
helloWorld

10
-1 C99 дозволяє динамічно розподіляти в стеку як код користувача (виключаючи ініціалізацію). Немає необхідності виконувати динамічні розподіли.
Девід Родрігес - дрибес

@helloWorld, оскільки розміри масиву повинні бути відомі.
Павло Радзивиловський
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.