创建数组时,如果在声明的同时直接为里面的元素赋好初始值,就叫做 “数组初始化”。
如果先声明数组,再通过下标一个个赋值,写起来会比较繁琐。直接在声明数组时完成初始化,不仅代码更简短,还能避免未赋值带来的随机 “垃圾值” 问题。
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 容器,它用起来会比原生数组灵活得多。
