名前空間
変種
操作

配列の初期化

From cppreference.com
< c‎ | language

初期化するオブジェクトが配列型の場合、初期化子は文字列リテラル(オプションで中括弧で囲む)または配列メンバ用の初期化子の、中括弧で囲まれたリストのいずれかでなければなりません。

= string-literal (1)
= { expression , ... } (2) (C99まで)
= { designator(optional) expression , ... } (2) (C99以降)
= { } (3) (C23以降)
1) 文字配列およびワイド文字配列用の文字列リテラル初期化子
2) 配列要素の初期化子である、コンマ区切りの(オプションで[ constant-expression ] = の形式の配列指定子を使用する)定数(C99まで)式、(C99以降)(C99以降)
3) 空の初期化子。配列のすべての要素を空初期化します。

サイズが既知の配列およびサイズが不明の配列は初期化できますが、VLAは初期化できません(C99以降、C23まで(C99以降)(C23まで))。VLAは空初期化のみ可能です。(C23以降)

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

目次

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

文字列リテラル(オプションで中括弧で囲む)は、一致する型の配列の初期化子として使用できます。

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

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

char str[] = "abc"; // str has type char[4] and holds 'a', 'b', 'c', '\0'
wchar_t wstr[4] = L"猫"; // str has type wchar_t[4] and holds L'猫', '\0', '\0', '\0'

配列のサイズがわかっている場合、配列のサイズは文字列リテラルのサイズより1つ少なくすることができます。この場合、終端のヌル文字は無視されます。

char str[3] = "abc"; // str has type char[3] and holds 'a', 'b', 'c'

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

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

配列を中括弧で囲まれた初期化子のリストで初期化する場合、リストの最初の初期化子はインデックスゼロの配列要素を初期化します(指定子がない場合(C99以降))。指定子がない後続の初期化子は、前の初期化子によって初期化された要素のインデックスよりも1つ大きいインデックスの配列要素を初期化します(指定子がない場合(C99以降))。

int x[] = {1,2,3}; // x has type int[3] and holds 1,2,3
int y[5] = {1,2,3}; // y has type int[5] and holds 1,2,3,0,0
int z[4] = {1}; // z has type int[4] and holds 1,0,0,0
int w[3] = {0}; // w has type int[3] and holds all zeroes

サイズが既知の配列を初期化する際に、要素数を超える初期化子を指定することはエラーです(文字列リテラルから文字配列を初期化する場合を除く)。

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

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] = { // array of 4 arrays of 3 ints each (4x3 matrix)
    { 1 },      // row 0 initialized to {1, 0, 0}
    { 0, 1 },   // row 1 initialized to {0, 1, 0}
    { [2]=1 },  // row 2 initialized to {0, 0, 1}
};              // row 3 initialized to {0, 0, 0}

ネストされた初期化子が開中括弧で始まらない場合、サブ配列、構造体、または共用体の要素またはメンバを考慮するためにリストから十分な初期化子のみが取得されます。残りの初期化子は、次の配列要素の初期化のために残されます。

int y[4][3] = {    // array of 4 arrays of 3 ints each (4x3 matrix)
1, 3, 5, 2, 4, 6, 3, 5, 7 // row 0 initialized to {1, 3, 5}
};                        // row 1 initialized to {2, 4, 6}
                          // row 2 initialized to {3, 5, 7}
                          // row 3 initialized to {0, 0, 0}
 
struct { int a[3], b; } w[] = { { 1 }, 2 }; // array of structs
   // { 1 } is taken to be a fully-braced initializer for element #0 of the array
   // that element is initialized to { {1, 0, 0}, 0}
   // 2 is taken to be the first initialized for element #1 of the array
   // that element is initialized { {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++}; // unspecified, but well-defined behavior,
                       // n is incremented twice (in arbitrary order)
                       // a initialized to {1, 2} and to {2, 1} are both valid
puts((char[4]){'0'+n} + n++); // undefined behavior:
                              // increment and read from n are unsequenced

Cでは、初期化子の中括弧リストは空にできません。C++は空リストを許可します。

(C23まで)

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

(C23以降)
int a[3] = {0}; // valid C and C++ way to zero-out a block-scope array
int a[3] = {}; // valid C++ way to zero-out a block-scope array; valid in C since C23

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

static char* p[2] = {malloc(1), malloc(2)}; // error

[編集]

int main(void)
{
    // The following four array declarations are the same
    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};
 
 
    // Character names can be associated with enumeration constants
    // using arrays with designators:
    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 Initialization
English 日本語 中文(简体) 中文(繁體)