名前空間
変種
操作

配列の初期化

提供: cppreference.com
< c‎ | language

配列型のオブジェクトを初期化するときは、初期化子は文字列リテラル (波括弧で囲っても構いません) であるか、波括弧で囲まれた配列メンバの初期化子のリストでなければなりません。

= string_literal (1)
= { expression , ... }

= { designator(オプション) expression , ... }

(2) (C99未満)
(C99以上)
1) 文字配列およびワイド文字配列用の文字列リテラルの初期化子。
2) 配列要素のための初期化子となる定数 (C99未満)式のコンマ区切りのリスト。 [ constant-expression ] = 形式の配列指示子を使用することもできます。 (C99以上)

サイズが既知な配列およびサイズが未知な配列は初期化できますが、 VLA はできません (C99以上)

明示的に初期化されないすべての配列要素は静的記憶域期間を持つオブジェクトと同じ方法で暗黙に初期化されます。

目次

[編集] 文字列からの初期化

一致する型の配列に対する初期化子として文字列リテラル (波括弧で囲っても構いません) を使用できます。

  • 通常の文字列リテラルおよび UTF-8 文字列リテラル (C11以上)は任意の文字型 (charsigned charunsigned char) の配列を初期化できます。
  • 接頭辞 L 付きのワイド文字列リテラルは wchar_t と互換な任意の型 (cv 修飾は無視します) の配列を初期化するために使用できます。
  • 接頭辞 u 付きのワイド文字列リテラルは char16_t と互換な任意の型 (cv 修飾は無視します) の配列を初期化するために使用できます。
  • 接頭辞 U 付きのワイド文字列リテラルは char32_t と互換な任意の型 (cv 修飾は無視します) の配列を初期化するために使用できます。
(C11以上)

文字列リテラルのバイトの並びまたはワイド文字列リテラルのワイド文字の並び (終端のヌル文字を含みます) が配列の要素を初期化します。

char str[] = "abc"; // str は char[4] 型で、 'a', 'b'. 'c', '\0' を保持します。
wchar_t wstr[4] = L"猫"; // str は wchar_t[4] 型で、 L'猫', L'\0', L'\0', L'\0' を保持します。

配列のサイズが既知な場合、そのサイズは文字列リテラルのサイズより1小さくても構いません。 この場合、終端のヌル文字は無視されます。

char str[3] = "abc"; // str は char[3] 型で、 'a', 'b', 'c' を保持します。

このような配列の内容は変更可能であることに注意してください。 char* str = "abc"; のように初期化して文字列リテラルに直接アクセスする場合とは異なります。

[編集] 波括弧で囲まれたリストからの初期化

配列が波括弧で囲まれた初期化子のリストを用いて初期化されるとき、 (指示子が指定された場合を除いて) (C99以上) リスト内の最初の初期化子はインデックスゼロの配列要素を初期化し、その後の指示子のない (C99以上)初期化子はそれぞれ直前の初期化子が初期化した要素より1つ大きなインデックスの配列要素を初期化します。

int x[] = {1,2,3}; // x は int[3] 型で、 1,2,3 を保持します。
int y[5] = {1,2,3}; // y は int[5] 型で、 1,2,3,0,0 を保持します。
int z[3] = {0}; // z は int[3] 型で、 0,0,0 を保持します。

サイズが既知な配列を初期化するとき、要素より多くの初期化子を提供することはエラーです (文字配列を文字列リテラルから初期化するときは除きます)。

指示子は、後続の初期化子が、その指示子によって表される配列要素を初期化するようにします。 その後の初期化は、指示子によって表された要素の次の要素から、順番通りに継続されます。

int n[5] = {[4]=5,[0]=1,2,3,4} // 1,2,3,4,5 を保持します。
 
int a[MAX] = {
    1, 3, 5, 7, 9, [MAX-5] = 8, 6, 4, 2, 0
}
// MAX=6 の場合、 a は 1,8,6,4,2,0 を保持します。
// MAX=20 の場合、 a は 1,3,5,7,9,0,0,0,0,0,0,0,0,0,0,8,6,4,2,0 を保持します (「疎な配列」)。
(C99以上)

サイズが未知な配列を初期化するときは、初期化子が指定された最も大きな添字から、宣言中の配列のサイズが決定されます。

[編集] ネストした配列

配列の要素が配列、構造体、または共用体の場合、波括弧で囲まれた初期化子内の対応する初期化子は、それらのメンバに対して有効な任意の初期化子になりますが、ただし、波括弧は以下のように省略しても構いません。

ネストした初期化子が開き波括弧で始まる場合は、閉じ波括弧までのそのネストした初期化子全体が、対応する配列要素を初期化します。

int y[4][3] = { // int 3個の配列4個の配列 (4x3の行列)。
    { 1 },      // 0行目は {1, 0, 0} に初期化されます。
    { 0, 1 },   // 1行目は {0, 1, 0} に初期化されます。
    { [2]=1 },  // 2行目は {0, 0, 1} に初期化されます。
};              // 3行目は {0, 0, 0} に初期化されます。

ネストした初期化子が開き波括弧で始まらない場合は、リストから必要なだけの初期化子が、その部分配列、構造体、共用体の要素またはメンバのために、取られます。 残りの初期化子は次の配列要素を初期化するために残されます。

int y[4][3] = { // int 3個の配列4個の配列 (4x3の行列)。
1, 3, 5, 2, 4, 6, 3, 5, 7 // 0行目は {1, 3, 5} に初期化されます。
};                        // 1行目は {2, 4, 6} に初期化されます。
                          // 2行目は {3, 5, 7} に初期化されます。
                          // 3行目は {0, 0, 0} に初期化されます。
 
struct { int a[3], b; } w[] = { { 1 }, 2 }; // 構造体の配列。
   // { 1 } は配列の0番目の要素に対する波括弧で囲まれた初期化子として取られます。
   // 0番目の要素は { {1, 0, 0}, 0} に初期化されます。
   // 2 は配列の1番目の要素に対する最初の初期化子として取られます。
   // 1番目の要素は { {2, 0, 0}, 0} に初期化されます。

配列指示子はネストしても構いません。 ネストした配列のための角括弧で囲まれた定数式が外側の配列のための角括弧で囲まれた定数式の後に続きます。

int y[4][3] = {[0][0]=1, [1][1]=1, [2][0]=1};  // 0行目は {1, 0, 0} に初期化されます。
                                               // 1行目は {0, 1, 0} に初期化されます。
                                               // 2行目は {1, 0, 0} に初期化されます。
                                               // 3行目は {0, 0, 0} に初期化されます。
(C99以上)

[編集] ノート

配列の初期化子内の部分式の評価順序は C では不定に配列されます (C++ では C++11 以上ならそうではありません)。

int n = 1;
int a[2] = {n++, n++}; // 未規定ですが well-defined です。
                       // n は (不定な順序で) 2回インクリメントされます。
                       // a は {1, 2} に初期化されることも {2, 1} に初期化されることもあります。
puts((char[4]){'0'+n} + n++); // 未定義動作。
                              // n のインクリメントと n の読み込みは配列されません。

C では波括弧で囲まれた初期化子のリストは空にできません。 C++ では空のリストが使用できます。

int a[3] = {0}; // ブロックスコープの配列をゼロに初期化する C と C++ の両方で有効な方法。
int a[3] = {}; // ブロックスコープの配列をゼロに初期化する C++ では有効だけれども C では無効な方法。

他のすべての初期化と同様に、静的またはスレッドローカル記憶域期間の配列を初期化するときは、初期化子リスト内のすべての式は定数式でなければなりません。

static char* p[2] = {malloc(1), malloc(2)}; // エラー。

[編集]

int main(void)
{
    // 以下の4つの配列宣言は同じです。
    short q1[4][3][2] = {
        { 1 },
        { 2, 3 },
        { 4, 5, 6 }
    };
 
    short q2[4][3][2] = {1, 0, 0, 0, 0, 0, 2, 3, 0, 0, 0, 0, 4, 5, 6};
 
    short q3[4][3][2] = {
        {
            { 1 },
        },
        {
            { 2, 3 },
        },
        {
            { 4, 5 },
            { 6 },
        }
    };
 
    short q4[4][3][2] = {1, [1]=2, 3, [2]=4, 5, 6};
 
 
    // 指示子を用いて
    // 文字列を列挙定数に関連付けます。
    enum { RED, GREEN, BLUE };
    const char *nm[] = {
        [RED] = "red",
        [GREEN] = "green",
        [BLUE] = "blue",
    };
}


[編集] 参考文献

  • C11 standard (ISO/IEC 9899:2011):
  • 6.7.9/12-38 Initialization (p: 140-144)
  • C99 standard (ISO/IEC 9899:1999):
  • 6.7.8/12-38 Initialization (p: 126-130)
  • C89/C90 standard (ISO/IEC 9899:1990):
  • 6.5.7 Initialization