C语言中"int arr[] = {}"和"int arr[]"的区别

The difference of "int arr[] = {}" and "int arr[]" in C

看下面的代码:

int arr[4];
for (int index = 0; index < 4; ++index) {
    printf("%d\t", arr[index]);
}

它打印随机值,像这样:

27224   -6784   32766   0   

但是当我将 arr 设置为 {} 时,它会打印零。

int arr[4] = {};
for (int index = 0; index < 4; ++index) {
    printf("%d\t", arr[index]);
}
0   0   0   0   

为什么?

默认情况下,数组元素未初始化,这意味着它们将包含垃圾值:

int arr[4];

使用大括号初始化器,您可以显式设置初始值,例如

int arr[4] = {1, 2, 3, 4};

但是如果大括号中的数字个数小于数组的长度,则其余用零补齐。这就是这种情况下发生的事情:

int arr[4] = {};

请注意,这在 C 中是 not valid,仅在 C++ 中,但您的编译器显然仍然允许这样做。在标准C中,至少要写一个值:

int arr[4] = {0};

代码

int arr[4];

为四个整数的数组(在堆栈上)分配内存但不对其进行初始化。您得到的输出只是内存中发生的任何内容的表示 - 实际上是随机的。

int arr[4] = {}

指示编译器将所有值设置为零。

或者你可以把

int arr[4]  = {1,2,3,4}

初始化为特定值

当我在我的编译器 (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}; 但是 没有 这个单一值(这是不正确的)。
当您为少于元素总数的元素提供初始值时 数组中的元素,则语言认为缺少的元素是 设为零。
在你的 incorrect 案例中,我猜编译器应用相同的规则 对于所有元素。
您的 {} 初始化被视为部分初始化 数组的。

这两个代码片段都无效。

在第一个代码片段中,数组具有自动存储持续时间并且未初始化。所以它的元素有不确定的值。因此,该程序具有未定义的行为。

在第二个代码片段中,使用了无效的结构来初始化数组

int arr[4] = {};

您不能在 C 中使用空括号(尽管它在 C++ 中有效)。这个构造可以是 C 的特定编译器扩展。正确的初始化看起来像

int arr[4] = { 0 };

当初始化次数少于已初始化元素的数量时,没有显式初始化程序的元素将被零初始化。

来自C标准(6.7.9初始化)

21 If there are fewer initializers in a brace-enclosed list than there are elements or members of an aggregate, or fewer characters in a string literal used to initialize an array of known size than there are elements in the array, the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration.

10 If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate. If an object that has static or thread storage duration is not initialized explicitly, then:

— if it has pointer type, it is initialized to a null pointer;

— if it has arithmetic type, it is initialized to (positive or unsigned) zero;

— if it is an aggregate, every member is initialized (recursively) according to these rules, and any padding is initialized to zero bits;

— if it is a union, the first named member is initialized (recursively) according to these rules, and any padding is initialized to zero bits;

因此在此声明中,数组的第一个元素由 0 显式初始化,数组的所有其他元素由编译器隐式初始化为 0。

在C中这样的初始化

int arr[4] = { 0 };

相当于下面的初始化形式

int arr[4] = { [0] = 0 };

或者例如下面的形式

int arr[4] = { [3] = 0 };

或者您甚至可以省略数组声明中的元素数量,例如

int arr[] = { [3] = 0 };

也就是说,所有没有显式初始化器的元素都将被零初始化。

通过声明 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};

希望对您有所帮助!