Cコンパイルエラー:「可変サイズのオブジェクトが初期化されていない可能性があります」


97

次のコードで「可変サイズのオブジェクトが初期化されていない可能性があります」というエラーが表示されるのはなぜですか?

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

David Rodriguezの優れた回答で指摘されているように、長さが変数の場合はmemsetが必要ですが、長さがコンパイル時の定数の場合、ステートメントは正常にコンパイルされます。
ケーシー

2020年への前進enum {length = 0xF } ; int boardAux[length][length] = {0};
シェフグラディエーター

回答:


121

私はC99コンパイラを使用していると仮定しています(動的にサイズが設定された配列をサポートしています)。あなたのコードの問題は、コンパイラが変数宣言を見るときに、配列に要素がいくつあるかを知ることができないということです(ここでも、lengthコンパイル時定数ではないコンパイラエラーから想定しています)。

その配列を手動で初期化する必要があります。

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

この目的でmallocも使用できます。2番目の質問についてはどう
ですか。Pavel

@helloWorld:スタックに割り当てられた配列を使用して、printf( "%d", boardAux[1][2] )正常にコンパイルします。コンパイラーはサイズを認識し、メモリー内の(1,2)番目の要素がどの位置にあるかを認識します。あなたが動的割り当てを使用する場合は、アレイは、一次元であり、あなたは数学を自分で実行する必要がありますprintf("%d", boardAux[ 1*length + 2 ])
デビッド・ロドリゲス- dribeas

@AndreyT:memsetコールアウトでエラーを指摘してくれてありがとう。修正しました。
デビッドロドリゲス-10

をに設定するlengthと、C99コンパイラでこのエラーが発生するのはなぜstaticですか?C ++ 14では正常に動作します。
Muhamed Cicak

25

C言語では、可変長配列でイニシャライザを使用できないため、このエラーが表示されます。あなたが得ているエラーメッセージは基本的にそれをすべて言います。

6.7.8初期化

...

3初期化するエンティティのタイプは、サイズが不明な配列か、可変長配列タイプではないオブジェクトタイプでなければなりません。


どこで見つけましたか、リンクをください。
helloWorld

1
@helloWorld:これは言語標準(C99)からのものです。TC3のアップデートで「動作する」コピーを入手できますopen-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf
AnT

5
非公式な説明を提供するだけの場合、一部の人は常にあなたを信じないでしょう。可変長配列はこれらのトピックの1つです。標準を引用するための+1。
Pascal Cuoq

14

これはエラーになります:

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シンプルで高速です。
カカウエテフリト

1

質問はすでに回答されていますが、実行時に長さを変更することを意図していない場合に高速で機能する別のソリューションを指摘したいと思います。main()の前にマクロ#defineを使用して長さを定義すると、main()で初期化が機能します。

#define length 10

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

マクロは実際のコンパイルの前に実行され、長さはコンパイル時の定数になります(回答でDavidRodríguezが参照)。実際には、コンパイル前に長さを10に置き換えます。


0

長さを短所として宣言するだけです。そうでない場合は、メモリを動的に割り当てる必要があります


2
constの意味を調べる必要があると思います。
Holger

@ホルガー:よろしいですか?長さを保持する変数(配列自体ではなく配列の長さ)が定数である場合、コンパイラーは配列を初期化するために使用する長さを認識しています。たとえば、「int length = 5; int array [length];」のようになります。エラーが発生しますが、「const int length = 5; int array [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
Stack Overflowへようこそ!良い答えを書く方法についてのガイドをお読みください:stackoverflow.com/help/how-to-answerあなたの現在の答えはあいまいなようだと、それへの説明はありません
gybandi

-5

C ++の場合、このように個別の宣言と初期化を行います。

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

1
C ++の質問ではありません
カカウエテフリト

上記は、配列全体ではなく、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(element))を計算する
  • malloc(size)を呼び出してメモリを割り当てます
  • アクセサーを作成:int * access(ptr、x、y、rowSize){return ptr + y * rowSize + x; }

* access(boardAux、x、y、size)= 42を使用して、マトリックスを操作します。


もう1つの質問、境界が指定されていない配列の無効な使用エラーが発生するのはなぜですか?printf( "%d"、board [i] [j]);
helloWorld

10
-1 C99では、ユーザーコード(初期化を除く)としてスタック内の動的割り当てが可能です。動的割り当てを実行する必要はありません。
デビッドロドリゲス-dribeas

@helloWorldは、配列の次元を知っている必要があるためです。
Pavel Radzivilovsky、2010年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.