C.中的数组初始化

Array initialisation in C

本文关键字:初始化 数组      更新时间:2023-10-16

我对以下代码有疑问:

int main()
{
    int array1 = {1,2,3,4,5}; //error in c++ , warning in c
    int array2[] = {1,2,3,4,5};
    int array3[5] = {1,2,3,4,5};
}

这段代码在c++中的第3行出现错误,但在c中没有?

我知道array1实际上是一个intarray2array3是数组,那么为什么c编译器不显示错误,而只是一个警告:"标量初始化中的多余元素"

有没有使用这样的定义?为什么它在c中有效?

无效C。参见C11 6.7.9:

任何初始值设定项都不应试图为对象提供值包含在正在初始化的实体中。

我猜你在使用gcc。然后,如果你想让你的程序表现得像严格的标准C,那么就这样编译它:

gcc -std=c11 -pedantic-errors

给出

错误:标量初始值设定项中的元素过多

它在C中无效。它只是对代码的检查较少。这是未定义的行为。

来源:C11草案N1570;6.7.9 初始化

限制
2初始化器不得试图为不包含在被初始化实体内的对象提供值
3待初始化实体的类型应为未知大小的数组或非可变长度数组类型的完整对象类型。

绝对打破了约束2。int完整对象类型吗?

来自附件J.2(未定义行为):

标量的初始值设定项既不是单个表达式,也不是用大括号括起来的单个表达式(6.7.9)

额外:
@James Kanze:

prog.c:4:12: error: expected identifier or ‘(’ before numeric constant
  int i = 1,2,3,4,5;
            ^

你可以做到,但你需要让它成为一个表达式:

int i = (1,2,3,4,5); //need parenthesis, evaluates to 5, values 1-4 thrown away.

使用用初始化器列表初始化的int编译会引发警告(在gcc中):

prog.c:5:2: warning: excess elements in scalar initializer [enabled by default]
  int j = {1,2,3,4,5};
  ^

但编译器似乎足够聪明,只初始化int,而不初始化后面的内存。demo

根据C规范,它是有效的。

引用C11第6.7.9节(初始化):

语法

1 initializer:
    assignment-expression
    { initializer-list }
    { initializer-list , }

因此,初始值设定项可以是直接表达式(上面的assignment-expression),也可以是用大括号括起来的初始值设定值列表。该标准中该部分的约束并不限制"正常"(非数组或非指针)变量。

这允许您编写例如

int a = { 1 };

和其他人一样,我认为您想知道的行是:

int array1 = {1,2,3,4,5};

在这种情况下,C和C++之间没有区别;这句话在两种语言中都可以说是合法的,但它并不是你想的那样。在C和C++中,都有一个语句,大意是如果类型是标量类型(int是),则{...}的内容必须是单个表达式。并且1,2,3,4,5可以被解释为单个表达式(使用逗号运算符);类似于:

int array1 = 1, 2, 3, 4, 5;

显然是合法的。

然而,这有点模棱两可,因为在这两种语言中,这种初始化类型的语法使,成为标点符号,而不是运算符。因此,这是一个解释问题;是内容必须是单个表达式的语句,是对语法的约束(这将导致逗号变成运算符),或是对指定语法的求值结果的约束。我的直觉是,第二个是意图,这个陈述应该会导致错误。但区别不在于C和C++之间,而在于编译器的作者解释标准的方式之间。

编辑:

再仔细阅读一下:在C++标准中,它明确表示

如果T是标量类型,则形式为
的声明

T x={a};

相当于

T x=a;

这并没有留下太多的回旋余地:在C++中,这种说法显然是合法的;只有在C中才有一些歧义。

在C/C++中初始化数组的正确方法是:

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

在这里,方括号实际上通知编译器这是一个数组,在您的情况下是一组数字。在这种初始化方式中,不需要指定数组的长度。编译器会知道的。

第二种方法是定义一个数组并对其进行后初始化:

int array3[5];
int *array = new int[5];

在这种情况下,您需要通知编译器数组的大小。此外,在第二种情况下,需要手动删除内存。

正如编译器所说,这对C来说也是不正确的。这里需要注意的重要一点是,在出现这种"违反约束"(官方术语)的情况下,编译器可能只会产生一个诊断(编译器就是这样做的)并继续。

这就是为什么您通常应该确保您的代码在编译时没有任何诊断。

C是一种低级的允许性语言

它允许影响指向内部的指针。
int array1 = {1,2,3,4,5};

编辑:

在写愚蠢的东西之前,我应该在不同的编译器下测试它。

MSVC(2008)认为这是一个错误。

gcc和clang都会发出警告excess elements in scalar initializer,并且只影响1到a