命名空间
变体
操作

数组初始化

来自 cppreference.cn
< c‎ | 语言

当初始化数组类型的对象时,初始化器必须是字符串字面量(可选地用花括号括起来)或用花括号括起来的数组元素初始化列表

= string-literal (1)
= { expression , ... } (2) (直到 C99)
= { designator(optional) expression , ... } (2) (自 C99 起)
= { } (3) (自 C23 起)
1) 字符和宽字符数组的字符串字面量初始化器
2) 逗号分隔的常量表达式列表,它们是数组元素的初始化器,可选地使用形式为 [ constant-expression ] = (自 C99 起)
3) 空初始化器将数组的每个元素都进行空初始化

已知大小的数组和未知大小的数组都可以初始化,但 VLA 除外(自 C99 起)(直到 C23) VLA 只能进行空初始化。(自 C23 起)

所有未显式初始化的数组元素都将被空初始化

目录

[编辑] 从字符串初始化

字符串字面量(可选地用花括号括起来)可以用作匹配类型的数组的初始化器

  • 普通字符串字面量和 UTF-8 字符串字面量(自 C11 起)可以初始化任何字符类型的数组 (char, signed char, unsigned 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 起),而每个后续的没有指示符(自 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++ 中不是,自 C++11 起)

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 初始化 (页码: 101-105)
  • C11 标准 (ISO/IEC 9899:2011)
  • 6.7.9/12-38 初始化 (页码: 140-144)
  • C99 标准 (ISO/IEC 9899:1999)
  • 6.7.8/12-38 初始化 (页码: 126-130)
  • C89/C90 标准 (ISO/IEC 9899:1990)
  • 6.5.7 初始化