Ошибка компиляции C: «Объект переменного размера не может быть инициализирован»


98

Почему я получаю сообщение об ошибке «Объект переменного размера не может быть инициализирован» с помощью следующего кода?

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

Как указано в отличном ответе Дэвида Родригеса: если длина является переменной, вам нужен memset, но если длина является константой времени компиляции, тогда оператор компилируется нормально.
Кейси

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

Ответы:


124

Я предполагаю, что вы используете компилятор 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 ])
Дэвид Родригес - dribeas

@AndreyT: Спасибо, что указали на ошибку в memsetвызове. Я только что поправил.
Дэвид Родригес - дрибес

Почему я получаю эту ошибку в C99 компилятора , когда я установил lengthбыть static? В C ++ 14 все работает нормально.
Мухамед Чичак

26

Вы получаете эту ошибку, потому что в языке C вам не разрешено использовать инициализаторы с массивами переменной длины. Сообщение об ошибке, которое вы получаете, говорит само за себя.

6.7.8 Инициализация

...

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


где ты это нашел, можешь дать ссылку?
helloWorld

1
@helloWorld: это из языкового стандарта (C99). Вы можете получить "рабочую" копию с обновлениями TC3 здесь open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf
AnT

5
Есть темы, по которым некоторые всегда не поверят вам, если вы предоставите только неформальное объяснение. Массивы переменной длины - одна из таких тем. +1 за цитирование стандарта.
Pascal Cuoq

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];

Самый простой способ присвоить начальным значениям ноль - использовать цикл for, даже если он может быть длинноватым

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

@Holger: Ты уверен? Если переменная, содержащая длину (не сам массив, а длина массива), является константой, то компилятор знает длину, используемую для инициализации массива. Например, «int length = 5; int array [length];» выдает ошибку, но « const int length = 5; int array [length];» компилируется нормально.
Кейси

@Casey: но const int lenght=5; int array[length][length] = {{0}};не будет.
MestreLion

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
Добро пожаловать в Stack Overflow! Пожалуйста, прочтите руководство о том, как написать хороший ответ: 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)); // очищаем память массива. Большинство компиляторов позволяют это: int a [n] [m] = {0}; // инициализировать все члены равными 0
Крис Рид

-9

Ты не можешь сделать это. Компилятор C не может делать такие сложные вещи в стеке.

Вы должны использовать кучу и динамическое размещение.

Что вам действительно нужно делать:

  • вычислить размер (n m sizeof (element)) необходимой вам памяти
  • вызвать malloc (size) для выделения памяти
  • создайте средство доступа: int * access (ptr, x, y, rowSize) {return ptr + y * rowSize + x; }

Используйте * access (boardAux, x, y, size) = 42 для взаимодействия с матрицей.


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

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

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