Lỗi biên dịch C: "Đối tượng có kích thước thay đổi có thể không được khởi tạo"


97

Tại sao tôi nhận được lỗi "Đối tượng có kích thước thay đổi có thể không được khởi tạo" với mã sau?

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

Như đã chỉ ra trong câu trả lời xuất sắc của David Rodriguez: nếu độ dài là một biến, bạn cần bộ nhớ, nhưng nếu độ dài là hằng số thời gian biên dịch, thì câu lệnh biên dịch tốt.
Casey

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

Câu trả lời:


121

Tôi giả định rằng bạn đang sử dụng trình biên dịch C99 (với hỗ trợ cho các mảng có kích thước động). Vấn đề trong mã của bạn là tại thời điểm khi trình biên dịch nhìn thấy khai báo biến của bạn, nó không thể biết có bao nhiêu phần tử trong mảng (tôi cũng giả định ở đây, do lỗi trình biên dịch lengthkhông phải là hằng số thời gian biên dịch).

Bạn phải khởi tạo mảng đó theo cách thủ công:

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

Tôi có thể sử dụng cho mục đích này malloc là tốt, những gì về câu hỏi thứ hai, tôi đã viết nó sau khi trả lời Pavel của
HelloWorld

@helloWorld: Với mảng được phân bổ ngăn xếp, printf( "%d", boardAux[1][2] )biên dịch tốt. Trình biên dịch biết kích thước và biết phần tử (1,2) -th nằm ở vị trí nào trong bộ nhớ. Nếu bạn sử dụng phân bổ động mảng là uni-chiều và bạn phải thực hiện các toán tự hỏi:printf("%d", boardAux[ 1*length + 2 ])
David Rodríguez - dribeas

@AndreyT: Cảm ơn bạn đã chỉ ra lỗi trong memsetcuộc gọi. Tôi vừa sửa lại.
David Rodríguez - dribeas

Tại sao tôi gặp lỗi này trong trình biên dịch C99 khi tôi đặt lengthstatic? Trong C ++ 14, nó hoạt động tốt.
Muhamed Cicak

25

Bạn nhận được lỗi này vì trong ngôn ngữ C, bạn không được phép sử dụng bộ khởi tạo với mảng có độ dài thay đổi. Về cơ bản, thông báo lỗi bạn đang nhận được đã nói lên tất cả.

6.7.8 Khởi tạo

...

3 Kiểu thực thể được khởi tạo phải là một mảng có kích thước không xác định hoặc một kiểu đối tượng không phải là kiểu mảng có độ dài thay đổi.


Bạn tìm thấy cái này ở đâu, Bạn có thể cho tôi một liên kết được không?
helloWorld

1
@helloWorld: Đây là từ tiêu chuẩn ngôn ngữ (C99). Bạn có thể nhận được bản sao "đang hoạt động" với các bản cập nhật TC3 tại đây open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf
AnT

5
Có những chủ đề mà một số người sẽ luôn không tin bạn nếu bạn chỉ đưa ra lời giải thích không chính thức. Mảng có độ dài thay đổi là một trong những chủ đề này. +1 để trích dẫn tiêu chuẩn.
Pascal Cuoq

14

Điều này gây ra lỗi:

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

Điều này cũng gây ra lỗi:

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

Nhưng điều này hoạt động tốt:

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

Bạn cần đặt giá trị theo cách sau:

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

2

Sau khi khai báo mảng

int boardAux[length][length];

cách đơn giản nhất để gán các giá trị ban đầu bằng 0 là sử dụng vòng lặp for, ngay cả khi nó có thể hơi dài dòng

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

2
memsetđơn giản hơn và nhanh hơn.
Cacahuete Frito

1

Câu hỏi đã được trả lời nhưng tôi muốn chỉ ra một giải pháp khác nhanh chóng và hoạt động nếu độ dài không được thay đổi trong thời gian chạy. Sử dụng macro #define trước main () để xác định độ dài và trong main () quá trình khởi tạo của bạn sẽ hoạt động:

#define length 10

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

Macro được chạy trước khi biên dịch thực sự và độ dài sẽ là một hằng số thời gian biên dịch (như David Rodríguez đã đề cập trong câu trả lời của mình). Nó thực sự sẽ thay thế độ dài bằng 10 trước khi biên dịch.


0

Đơn giản chỉ cần khai báo độ dài là một khuyết điểm, nếu không thì bạn nên cấp phát bộ nhớ động


2
Tôi nghĩ bạn cần phải tra cứu const có nghĩa là gì!
Holger

@Holger: Bạn có chắc không? Nếu biến chứa độ dài (không phải bản thân mảng mà là độ dài mảng) là một hằng số, thì trình biên dịch biết độ dài cần sử dụng để khởi tạo mảng. Ví dụ: "int length = 5; int array [length];" đưa ra lỗi nhưng " const int length = 5; int array [length];" biên dịch tốt.
Casey

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
Chào mừng bạn đến với Stack Overflow! Vui lòng đọc hướng dẫn về cách viết một câu trả lời hay: stackoverflow.com/help/how-to-answer Câu trả lời hiện tại của bạn có vẻ mơ hồ và không có bất kỳ lời giải thích nào
gybandi

-5

Đối với khai báo và khởi tạo riêng biệt C ++ như thế này ..

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

1
Không phải câu hỏi C ++
Cacahuete Frito

Ở trên chỉ khởi tạo A [n] [m], không phải toàn bộ mảng. int a [n] [m]; memset (a, 0, (n m sizeof (int)); // xóa mem của mảng Hầu hết các trình biên dịch đều cho phép điều này: int a [n] [m] = {0}; // khởi tạo tất cả thành viên thành 0
Chris Reid

-9

Bạn không thể làm điều đó. Trình biên dịch C không thể làm một điều phức tạp như vậy trên ngăn xếp.

Bạn phải sử dụng heap và phân bổ động.

Những gì bạn thực sự cần làm:

  • tính toán kích thước (n m sizeof (phần tử)) của bộ nhớ bạn cần
  • gọi malloc (size) để cấp phát bộ nhớ
  • tạo một trình truy cập: int * access (ptr, x, y, rowSize) {return ptr + y * rowSize + x; }

Sử dụng * access (boardAux, x, y, size) = 42 để tương tác với ma trận.


một câu hỏi nữa, tại sao tôi nhận được lỗi sử dụng mảng không hợp lệ với các giới hạn không xác định? printf ("% d", ban [i] [j]);
helloWorld

10
-1 C99 cho phép phân bổ động trong ngăn xếp dưới dạng mã người dùng (không bao gồm phần khởi tạo). Không cần thực hiện phân bổ động.
David Rodríguez - dribeas

@helloWorld vì kích thước mảng phải được biết.
Pavel Radzivilovsky
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.