ข้อผิดพลาดในการคอมไพล์ C:“ อ็อบเจ็กต์ขนาดตัวแปรอาจไม่สามารถเริ่มต้นได้”


100

เหตุใดฉันจึงได้รับข้อผิดพลาด "Variable-sized object may not be initialized" พร้อมรหัสต่อไปนี้

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

ตามที่ระบุไว้ในคำตอบที่ยอดเยี่ยมของ David Rodriguez: หากความยาวเป็นตัวแปรคุณต้องมี memset แต่ถ้าความยาวเป็นค่าคงที่เวลาคอมไพล์คำสั่งนั้นจะรวบรวมได้ดี
Casey

ffwd ถึงปี 2020 -enum {length = 0xF } ; int boardAux[length][length] = {0};
Chef Gladiator

คำตอบ:


126

ฉันสมมติว่าคุณใช้คอมไพเลอร์ C99 (พร้อมการรองรับอาร์เรย์ขนาดไดนามิก) ปัญหาในโค้ดของคุณคือในเวลาที่คอมไพเลอร์เห็นการประกาศตัวแปรของคุณมันไม่สามารถรู้ได้ว่ามีองค์ประกอบในอาร์เรย์กี่องค์ประกอบ (ฉันสมมติที่นี่จากข้อผิดพลาดของคอมไพเลอร์ที่lengthไม่ใช่ค่าคงที่ของเวลาในการคอมไพล์)

คุณต้องเริ่มต้นอาร์เรย์นั้นด้วยตนเอง:

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

ฉันสามารถใช้เพื่อจุดประสงค์นี้ malloc เช่นกันคำถามที่สองฉันเขียนไว้หลังจาก Pavel ตอบกลับ
helloWorld

@helloWorld: ด้วยอาร์เรย์ที่จัดสรรกองซ้อนprintf( "%d", boardAux[1][2] )คอมไพล์ได้ดี คอมไพเลอร์รู้ขนาดและรู้ว่าตำแหน่งใดในหน่วยความจำองค์ประกอบ (1,2) -th คืออะไร หากคุณใช้การจัดสรรแบบไดนามิกอาร์เรย์จะเป็นมิติเดียวและคุณต้องคำนวณด้วยตัวเอง:printf("%d", boardAux[ 1*length + 2 ])
David Rodríguez - dribeas

@AndreyT: ขอบคุณที่ชี้ข้อผิดพลาดในการmemsetโทรออก ฉันเพิ่งแก้ไขมัน
David Rodríguez - dribeas

ทำไมฉันจะได้รับข้อผิดพลาดใน C99 คอมไพเลอร์เมื่อฉันตั้งค่าlengthจะเป็นstatic? ใน C ++ 14 ทำงานได้ดี
Silidrone

ฉันต้องการทราบเหตุผลว่าทำไมจึงmallocไม่จำเป็นต้องใช้
mazend

26

คุณได้รับข้อผิดพลาดนี้เนื่องจากในภาษา C คุณไม่ได้รับอนุญาตให้ใช้ initializers กับอาร์เรย์ที่มีความยาวผันแปรได้ ข้อความแสดงข้อผิดพลาดที่คุณได้รับโดยทั่วไปกล่าวได้ทั้งหมด

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

3

หลังจากประกาศอาร์เรย์

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

3

คำถามได้รับคำตอบแล้ว แต่ฉันต้องการชี้ให้เห็นวิธีแก้ปัญหาอื่นที่รวดเร็วและใช้งานได้ถ้าความยาวไม่ได้หมายถึงการเปลี่ยนแปลงในเวลาทำงาน ใช้มาโคร #define ก่อน main () เพื่อกำหนดความยาวและใน main () การเริ่มต้นของคุณจะทำงาน:

#define length 10

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

มาโครถูกเรียกใช้ก่อนการคอมไพล์จริงและความยาวจะเป็นค่าคงที่เวลาคอมไพล์ (ตามที่ David Rodríguezอ้างในคำตอบของเขา) มันจะแทนความยาวด้วย 10 ก่อนคอมไพล์


จะมีความแตกต่างระหว่างจริง{0}และ{{0}}?
ITJ

1

อาร์เรย์ไม่ได้เริ่มต้นด้วยหน่วยความจำที่ระบุ anf แสดงข้อผิดพลาด variable sized array may not be initialised ฉันชอบวิธีการเริ่มต้นตามปกติ

for (i = 0; i <= bins; i++)
        arr[i] = 0;

0

เพียงแค่ประกาศความยาวเป็นข้อเสียหากไม่เป็นเช่นนั้นคุณควรจัดสรรหน่วยความจำแบบไดนามิก


2
ฉันคิดว่าคุณต้องค้นหาความหมายของ const!
Holger

@ Holger: แน่ใจเหรอ? ถ้าตัวแปรที่เก็บความยาว (ไม่ใช่อาร์เรย์เอง แต่เป็นความยาวอาร์เรย์) เป็นค่าคงที่คอมไพเลอร์จะทราบความยาวที่จะใช้เริ่มต้นอาร์เรย์ ตัวอย่างเช่น "int length = 5; int array [length];" ให้ข้อผิดพลาด แต่ " const int length = 5; int array [length];" รวบรวมได้ดี
Casey

@ 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)); // clear mem of array คอมไพเลอร์ส่วนใหญ่อนุญาตสิ่งนี้: int a [n] [m] = {0}; // เริ่มต้นสมาชิกทั้งหมดเป็น 0
Chris Reid

-9

คุณไม่สามารถทำได้. คอมไพเลอร์ C ไม่สามารถทำสิ่งที่ซับซ้อนบนสแต็กได้

คุณต้องใช้ฮีปและการจัดสรรแบบไดนามิก

สิ่งที่คุณต้องทำ:

  • ขนาดคำนวณ ( nm sizeof (องค์ประกอบ)) ของหน่วยความจำที่คุณต้องการ
  • เรียก malloc (ขนาด) เพื่อจัดสรรหน่วยความจำ
  • สร้าง accessor: 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 อนุญาตให้มีการจัดสรรแบบไดนามิกในสแต็กเป็นรหัสผู้ใช้ (ไม่รวมการเริ่มต้น) ไม่จำเป็นต้องทำการจัดสรรแบบไดนามิก
David Rodríguez - dribeas

@helloWorld เนื่องจากต้องทราบขนาดอาร์เรย์
Pavel Radzivilovsky
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.