Błąd kompilacji C: „Nie można zainicjować obiektu o zmiennej wielkości”


98

Dlaczego pojawia się błąd „Nie można zainicjować obiektu o zmiennej wielkości” za pomocą następującego kodu?

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

Jak wskazał w doskonałej odpowiedzi Davida Rodrigueza: jeśli długość jest zmienną, potrzebny jest zestaw memset, ale jeśli długość jest stałą w czasie kompilacji, to instrukcja kompiluje się dobrze.
Casey

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

Odpowiedzi:


124

Zakładam, że używasz kompilatora C99 (z obsługą tablic o dynamicznych rozmiarach). Problem w twoim kodzie polega na tym, że w momencie, gdy kompilatory widzą twoją deklarację zmiennej, nie mogą wiedzieć, ile elementów znajduje się w tablicy (zakładam również tutaj, na podstawie błędu kompilatora, który lengthnie jest stałą czasową kompilacji).

Musisz ręcznie zainicjować tę tablicę:

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

Mogę do tego użyć również malloc, a co z drugim pytaniem, napisałem je po odpowiedzi Pawła
helloWorld

@helloWorld: z tablicami przydzielonymi na stosie, printf( "%d", boardAux[1][2] )kompiluje się dobrze. Kompilator zna rozmiary i wie, w jakiej pozycji w pamięci znajduje się (1,2) -ty element. Jeśli korzystasz z alokacji dynamicznej, tablica jest jednowymiarowa i musisz wykonać obliczenia samodzielnie:printf("%d", boardAux[ 1*length + 2 ])
David Rodríguez - dribeas

@AndreyT: Dziękuję za wskazanie błędu w memsetwezwaniu. Właśnie to poprawiłem.
David Rodríguez - dribeas

Dlaczego otrzymuję ten błąd w C99 kompilatora kiedy ustawić lengthsię static? W C ++ 14 działa dobrze.
Muhamed Cicak,

26

Ten błąd pojawia się, ponieważ w języku C nie możesz używać inicjatorów z tablicami o zmiennej długości. Komunikat o błędzie, który otrzymujesz, w zasadzie mówi wszystko.

6.7.8 Inicjalizacja

...

3 Typ obiektu, który ma zostać zainicjowany, powinien być tablicą o nieznanym rozmiarze lub typem obiektu, który nie jest typem tablicy o zmiennej długości.


gdzie to znalazłeś, czy możesz podać mi link?
helloWorld,

1
@helloWorld: To jest ze standardu językowego (C99). Możesz otrzymać "roboczą" kopię z aktualizacjami TC3 tutaj open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf
AnT,

5
Są tematy, w przypadku których niektórzy zawsze będą ci nie wierzyć, jeśli podasz tylko nieformalne wyjaśnienie. Tablice o zmiennej długości są jednym z tych tematów. +1 za cytowanie normy.
Pascal Cuoq

15

To daje błąd:

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

Daje to również błąd:

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

Ale to działa dobrze:

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

Musisz podać wartość w następujący sposób:

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

2

Po zadeklarowaniu tablicy

int boardAux[length][length];

najprostszym sposobem przypisania początkowych wartości jako zera jest użycie pętli for, nawet jeśli może to być trochę za długie

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

2
memsetjest prostsze i szybsze.
Cacahuete Frito

1

Odpowiedź na to pytanie jest już dostępna, ale chciałem wskazać inne rozwiązanie, które jest szybkie i działa, jeśli długość nie ma być zmieniana w czasie wykonywania. Użyj makra #define przed main (), aby zdefiniować długość, aw main () inicjalizacja zadziała:

#define length 10

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

Makra są uruchamiane przed właściwą kompilacją, a długość będzie stałą czasu kompilacji (o czym wspomina David Rodríguez w swojej odpowiedzi). W rzeczywistości zastąpi on długość 10 przed kompilacją.


0

Po prostu zadeklaruj długość jako wadę, jeśli tak nie jest, powinieneś alokować pamięć dynamicznie


2
Myślę, że musisz sprawdzić, co oznacza const!
Holger,

@Holger: Czy na pewno? Jeśli zmienna, która przechowuje długość (nie samą tablicę, ale długość tablicy) jest stałą, to kompilator zna długość, której należy użyć do zainicjowania tablicy. Na przykład „int length = 5; int array [length];” podaje błąd, ale " const int length = 5; int array [length];" kompiluje się dobrze.
Casey

@Casey: ale const int lenght=5; int array[length][length] = {{0}};nie będzie.
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
Witamy w Stack Overflow! Przeczytaj przewodnik, jak napisać dobrą odpowiedź: stackoverflow.com/help/how-to-answer Twoja obecna odpowiedź wydaje się niejasna i nie ma żadnego wyjaśnienia
gybandi

-5

Dla oddzielnej deklaracji C ++ i inicjalizacji w ten sposób ...

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

1
To nie jest pytanie C ++
Cacahuete Frito

Powyżej tylko inicjalizuje A [n] [m], a nie całą tablicę. int a [n] [m]; memset (a, 0, (n m sizeof (int)); // wyczyść mem z tablicy Większość kompilatorów pozwala na to: int a [n] [m] = {0}; // zainicjuj wszystkich członków na 0
Chris Reid

-9

Nie możesz tego zrobić. Kompilator C nie może zrobić tak złożonej rzeczy na stosie.

Musisz użyć sterty i alokacji dynamicznej.

Co naprawdę musisz zrobić:

  • oblicz rozmiar (n m sizeof (element)) potrzebnej pamięci
  • wywołaj malloc (size), aby przydzielić pamięć
  • utwórz akcesor: int * access (ptr, x, y, rowSize) {return ptr + y * rowSize + x; }

Użyj * access (boardAux, x, y, size) = 42 do interakcji z macierzą.


jeszcze jedno pytanie, dlaczego otrzymuję błąd nieprawidłowego użycia tablicy z nieokreślonymi granicami? printf ("% d", deska [i] [j]);
helloWorld

10
-1 C99 pozwala na dynamiczną alokację w stosie jako kod użytkownika (z wyłączeniem inicjalizacji). Nie ma potrzeby wykonywania alokacji dynamicznych.
David Rodríguez - dribeas

@helloWorld, ponieważ wymiary tablicy muszą być znane.
Pavel Radzivilovsky
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.