命名空间
变体
操作

数组初始化

来自 cppreference.com
< c‎ | 语言

初始化一个数组类型的对象时,初始化器必须是一个字符串字面量(可以选择用大括号括起来)或是一个用大括号括起来,用于初始化数组成员的列表。

= 字符串字面量 (1)
= { 表达式 , ... } (2) (直到C99)
= { 指定符(可选) 表达式 , ... } (2) (从C99开始)
= { } (3) (从C23开始)
1) 字符和宽字符数组的字符串字面量初始化器
2) 逗号分隔的常量(直到C99)表达式列表,这些表达式是数组元素的初始化器,可以选择使用形式为[ 常量表达式 ] = 的数组指定符(从C99开始)
3) 空初始化器会将数组的每个元素都进行空初始化

可以初始化已知大小的数组和未知大小的数组,但不能初始化VLA(从C99开始)(直到C23) VLA只能进行空初始化。(从C23开始)

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

内容

[编辑] 从字符串初始化

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

  • 普通字符串字面量和UTF-8字符串字面量(从C11开始)可以初始化任何字符类型( char, signed char, unsigned char)的数组。
  • 以L为前缀的宽字符串字面量可以用来初始化与(忽略cv限定符) wchar_t 兼容的任何类型。
  • 以u为前缀的宽字符串字面量可以用来初始化与(忽略cv限定符) char16_t 兼容的任何类型。
  • 以U为前缀的宽字符串字面量可以用来初始化与(忽略cv限定符) char32_t 兼容的任何类型。
(从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 初始化 (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 初始化