查看以下代码:
int arr[4];
for (int index = 0; index < 4; ++index) {
printf("%dt", arr[index]);
}
它打印随机值,如下所示:
27224 -6784 32766 0
但是当我arr
设置为{}
时,它会打印零。
int arr[4] = {};
for (int index = 0; index < 4; ++index) {
printf("%dt", arr[index]);
}
0 0 0 0
为什么?
默认情况下,数组元素是未初始化的,这意味着它们将包含垃圾值:
int arr[4];
使用大括号初始值设定项,您可以显式设置初始值,例如
int arr[4] = {1, 2, 3, 4};
但是,如果大括号中的数字数小于数组的长度,则其余数字用零填充。这就是在这种情况下发生的事情:
int arr[4] = {};
请注意,这在 C 中无效,仅在 C++ 中有效,但您的编译器显然无论如何都允许它。在标准 C 中,必须至少写入一个值:
int arr[4] = {0};
当我在编译器(gcc 9.3)中尝试您的代码时,它会发出以下警告:
prog_c.c:14:12: warning: ISO C forbids empty initializer braces [-Wpedantic]
14 | int arr[4]={};
我认为它认为这相当于int arr[4]={a_single_value};
但没有这个单一值(这是不正确的)。
当您为少于 元素,则语言认为缺少的元素是 设置为零。
在您不正确的情况下,我想编译器应用相同的规则 对于所有元素。
您的{}
初始化被视为部分初始化 的数组。
这两个代码片段都无效。
在第一个代码片段中,数组具有自动存储持续时间,并且未初始化。所以它的元素具有不确定的值。因此,程序具有未定义的行为。
在第二个代码片段中,使用了无效的构造来初始化数组
int arr[4] = {};
您不能在 C 中使用空大括号(尽管它在 C++ 中有效)。此构造可以是 C 的特定编译器扩展。正确的初始化如下所示
int arr[4] = { 0 };
当初始化少于初始化元素的数量时,没有显式初始值设定项的元素初始化为零。
来自 C 标准(6.7.9 初始化)
21 如果大括号括起来的列表中的初始值设定项少于 是聚合的元素或成员,或 字符串文字,用于初始化已知大小的数组,而不是那里 是数组中的元素,聚合的其余部分应为 隐式初始化与具有静态存储的对象相同 期间。
和
10 如果具有自动存储持续时间的对象未初始化 明确地说,它的值是不确定的。如果对象具有静态 或线程存储持续时间未显式初始化,则:
— 如果它具有指针类型,则将其初始化为空指针;
— 如果它具有算术类型,则初始化为 (正或 无符号)零;
— 如果它是一个聚合,则初始化每个成员(递归) 根据这些规则,任何填充都初始化为零位;
— 如果是联合,则初始化第一个命名成员 (递归)根据这些规则,并且初始化任何填充 到零位;
因此,在此声明中,数组的第一个元素由 0 显式初始化,数组的所有其他元素由编译器使用 0 隐式初始化。
在 C 中这样的初始化
int arr[4] = { 0 };
等效于以下初始化形式
int arr[4] = { [0] = 0 };
或例如以下形式
int arr[4] = { [3] = 0 };
或者您甚至可以省略数组声明中的元素数量,例如
int arr[] = { [3] = 0 };
也就是说,所有没有显式初始值设定项的元素都将为零初始化。
代码
int arr[4];
为四个整数的数组(在堆栈上)分配内存,但不初始化它。你得到的输出只是内存中发生的一切的表示 - 实际上是随机的。
int arr[4] = {}
指示编译器将所有值设置为零。
你可以把
int arr[4] = {1,2,3,4}
初始化为特定值
通过声明int arr [4]
,您只是在创建一个引用。由于从未为其赋值,因此此引用指向的值不会更改。这是因为 C 是一种显式语言。因此,那里的值是内存 arr[4] 正在使用的先前保存的任何值。
通过声明int arr[4] = {};
,您将数组显式设置为等于某些内容。这将清除使用 arr[4] 引用的内存,并将其设置为等于值 {}。由于 {} 中没有任何值,因此C++将其默认为 0。
看起来您正在运行一个可以编译 C 和 C++ 代码的 IDE。这就是为什么它默认为 0。C 比 C++ 更明确,因此对于 C 代码,您必须将值放在括号中,例如int arr[4] = {1, 2, 3, 4};
希望对您有所帮助!