C++ 数组是什么?
一个普通变量一次只能保存一个值。比如想要保存整数 10,我们可以这样写:
int a = 10;如果现在需要保存 10、20、30、40、50 这 5 个整数,应该怎么做呢?很多初学的小伙伴可能会写出下面这段代码:
int a = 10;
int b = 20;
int c = 30;
int d = 40;
int e = 50;写完之后你会发现,这种方式实在太繁琐了。要是需要保存几十个甚至上百个整数,总不能给每一个数都单独起一个变量名,那样光起名字就够头疼了。
为了解决这个问题,C++ 提供了 “数组(array)”。简单来说,数组就是用来按顺序保存一组 “相同类型” 数据的容器。数组中的每一个数据称为一个 “元素”,所有元素在内存中都是挨着连续存放的。
回到上面的需求,如果我们使用数组来保存这 5 个整数,只需要一行代码就可以搞定:
int arr[5] = {10, 20, 30, 40, 50};上面这行代码定义了一个名为 arr 的整型数组,并在创建的同时使用花括号 {} 一次性存入了 5 个整数。这样一来,原本零散的多个数据就被整齐地收纳到了同一个名字下面。
C++ 数组的声明
在 C++ 中,我们可以按照下面的语法格式来声明一个数组。
语法:
数据类型 数组名[数组长度];说明:
数组声明语句主要由以下 3 个部分组成:
- 数据类型:指定数组中存放的元素是什么类型,比如
int表示存放整数,double表示存放双精度浮点数,char表示存放字符。同一个数组中所有元素的类型必须相同。 - 数组名:数组的名称,命名规则与变量完全一致,平时尽量取有意义的名字。
- 数组长度:中括号
[]里的数字,表示数组中一共可以存放多少个元素。
比如下面这几行代码,分别声明了不同元素类型的数组:
int arr[5]; // 可存放 5 个整数
double prices[3]; // 可存放 3 个浮点数
char grades[4]; // 可存放 4 个字符在声明 C++ 数组时,小伙伴们需要注意以下两点。
第一,数组的长度一旦确定就不能再改变,而且中括号里的长度必须是在编译阶段就能确定的正整数。也就是说,我们不能拿普通变量作为数组长度,但可以使用 const 常量:
const int size = 5;
int n = 5;
// 正确方式
int arr1[5];
int arr2[size];
// 错误方式
int arr3[n];上面代码中,size 是通过 const 定义的常量,它的值在编译阶段就已经固定为 5,因此 int arr2[size]; 是合法的。而 n 是普通变量,在标准 C++ 中写成 int arr3[n]; 会引发编译报错。
提示 在使用 g++ 编译时,写成 int arr[n]; 有时也能通过编译,但这属于编译器的非标准扩展,换到 Visual Studio 等环境下就会直接报错。为了保证代码通用,平时指定数组长度时统一使用具体的正整数或 const 常量即可。
第二,在 main() 函数内部只声明数组而没有赋初始值时,C++ 不会自动把里面的元素清零,此时每个元素里存放的都是不确定的随机 “垃圾值”。因此,只声明但未赋值的数组元素千万不要直接读取。
平时创建数组时,我们通常会在声明后面直接加上 = {10, 20, 30} 这样的花括号列表赋好初始值,更多写法我们会在下一节 “C++ 数组初始化” 中展开介绍。
访问数组元素
在 C++ 中,如果我们想要读取数组中的某一个元素,需要通过 “数组下标”(也叫 “索引”)来实现。
语法:
数组名[下标]说明:
需要特别注意的是,C++ 数组的下标是从 0 开始计算的,而不是从 1 开始的。也就是说,第 1 个元素的下标是 0,第 2 个元素的下标是 1,以此类推。
为什么下标要从 0 算起呢?你可以把下标理解成 “当前元素距离第 1 个元素隔了几个位置”:第 1 个元素就在起点,隔了 0 个位置,因此写成 arr[0]。第 2 个元素隔了 1 个位置,因此写成 arr[1]。
以长度为 5 的整型数组 int arr[5] 为例,各个元素位置与下标的对应关系如下表所示。
| 元素位置 | 数组下标 | 访问写法 |
|---|---|---|
| 第 1 个元素 | 0 | arr[0] |
| 第 2 个元素 | 1 | arr[1] |
| 第 3 个元素 | 2 | arr[2] |
| 第 4 个元素 | 3 | arr[3] |
| 第 5 个元素 | 4 | arr[4] |
看到这里,初学的小伙伴可能会把两种中括号 [] 搞混。其实只需要记住这么一个规律:如果 [] 出现在 “声明数组” 时,里面的数字表示数组长度。如果出现在后续 “使用数组” 时,里面的数字则表示元素下标。
比如 int arr[5] 中的 5 出现在声明语句里,表示数组一共能放 5 个元素。而后面代码里的 arr[2] 则是访问下标为 2 的元素,也就是第 3 个元素。
示例 1:访问数组元素
#include <iostream>
int main() {
int arr[5] = {12, 24, 36, 48, 60};
std::cout << "第 1 个元素:" << arr[0] << '\n';
std::cout << "第 3 个元素:" << arr[2] << '\n';
std::cout << "第 5 个元素:" << arr[4] << '\n';
return 0;
}运行结果如下。
第 1 个元素:12
第 3 个元素:36
第 5 个元素:60分析:
在这个例子中,我们定义了一个包含 5 个整数的数组 arr。由于下标从 0 开始计算,输出时 arr[0] 获取的是第 1 个元素 12,arr[2] 获取的是第 3 个元素 36,而 arr[4] 获取的是第 5 个元素 60,对应关系如下图所示。

修改数组元素
学会了读取数组元素的值,如果想要给声明好的数组元素赋值,或者修改某个元素原有的值,应该怎么做呢?其实同样是通过数组下标来实现的。
语法:
数组名[下标] = 新值;说明:
数组中的每一个元素,使用起来就跟一个普通变量一模一样。我们既可以给已有初值的元素重新赋值来覆盖旧值,也可以在声明数组后通过下标逐个为元素赋值,还可以直接拿数组元素参与加减乘除运算。
示例 2:修改数组元素的值
#include <iostream>
int main() {
int arr[5] = {12, 24, 36, 48, 60};
arr[1] = 100; // 修改第 2 个元素
arr[2] = 200; // 修改第 3 个元素
std::cout << arr[1] << '\n';
std::cout << arr[2] << '\n';
return 0;
}运行结果如下。
100
200分析:
arr[1] = 100; 表示将下标为 1 的第 2 个元素重新赋值为 100,原来的旧值 24 就被覆盖成了 100。同理,arr[2] = 200; 会将第 3 个元素从原来的 36 修改为 200。
在下面代码中,arr[0] 的最终值是 50,小伙伴们可以思考一下为什么。
int arr[3] = {10, 20, 30};
arr[0] = arr[1] + arr[2];除了修改已有初值的元素之外,如果在创建数组时暂时还不知道具体数据,也可以先声明固定长度的数组,随后再通过下标逐个赋值。下面我们来看一个例子。
示例 3:先声明后逐个赋值
#include <iostream>
int main() {
double scores[3]; // 先声明长度为 3 的数组
scores[0] = 88.5;
scores[1] = 92.5;
scores[2] = 96.5;
std::cout << scores[0] << '\n';
std::cout << scores[1] << '\n';
std::cout << scores[2] << '\n';
return 0;
}运行结果如下。
88.5
92.5
96.5分析:
在这个例子中,我们先通过 double scores[3]; 声明了一个可存放 3 个双精度浮点数的数组。虽然刚声明完时里面是随机垃圾值,但只要在读取之前通过 scores[0]、scores[1]、scores[2] 赋予确定的值,后面就可以正常读取使用了。
C++ 数组下标越界
由于数组下标是从 0 开始计算的,所以数组的最大合法下标总是比数组长度小 1,也就是 “数组长度 - 1”。比如对于长度为 5 的数组 arr[5],合法的下标范围是 0 ~ 4,我们最大只能访问到 arr[4]。
如果在代码中访问 arr[5] 甚至更大的下标,或者使用了负数下标,就会超出数组的有效范围,这种错误称为 “数组下标越界”。下面这种写法就是错误的:
int arr[5] = {12, 24, 36, 48, 60};
std::cout << arr[5]; // 下标越界为什么访问 arr[5] 是错误的呢?因为下标从 0 算起,arr[5] 指的是第 6 个元素,而数组 arr 一共只有 5 个元素,根本不存在第 6 个元素。
需要特别注意的是,C++ 编译器在编译阶段通常不会检查数组下标越界。一旦程序运行时发生了越界读写,就会访问到不属于这个数组的内存区域,轻则打印出莫名其妙的乱码数字,重则直接导致程序崩溃。因此大家平时操作数组时,一定要确保下标处在合法范围内。
