C++ 数组

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,对应关系如下图所示。

数组从 0 开始的下标与元素位置对应关系

修改数组元素

学会了读取数组元素的值,如果想要给声明好的数组元素赋值,或者修改某个元素原有的值,应该怎么做呢?其实同样是通过数组下标来实现的。

语法:

数组名[下标] = 新值;

说明:

数组中的每一个元素,使用起来就跟一个普通变量一模一样。我们既可以给已有初值的元素重新赋值来覆盖旧值,也可以在声明数组后通过下标逐个为元素赋值,还可以直接拿数组元素参与加减乘除运算。

示例 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++ 编译器在编译阶段通常不会检查数组下标越界。一旦程序运行时发生了越界读写,就会访问到不属于这个数组的内存区域,轻则打印出莫名其妙的乱码数字,重则直接导致程序崩溃。因此大家平时操作数组时,一定要确保下标处在合法范围内。

常见问题

1. 能不能直接使用 std::cout << arr; 把整个数组的元素打印出来?

不能。如果直接写 std::cout << arr,屏幕上并不会输出数组里的各个元素,而是会打印出一串类似 0x61fe00 的内存地址。想要把数组里的所有元素依次打印出来,我们需要配合循环按顺序逐个访问,后面讲到遍历数组时会详细介绍。

2. 中括号 “[]” 也是一种运算符,这个说法正确吗?

这个说法是正确的。前面学习运算符优先级时我们提到过,() 和 [] 其实都属于 C++ 运算符,并且它们的优先级排在最高的一档。其中 [] 叫做 “下标运算符”,专门用来指定访问数组中的哪一个元素。

上一篇:

下一篇:

给站长反馈

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

邮箱:lvyenet@vip.qq.com

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