Namespaces
Variants

Array initialization

From cppreference.net

オブジェクトの 初期化 において、 配列 型のオブジェクトを初期化する場合、初期化子は 文字列リテラル (波括弧で囲んでもよい)であるか、または配列メンバーの初期化子を波括弧で囲んだリストでなければなりません:

= 文字列リテラル (1)
= { , ... } (2) (C99まで)
= { 指示子 (オプション) , ... } (2) (C99以降)
= { } (3) (C23以降)
1) 文字配列およびワイド文字配列の文字列リテラル初期化子
2) 配列要素の初期化子である 定数 (C99まで) 式のカンマ区切りリスト (オプションで [ 定数式 ] = 形式の配列指示子を使用可能) (C99以降)
3) 空の初期化子は配列のすべての要素を空初期化します

既知サイズの配列と未知サイズの配列は初期化できます (ただしVLAは除く) (C99以降) (C23以前) VLAは空初期化のみ可能です。 (C23以降)

明示的に初期化されていないすべての配列要素は 空初期化 されます。

目次

文字列からの初期化

String literal (オプションで中括弧で囲むことが可能)は、一致する型の配列の初期化子として使用できます:

  • 通常の文字列リテラル およびUTF-8文字列リテラル (C11以降) は任意の文字型の配列を初期化できます ( char , signed char , unsigned char )
  • Lプレフィックス付きワイド文字列リテラルは、(cv修飾子を無視して) wchar_t と互換性のある任意の型の配列の初期化に使用できます
  • u接頭辞付きワイド文字列リテラルは、(cv修飾を無視して)互換性のある任意の型の配列を初期化するために使用できます char16_t
  • U接頭辞付きワイド文字列リテラルは、(cv修飾を無視して)互換性のある任意の型の配列を初期化するために使用できます char32_t
(C11以降)

文字列リテラルの連続するバイト、またはワイド文字列リテラルのワイド文字(終端のnullバイト/文字を含む)が配列の要素を初期化します:

char str[] = "abc"; // strはchar[4]型を持ち、'a', 'b', 'c', '\0'を保持
wchar_t wstr[4] = L"猫"; // strはwchar_t[4]型を持ち、L'猫', '\0', '\0', '\0'を保持

配列のサイズが既知の場合、文字列リテラルのサイズより1少ない場合があり、その場合、終端のnull文字は無視されます:

char str[3] = "abc"; // strはchar[3]型を持ち、'a', 'b', 'c'を保持

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

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

配列が波括弧で囲まれた初期化子リストで初期化される場合、リスト内の最初の初期化子はインデックス0の配列要素を初期化します (指示子が指定されている場合を除く) (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[4] = {1}; // z は int[4] 型を持ち、1,0,0,0 を保持
int w[3] = {0}; // w は int[3] 型を持ち、すべてゼロを保持

既知のサイズを持つ配列を初期化する際、要素数よりも多くの初期化子を提供することはエラーです(文字配列を文字列リテラルから初期化する場合を除く)。

指示子は、その後に続く初期化子が指示子によって記述された配列要素を初期化するようにします。初期化はその後、指示子によって記述された要素の次の要素から順に前方へ続行されます。

int n[5] = {[4]=5,[0]=1,2,3,4}; // holds 1,2,3,4,5
int a[MAX] = { // starts initializing a[0] = 1, a[1] = 3, ...
    1, 3, 5, 7, 9, [MAX-5] = 8, 6, 4, 2, 0
};
// for MAX=6,  array holds 1,8,6,4,2,0
// for MAX=13, array holds 1,3,5,7,9,0,0,0,8,6,4,2,0 ("sparse array")
(C99以降)

未知のサイズの配列を初期化する場合、初期化子が指定されている最大の添字が宣言される配列のサイズを決定します。

ネストされた配列

配列の要素が配列、構造体、または共用体である場合、中括弧で囲まれた初期化子リスト内の対応する初期化子は、それらのメンバーに対して有効な任意の初期化子です。ただし、以下のように中括弧を省略することができます:

ネストされた初期化子が開きブレースで始まる場合、対応する配列要素はその閉じブレースまでのネストされた初期化子全体によって初期化されます:

int y[4][3] = { // 4つの3要素int配列の配列(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] = {    // 4つの3要素int配列の配列(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の完全ブレース初期化子と解釈
   // その要素は { {1, 0, 0}, 0} で初期化
   // 2 は配列の要素#1の最初の初期化子と解釈
   // その要素は { {2, 0, 0}, 0} で初期化

配列指示子はネスト可能です。ネストされた配列の角括弧内の定数式は、外側の配列の角括弧内の定数式に続きます:

int y[4][3] = {[0][0]=1, [1][1]=1, [2][0]=1};  // row 0 initialized to {1, 0, 0}
                                               // row 1 initialized to {0, 1, 0}
                                               // row 2 initialized to {1, 0, 0}
                                               // row 3 initialized to {0, 0, 0}
(C99以降)

注記

配列初期化子における部分式の 評価順序 は、C言語では不定シーケンスです(ただしC++11以降のC++では異なります):

int n = 1;
int a[2] = {n++, n++}; // 未規定だが明確に定義された動作
                       // nは2回インクリメントされる(順序は任意)
                       // aが{1, 2}と{2, 1}のどちらで初期化されても有効
puts((char[4]){'0'+n} + n++); // 未定義動作:
                              // nのインクリメントと読み取りが非順序付けされている

C言語では、初期化子の波括弧リストを空にすることはできません。C++では空のリストが許可されます:

(until C23)

空の初期化子を使用して配列を初期化できます:

(since C23)
int a[3] = {0}; // ブロックスコープ配列をゼロ初期化する有効なCおよびC++の方法
int a[3] = {}; // ブロックスコープ配列をゼロ初期化する有効なC++の方法;C23以降ではCでも有効

他のすべての initialization と同様に、staticまたはthread-localの storage duration を持つ配列を初期化する際には、初期化子リスト内の各式は constant expression でなければなりません:

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

参考文献

  • C17規格 (ISO/IEC 9899:2018):
  • 6.7.9/12-39 初期化 (p: 101-105)
  • C11規格 (ISO/IEC 9899:2011):
  • 6.7.9/12-38 初期化 (p: 140-144)
  • C99規格 (ISO/IEC 9899:1999):
  • 6.7.8/12-38 初期化 (p: 126-130)
  • C89/C90標準 (ISO/IEC 9899:1990):
  • 6.5.7 初期化