C++ 数组初始化

创建数组时,如果在声明的同时直接为里面的元素赋好初始值,就叫做 “数组初始化”。

如果先声明数组,再通过下标一个个赋值,写起来会比较繁琐。直接在声明数组时完成初始化,不仅代码更简短,还能避免未赋值带来的随机 “垃圾值” 问题。

C++ 数组初始化语法

在 C++ 中,最基本的数组初始化方式是在声明数组后面加上等号 =,并使用花括号 {} 将各个元素的初始值依次括起来。

语法:

数据类型 数组名[数组长度] = {元素1, 元素2, ..., 元素n};

说明:

花括号 {} 内部的各个初始值之间使用英文逗号(,)隔开。编译器会按照从左到右的顺序,将它们依次赋给下标为 0、1、2……的数组元素。

需要注意的是,花括号内的初始值必须与数组的数据类型相匹配,不能往 int 数组里塞入小数 3.14 这样会丢失精度的值。同时,初始值的个数也不能超过 [] 中声明的数组长度。下面这两种写法都会引发编译报错:

int arr1[3] = {10, 20, 3.14};      // 类型不匹配
int arr2[3] = {10, 20, 30, 40};    // 超出声明长度

注意 在 Python、JavaScript 等语言中通常使用中括号 [] 来写列表或数组,而 C++ 数组在初始化时必须使用花括号 {} 括起来,小伙伴们不要写混了。

示例 1:完整初始化数组

#include <iostream>

int main() {
    int arr[5] = {10, 20, 30, 40, 50};

    std::cout << arr[0] << '\n';
    std::cout << arr[2] << '\n';
    std::cout << arr[4] << '\n';
    return 0;
}

运行结果如下。

10
30
50

分析:

int arr[5] = {10, 20, 30, 40, 50}; 表示定义一个长度为 5 的整型数组,并按顺序将 10、20、30、40、50 分别存入 arr[0] 到 arr[4] 中。

从 C++11 标准开始,使用花括号初始化数组时还可以省略中间的等号 =。对于上面这个例子来说,下面 2 种方式是等价的:

// 方式 1(推荐)
int arr[5] = {10, 20, 30, 40, 50};

// 方式 2
int arr[5]{10, 20, 30, 40, 50};

在实际开发中给数组提供具体的初值列表时,我们更推荐使用方式 1,保留等号 = 读起来更加直观。如果你在阅读别人写的代码时遇到方式 2,知道它们的效果完全一样就可以了。

部分初始化与全 0 初始化

在初始化数组时,花括号 {} 里并不一定非要把所有元素的值全部写满。在实际开发中,我们经常会用到 “部分初始化” 和 “全 0 初始化” 这两种写法。

1. 部分初始化

在 C++ 中,我们可以只给数组的前几个元素提供初始值。当花括号 {} 内初始值的个数少于数组长度时,后面未指定的剩余元素会自动初始化为 0。

示例 2:部分初始化数组

#include <iostream>

int main() {
    int arr[4] = {12, 24};

    std::cout << arr[0] << '\n';
    std::cout << arr[1] << '\n';
    std::cout << arr[2] << '\n';
    std::cout << arr[3] << '\n';
    return 0;
}

运行结果如下。

12
24
0
0

分析:

在这个例子中,数组 arr 的长度声明为 4,但花括号里只给出了 2 个初始值。这 2 个值会按顺序赋给前两个元素 arr[0] 和 arr[1],后面没写出来的 arr[2] 和 arr[3] 则自动补 0。

因此对于这个例子来说,下面 2 种方式是等价的:

// 方式 1
int arr[4] = {12, 24};

// 方式 2
int arr[4] = {12, 24, 0, 0};

2. 全 0 初始化

如果在创建数组时暂时还没有具体数据,希望先把所有元素全部清零以避免残留随机的垃圾值,我们只需要在等号后面写上一对空花括号 {} 就可以了。

示例 3:全 0 初始化数组

#include <iostream>

int main() {
    int arr[5] = {};

    std::cout << arr[0] << '\n';
    std::cout << arr[4] << '\n';
    return 0;
}

运行结果如下。

0
0

分析:

int arr[5] = {}; 会将整型数组中的 5 个元素全部初始化为 0,平时也可以省略等号写成 int arr[5]{}。如果换作 double 类型的浮点数数组,空花括号 {} 则会将每个元素初始化为 0.0。

在早期代码中,大家也常写成 int arr[5] = {0}; 来清零。结合刚刚学过的部分初始化规则其实很好理解:{0} 先把第 1 个元素设为 0,后面没写出来的 4 个元素又会自动补 0,结果自然也是全部为 0。

到这里可能有些小伙伴会问:“既然写 {0} 能让整个数组变成 0,那写 {1} 是不是也能让 5 个元素全部变成 1 呢?” 实际上,这样理解是不正确的:

int arr1[5] = {};     // 全部元素为 0
int arr2[5] = {0};    // 全部元素为 0
int arr3[5] = {1};    // 仅第 1 个元素为 1

按照部分初始化规则,int arr3[5] = {1}; 只会把第 1 个元素 arr3[0] 设为 1,后面未指定的 4 个元素依然是自动补 0,最终得到的是 {1, 0, 0, 0, 0}。

另外大家还要把 int arr[5] = {}; 和 int arr[5]; 区分清楚:前者是把所有元素清零,而后者没有初始化,里面装的是随机垃圾值,平时写代码时不要搞混了。

省略数组长度

如果在声明数组的同时已经列出了所有元素的初始值,我们还可以把中括号 [] 里的数字省略掉,让编译器根据花括号内元素的个数自动推算数组长度。

语法:

数据类型 数组名[] = {元素1, 元素2, ..., 元素n};

说明:

当省略中括号 [] 里的数字时,花括号 {} 里写了几个初始值,数组的长度就是几。需要注意的是,这只是让编译器帮我们数了一下初始元素的个数,数组一旦创建完成,它的长度同样是固定不变的。

示例 4:省略数组长度

#include <iostream>

int main() {
    double prices[] = {12.5, 8.8, 19.9};

    std::cout << prices[0] << '\n';
    std::cout << prices[1] << '\n';
    std::cout << prices[2] << '\n';
    return 0;
}

运行结果如下。

12.5
8.8
19.9

分析:

在这个例子中,我们在花括号里写了 3 个浮点数,编译器会自动数出元素个数并将 prices 的长度确定为 3,等价于写成 double prices[3] = {12.5, 8.8, 19.9}。

当初始元素较多且省略了 [] 里的数字时,后续我们可以调用 std::size() 函数自动获取数组长度,下一节就会具体介绍。

在实际开发中,什么时候适合省略长度,什么时候必须写出长度呢?我们可以按下面 2 种情况来区分:

  • 推荐省略长度的场景:当创建数组时已经明确列出了全部初始元素,直接写成 int arr[] = {10, 20, 30} 即可。这样既不用自己去数元素个数,后续增删初始元素时也不用回头修改 [] 里的数字。
  • 必须写出长度的场景:当需要预先指定固定容量时,比如做全 0 初始化 int arr[100] = {}、部分初始化,或者只声明数组暂不赋初值时,必须在 [] 中显式写出数组长度。

另外要注意,如果既省略了 [] 里的数组长度,又没有在后面提供初始值,编译器不知道应该分配多大的内存空间,就会直接报错:

int arr[];    // 缺少数组长度与初始值

不能整体重新赋值与复制

操作普通变量时,我们可以先声明变量 a,随后再写 a = 10 赋值,也可以直接写 int b = a 把它的值复制给 b。

很多初学的小伙伴会把这套习惯照搬到数组上,结果一编译就报错。在使用 C++ 原生数组时,有以下 2 条语法限制需要特别留意:

  • 不能先声明再整体赋值:花括号 {} 初值列表只能在声明数组的同时使用。声明结束后,不能再写 arr = {10, 20, 30} 给整个数组重新赋值,只能通过下标逐个修改元素。
  • 不能直接复制整个数组:C++ 原生数组不支持整体直接复制,不能写成 int arr2[3] = arr1 把一个数组直接赋给另一个数组。

也就是说,下面这两种写法都是无法通过编译的:

int arr[3];
arr = {10, 20, 30};    // 不能先声明再整体赋值

int arr1[3] = {10, 20, 30};
int arr2[3] = arr1;    // 不能直接复制整个数组

如果在实际开发中确实需要整体重新赋值,或者直接把整组数据复制给另一个容器,可以使用后面章节学习的 vector 容器,它用起来会比原生数组灵活得多。

上一篇:

下一篇:

给站长反馈

绿叶网正在不断完善中,小伙伴们如果发现任何问题,还望多多给站长反馈,谢谢!

邮箱:lvyenet@vip.qq.com

「绿叶网」服务号
绿叶网服务号放大
关注服务号,微信也能看教程。
绿叶网服务号