2D配列全体を1つの値で初期化する


82

次の宣言で

すべてゼロの配列を取得しますが、次の配列を使用します

すべて1つの値を持つ配列を取得しません。デフォルト値は0のままです。

なぜこの動作をし、どのようにすべて1で初期化できますか?

編集:memset値を1として使用すると、各バイトが1に設定されるため、各配列セルの実際の値は1ではなく16843009。になることを理解しました。1に設定するにはどうすればよいですか?


1
@ckruse:質問は「方法」ではなく、「理由」です。
masoud 2013年

@んん。答えは私がリンクしたスレッドで与えられます。
ckruse 2013年

問題は実際にはwhy and how両方でした。:)
クラーケン

@Kraken編集中の質問は、おそらくこれとは別の質問として投稿する必要があります。
Lundin

1
@Kraken実際、私はその質問をここで見つけまし。私の答えで提案されているように(もちろん!)、GCC拡張機能に依存しないことをお勧めします。
Lundin

回答:


126

「すべてのアイテムを1つに設定する」という意味でint array [ROW][COLUMN] = {1};ないため、この動作が発生します。これがどのように機能するかを段階的に説明してみましょう。

配列を初期化する明示的で過度に明確な方法は、次のようになります。

ただし、Cを使用すると、配列(または構造体/共用体)内の一部の項目を除外できます。たとえば、次のように書くことができます。

つまり、最初の要素を1と2に初期化し、残りの要素を「静的な保存期間があるかのように」初期化します。Cには、プログラマーによって明示的に初期化されていない静的ストレージ期間のすべてのオブジェクトをゼロに設定する必要があるという規則があります。

したがって、上記の例では、明示的な値を指定しなかったため、最初の行は1,2に設定され、次の行は0,0に設定されます。

次に、Cには緩いブレーススタイルを許可するルールがあります。最初の例は、次のように書くこともできます。

もちろんこれは貧弱なスタイルですが、読みにくく、理解しにくいです。しかし、このルールは私たちが書くことができるので便利です

つまり、「最初の行の最初の列を0に初期化し、他のすべてのアイテムを静的な保存期間があるかのように初期化します。つまり、ゼロに設定します。」

したがって、あなたがしようとすると

これは、「最初の行の最初の列を1に初期化し、他のすべての項目をゼロに設定する」ことを意味します。


2
そのおかげで、配列全体を1で初期化するためにできることは何ですか?私の行と列のサイズが数百であることを考慮しますか?
クラーケン

1
@Krakenマクロトリック付き。これを参照してください
Lundin 2014年

それは私だけですか、それとも2番目の括弧が必要ですか?int array [ROW][COLUMN] = {{0}};
user1794469 2016年

@ user1794469いいえ。
Lundin 2016年

1
@ user1794469はい、それは良いことです。ほとんどの場合、中括弧をスキップすることは悪い習慣だからです。しかし、コンパイラーは診断を行う必要はありません。この場合の良い/悪い習慣については、この質問に対する私の答えを参照してください。
Lundin 2016年

40

配列を初期化する-1場合は、次を使用できます。

しかし、これは動作します0-1だけ


17
「sizeof(array [0] [0])* row * count」の代わりに「sizeof(array)」を使用する方が簡単です。
Vladyslav Savchenko

その私にはクリアしていないが、それはほかに有用であろうものを任意の一定のバイトのために働く00001111
user1794469

5
<cstring>C ++に含める必要があります
mtk 2016

12

これにより、最初の要素のみが1に初期化されます。それ以外はすべて0になります。

最初の例では、同じことを行っています。最初の要素を0に初期化し、残りはデフォルトで0に設定します。

理由は簡単です。配列の場合、コンパイラは指定しないすべての値を0で初期化します。

ではchar、配列あなたは使用することができmemset、すべてのバイトを設定するが、これは一般的では動作しませんint(0のためにそれの罰金が)配列。

一般的なforループはこれをすばやく実行します。

または、おそらくより高速です(コンパイラによって異なります)


1
@ Kraken-そうではありません-0最初の値だけも初期化します。次に、残りのすべて0をデフォルトで初期化します。
teppic 2013年

@EricPostpischilなので、すべてのバイトを1に設定します。したがって、32ビット整数を考慮すると、のvalueフィールドmemsetが1の場合、マトリックスの実際の値は1になり2^0 + 2^8 + 2^16 + 2^24ませんが、?
クラーケン

@Kraken:基本的にはそうです。memset宛先の各バイトを指定された値に設定intします。これmemsetは、を1に設定するためには機能しません。オブジェクトの各バイトを同じ値に設定する場合を除いて、複数バイトのオブジェクトの値を設定するために使用することはできません。
Eric Postpischil 2013年

@EricPostpischilでは、それぞれを手動で初期化する以外にそれを行う方法はありませんか?私の行と列が数千にさえあることを考慮しますか?
クラーケン

@Kraken {1}が機能しない理由の説明を投稿しました。そして実際、手動で初期化する以外に方法はありません。何千もの数字を入力する必要はありません。マクロのトリックがありますが、それはおそらく別の質問のトピックです。
Lundin

8

GCCには、指定された初期化子表記の拡張機能があり、コンテキストに非常に役立ちます。clangコメントなしでも許可されます(一部はGCCとの互換性を確保しようとしているため)。

拡張表記を使用...すると、次の値で初期化する要素の範囲を指定できます。例えば:

当然のことながら、出力は次のとおりです。

Fortran 66(Fortran IV)には、配列の初期化子の繰り返しカウントがあることに注意してください。指定されたイニシャライザーが言語に追加されたときにCがそれらを取得しなかったのは、いつも奇妙なことに私を驚かせました。また、Pascalは0..9表記を使用して、0から9までの範囲を指定しますが、Cは..トークンとして使用しないため、使用されなかったのは当然のことです。

...表記の周りのスペースは基本的に必須であることに注意してください。それらが数値に付加されている場合、その数値は浮動小数点数として解釈されます。例えば、0...9としてトークン化されるであろう0...9、および浮動小数点数は、配列の添字として使用できません。名前付き定数を使用すると、...ROW-1問題は発生しませんが、安全な習慣を身に付けることをお勧めします。


補遺:

ちなみに、GCC7.3.0は以下を拒否します。

ここで、スカラー初期化子1error: braces around scalar initializer [-Werror])の周りに余分な中括弧のセットがあります。でスカラーを囲む中括弧を通常指定できることを考えると、それが正しいかどうかはわかりませんint a = { 1 };。これは、標準で明示的に許可されています。それが間違っているかどうかもわかりません。

また、より適切な表記法[0]...[9]は、明確であり、他の有効な構文と混同することはできず、浮動小数点数との混同を回避することになるのではないかと思います。

たぶん、標準化委員会はそれを検討するでしょうか?


7

2D配列をゼロで初期化するには、以下の方法を使用します。 int arr[n][m] = {};

:上記の方法は、0で初期化する場合にのみ機能します。



0

これは、char配列要素をスペース文字に初期化するためのものです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.