关于一个时髦的数组声明的问题

Question about a funky array declaration

本文关键字:数组 问题 声明 于一个      更新时间:2023-10-16

我刚刚遇到了这个数组声明:

const int nNums= 4;
int* nums[nNums] = {0, 0, 0}, d[nNums];

我知道正在创建指向nums的指针,但是右边的业务是什么?d[]被初始化,但我不太确定{0,0,0}做什么。

int* nums[nNums] = {0, 0, 0}定义了一个包含4个整型指针的数组,每个指针初始化为NULL。但是,注意d是一个由整型而不是整型指针组成的数组,并且这些值不会初始化。

该代码相当于:

const int nNums= 4;
int* nums[nNums] = {0, 0, 0};
int d[nNums];

因此,nums是一个长度为4的 int*s数组,所有四个元素初始化为null;d是一个长度为4的 ints数组,所有四个元素未初始化(再次强调,d没有以任何方式初始化)。

语法= {0, 0, 0}在这个上下文中被称为"聚合初始化",在c++ 03标准的第8.5.1节中描述。本规范的相关部分(§8.5.1/2)规定:

初始化聚合时,初始化项可以包含初始化子句,该初始化子句由一个用大括号括起来、逗号分隔的初始化子句列表组成,用于聚合的成员,以下标递增或成员顺序书写。如果聚合包含子聚合,则此规则递归地应用于子聚合的成员。

因此,nums的前三个元素显式初始化为0,第四个元素隐式地"value-initialized",如§8.5.1/7所述:

如果列表中的初始化式少于聚合中的成员数,则每个未显式初始化的成员都应进行值初始化。

值初始化在§8.5/5中描述:

value-initialize类型为T的对象意味着:

  • 如果T是具有用户声明构造函数的类类型,则调用T的默认构造函数(如果T没有可访问的默认构造函数,则初始化是错误的);
  • 如果T是一个没有用户声明构造函数的非联合类类型,那么T的每个非静态数据成员和基类组件都是值初始化的;
  • 如果T是数组类型,则每个元素都是值初始化的;
  • 否则,对象为零初始化

零初始化类型为T的对象意味着:

  • 如果T是标量类型,则该对象设置为0(零)转换为T的值;
  • 如果T是非联合类类型,则每个非静态数据成员和每个基类子对象都是零初始化的;
  • 如果T是联合类型,则对象的第一个命名数据成员为零初始化;
  • 如果T是数组类型,每个元素都是零初始化;
  • 如果T是引用类型,不初始化。

这导致nums的第四个元素也被初始化为null。

int* nums[nNums] = {0, 0, 0}, d[nNums];

正如@Asha已经说过的,nums是一个由4个整数指针组成的数组,每个指针初始化为NULL。

这里可以进一步问一个有趣的问题:变量d的类型是什么?

是一个4个整数指针的数组吗?

是一个包含4个整数的数组吗?

所以答案是:它是一个包含4个整数的数组。*只与第一个声明的符号nums相关联。

等价的声明是:

int* nums[nNums] = {0, 0, 0};
int d[nNums]; //not int* d[nNums];

为了避免这样的混淆,我倾向于将这样的声明写在多行上。如果您想在一行中声明,那么第二个声明会更好:

int*  nums[nNums] = {0, 0, 0}, d[nNums];  //old one!
int  *nums[nNums] = {0, 0, 0}, d[nNums];  //new one. note the position of *

>我理解指向nums的指针是创建

你理解错了。在该声明中没有创建"指向nums的指针"。声明

int* nums[4] = {0, 0, 0};

声明一个包含4个指针的数组。nums本身是一个数组,而不是指向任何对象的指针。

>但是右边的业务是什么?

= {0, 0, 0}部分称为"聚合初始化器"。它初始化nums数组的第一个树元素。不清楚为什么只有三个显式初始化(而第四个被隐式初始化为零)。同样,在c++中,

也可以达到同样的效果。
int* nums[4] = {};

声明,其中所有四个元素都隐式初始化为0

> d[]初始化

啊?不。d的声明相当于

int d[4];

表示根本不初始化d