HOWTO · C
在 C 语言中将数组初始化为 0
本教程介绍了在 C 语言中初始化数组为 0 的不同方法。
本页内容
声明 int 数组时,使用 int values[5] = {0}; 可将每个元素初始化为零。C 会将第一个元素初始化为 0,并将聚合对象中其余未显式指定的元素也初始化为零。如果数组已经声明,则可用循环逐个赋值。memset 可以将数组的字节填充为零,但按字节填充不能普遍替代类型化初始化。
在声明时将数组初始化为零
如果在声明数组时已知其大小,可以使用初始化列表。下面的完整示例会打印这五个已初始化的值。
#include <stdio.h>
int main(void) {
int values[5] = {0};
for (size_t i = 0; i < sizeof values / sizeof values[0]; ++i) {
printf("%d%s", values[i], i == 4 ? "\n" : " ");
}
return 0;
}
0 0 0 0 0
{0} 初始化器会明确将第一个元素设为零;聚合初始化也会将省略的元素初始化为零。对于具有静态或线程存储期的对象,也可以省略初始化器:C 会自动将其初始化为零。普通的未初始化局部数组具有自动存储期,因此其元素不会自动设为零。读取元素前,请添加初始化器或先为元素赋值。
使用循环将数组初始化为零
如果数组已经声明,或者要在程序运行时确定元素值,循环就很有用。下面的完整示例以数组的元素个数作为循环上限,并打印结果。
#include <stdio.h>
int main(void) {
int values[5];
size_t count = sizeof values / sizeof values[0];
for (size_t i = 0; i < count; ++i) {
values[i] = 0;
}
for (size_t i = 0; i < count; ++i) {
printf("%d%s", values[i], i + 1 == count ? "\n" : " ");
}
return 0;
}
0 0 0 0 0
这里的 sizeof 表达式之所以可用,是因为 values 在同一作用域内是数组,而不是指针形参。如果将数组传给函数,应另外传入它的长度;在函数内部,数组形参会调整为指针,sizeof 得到的是指针的大小。
谨慎使用 memset()
标准库函数 memset 会在一段内存区域中写入相同的字节值。请包含 <string.h>,并像下面的完整示例一样使用 sizeof values 覆盖当前作用域内的整个数组。
#include <stdio.h>
#include <string.h>
int main(void) {
int values[5];
memset(values, 0, sizeof values);
for (size_t i = 0; i < sizeof values / sizeof values[0]; ++i) {
printf("%d%s", values[i], i == 4 ? "\n" : " ");
}
return 0;
}
0 0 0 0 0
第三个参数表示字节数,因此对这个数组而言,sizeof values 是正确的。memset 不会为每个元素赋予相应类型的值,而是写入全零位表示。只有当这种表示适用于元素类型和目标平台时,才应使用它。如果要在声明时以可移植的方式进行语义上的零初始化,优先使用 {0}。不要假设在所有 C 实现中,零字节都代表空指针或浮点零。
将数组初始化为非零值
在初始化列表中列出所需的值,例如 int values[] = {2, 4, 6};。C 会根据初始化值的数量推断最外层维度。对于多维数组,这种写法只能省略最外层维度:int grid[][3] = {{1, 2, 3}, {4, 5, 6}};;内层维度必须指定。
GNU 范围指示符(例如 int values[5] = {[0 ... 4] = 7};)是 GCC 扩展,并非可移植的标准 C 语法。若要兼顾不同 C 编译器的可移植性,请使用普通初始化列表或循环。在此函数上下文中,复合字面量(例如 (int[]){1, 2, 3})会创建一个未命名数组,其生命周期持续到所在代码块结束;它不是动态分配,也不能普遍替代命名数组的声明和初始化。