C 参考手册
- C 语言
- C 的历史
- 基本概念
- 表达式
- 声明
- 初始化
- 函数
- 语句
- 静态断言
- 字符常量
- 函数声明
- 函数定义
- 转义序列
- 翻译阶段
- 标识符
- 作用域
- 生存期
- 查找与命名空间
- ASCII 码表
- 类型
- 遵从性
- 算术类型
- restrict 类型限定符
- 类型
- 对象与对齐
- 主函数
- 未定义行为
- 内存模型
- if 语句
- switch 语句
- for 循环
- while 循环
- do-while 循环
- continue语句
- break 语句
- goto语句
- return 语句
- 值类别
- 求值顺序
- 整数常量
- 浮点常量
- 字符串字面量
- 复合字面量
- 常量表达式
- 隐式转换
- 成员访问运算符
- 逻辑运算符
- 比较运算符
- 算术运算符
- 赋值运算符
- 自增/自减运算符
- 其他运算符
- sizeof 运算符
- _Alignof 运算符
- 转型运算符
- C 运算符优先级
- 泛型选择
- 标量初始化
- 数组初始化
- 结构体与联合体初始化
- 指针声明
- 数组声明
- 枚举
- 存储类指定符
- const 类型限定符
- volatile 类型限定符
- 结构体声明
- 联合体声明
- 位域
- _Alignas
- typedef 声明
- 原子类型
- 外部及试探性定义
- inline 函数指定符
- _Noreturn 函数指定符
- 变长参数
- 内联汇编
- 可分析性
- 替用运算符及记号
- C 关键词
- 预处理器
- C 标准库头文件
- 类型支持
- 程序支持工具
- 变参数函数
- 错误处理
- 动态内存管理
- 日期和时间工具
- 字符串库
- 算法
- 数值
- 文件输入/输出
- 本地化支持
- 原子操作库
- 线程支持库
- 实验性 C 标准库
- 有用的资源
- 符号索引
- 注释
数组初始化
初始化数组类型的对象时,初始化器必须是一个字符串字面量(可选地在花括号中),或是一个花括号环绕的被初始化数组成员列表:
= string_literal
|
(1) | ||||||||
= { expression , ... }
|
(2) | (C99 前) (C99 起) | |||||||
[
constant-expression ]
=
的数组指代器 (C99 起)可初始化已知大小的数组和未知大小的数组,但不可初始化 VLA (C99 起)。
任何未被显示初始化的数组元素,被以与拥有静态存储期的对象相同方式隐式初始化。
从字符串初始化
字符串字面量(可选地在花括号中)可以用作匹配数组类型的初始化器:
- 通常字符串字面量及 UTF-8 字符串字面量 (C11 起)可用于初始化任何字符类型( char 、 signed char 、 unsigned char )的数组。
- L 前缀的宽字符串字面量可用于初始化任何与 wchar_t 兼容(忽略 cv 限定)的类型的数组。
|
(C11 起) |
字符串字面量的连续字节,或宽字符串字面量的连续宽字符,包含空终止字节/字符,会初始化数组的元素:
char str[] = "abc"; // str 拥有类型 char[4] 并保有 'a', 'b', 'c', '\0' wchar_t wstr[4] = L"猫"; // wstr 拥有类型 wchar_t[4] 并保有 L'猫', L'\0', L'\0', L'\0'
若数组大小已知,则它可以比字符串字面量的大小少一,此情况下空终止字符被忽略:
char str[3] = "abc"; // str 拥有类型 char[3] 并保有 'a', 'b', 'c'
注意这种数组的内容是可更改的,不像直接以 char* str = "abc"; 访问字符串常量。
从花括号环绕列表初始化
当数组以花括号环绕的初始化器列表初始化时,首个初始化器初始化序号为零的数组元素(除非指定了指代器) (C99 起),而每个不含指代器的 (C99 起)后继的初始化器所初始化的数组元素,序号比前一个初始化器所初始化的多一。
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] 并保有全零
在初始化已知大小数组时,提供多于元素数量的初始化器是错误(除了从字符串字面量初始化字符数组)。
指代器导致接下来的初始化器初始化指代器所描述的数组元素。然后初始化以向前顺序持续,从指代器所描述元素的下一个元素开始。 int n[5] = {[4]=5,[0]=1,2,3,4} // 保有 1,2,3,4,5 int a[MAX] = { // 开始初始化 a[0] = 1, a[1] = 3, ... 1, 3, 5, 7, 9, [MAX-5] = 8, 6, 4, 2, 0 } // 对于 MAX=6 ,数组保有 1,8,6,4,2,0 // 对于 MAX=13 ,数组保有 1,3,5,7,9,0,0,0,8,6,4,2,0(“稀疏数组”) |
(C99 起) |
在初始化未知大小的数组时,指定初始化器的最大下标会确定所声明的数组大小。
嵌套数组
若数组的元素是数组、结构体或联合体,则对应的花括号环绕的初始化器列表中的初始化器是任何对于那些成员合法的初始化器,除了它们的花括号可以按如下方式省略:
若嵌套初始化器从左花括号开始,则整个直到其右花括号为止的初始化器初始化对应的数组元素:
int y[4][3] = { // 4 个 3 个 int 的数组的数组( 4*3 矩阵) { 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 的数组的数组( 4*3 矩阵) 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}; // 0 行初始化为 {1, 0, 0} // 1 行初始化为 {0, 1, 0} // 2 行初始化为 {1, 0, 0} // 3 行初始化为 {0, 0, 0} |
(C99 起) |
注意
数组初始化器中的子表达式求值顺序在 C 中是不定序的(但在从 C++11 开始的 C++ 中不是):
int n = 1; int a[2] = {n++, n++}; // 未指定,但是是良好定义行为, // n 自增二次(以任意顺序) // a 初始化为 {1, 2} 和为 {2, 1} 均合法 puts((char[4]){'0'+n} + n++); // 未定义行为: // n 的自增和读取是无序的
在 C 中,初始化器的花括号列表不能为空。 C++ 允许空列表:
int a[3] = {0}; // C 与 C++ 中均为清零块作用域数组的合法途径 int a[3] = {}; // C 中非法但在 C++ 中合法的清零块作用域数组的途径
与所有其他初始化一样,在初始化静态或线程局域存储期的数组时,初始化器列表中的每个表达式都必须是常量表达式:
示例
int main(void) { // 下列四个数组的声明是相同的 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):
- 3.5.7/12- Initialization