目录
[一、Array 数组特点](#一、Array 数组特点)
[1.定义 array 对象](#1.定义 array 对象)
[三、向 array 对象中添加或删除元素](#三、向 array 对象中添加或删除元素)
[四、array 常用迭代器](#四、array 常用迭代器)
[五、array 常用运算符](#五、array 常用运算符)
[六、array 常用成员函数](#六、array 常用成员函数)
[2.empty 成员函数](#2.empty 成员函数)
[3.size 成员函数](#3.size 成员函数)
[4.front 成员函数](#4.front 成员函数)
[5.back 成员函数](#5.back 成员函数)
[6.fill 成员函数](#6.fill 成员函数)
[7.swap 成员函数](#7.swap 成员函数)
[七、array 与原生数组的比较](#七、array 与原生数组的比较)
[3.示例:array 与原生数组的对比](#3.示例:array 与原生数组的对比)
[1.练习 1:array 基本操作](#1.练习 1:array 基本操作)
[2.练习 2:使用 array 存储自定义类型](#2.练习 2:使用 array 存储自定义类型)
前言
C++11标准库中的array容器是一种固定大小的顺序容器,具有连续存储、高效性能和类型安全等特点。
它定义在<array>头文件中,大小在编译时确定,不能动态调整。array支持多种初始化方式(默认、列表、聚合、拷贝),提供丰富的迭代器类型(正向、反向、常量)和成员函数(at、empty、size、front、back、fill、swap)。相比原生数组,array具有类型安全、边界检查等优势,但大小固定。文章详细介绍了array的定义、初始化、元素修改、迭代器使用、运算符重载以及与原生数组的比较,并提供了两个综合练习示例。
一、Array 数组特点
array 是 C++11 引入的标准库容器,定义在 <array> 头文件中,位于 std 命名空间内。它是一种固定大小的顺序容器,具有以下特点:
- 固定大小 :在编译时确定大小,不能动态扩容或缩容
- 连续存储 :元素在内存中连续存储,支持快速随机访问
- 高效性能:性能与原生数组相当,同时提供了更多的成员函数和安全检查
- 与 STL 兼容:可以使用 STL 算法和迭代器
- 类型安全:提供了类型安全的接口,避免了原生数组的一些问题
它是有着固定大小用于保存一系列同类型元素的顺序容器 。因此不能对它进行增加或者删除 ,只能使用或者替换它的元素值。
二、定义及初始化
1.定义 array 对象
使用array,必须包含头文件<array>
cpp
#include <array> //使用array,在std命名空间
该类型被定义为一个类模板,在std命名空间中。
cpp
template<class T, std::size_t N>
class array;
cpp
#include <array>
// 定义一个包含 5 个 int 元素的 array
std::array<int, 5> arr;
// 定义一个包含 3 个 std::string 元素的 array
std::array<std::string, 3> strArr;
2.初始化方式
-
默认初始化:值初始化(对于内置类型,初始化为 0 或空)
cppstd::array<int, 5> arr; // 所有元素初始化为 0 std::array<std::string, 3> strArr; // 所有元素初始化为空字符串 -
列表初始化:
cppstd::array<int, 5> arr = {1, 2, 3, 4, 5}; std::array<int, 5> arr2{1, 2, 3, 4, 5}; // 与上面等价 -
聚合初始化:
cppstd::array<int, 5> arr = {1, 2, 3}; // 前三个元素初始化为 1, 2, 3,其余元素初始化为 0 -
拷贝初始化:
cppstd::array<int, 5> arr1 = {1, 2, 3, 4, 5}; std::array<int, 5> arr2 = arr1; // 拷贝初始化 std::array<int, 5> arr3(arr1); // 拷贝构造
三、向 array 对象中添加或删除元素
由于 array 是固定大小的容器,因此不能 像 vector 那样动态添加或删除元素。所有元素的存储空间在编译时就已经分配好了。
1.修改元素
虽然不能添加或删除元素,但可以修改现有元素的值:
cpp
#include <array>
std::array<int, 5> arr = {1, 2, 3, 4, 5};
// 通过下标修改元素
arr[0] = 10;
arr[1] = 20;
// 通过 at() 成员函数修改元素
arr.at(2) = 30;
// 通过迭代器修改元素
auto it = arr.begin();
*it = 100;
++it;
*it = 200;
四、array 常用迭代器
array 容器提供了多种迭代器类型,用于遍历容器中的元素:
|------------|-----------------------------|
| 迭代器 | 含义 |
| a.begin() | 第一个元素的迭代器 |
| a.end() | 最后一个元素的下一个位置迭代器(尾后迭代器或尾迭代器) |
| a.cbegin() | 第一个元素的常量迭代器(不修改元素内容) |
| a.cend() | 尾后常量迭代器(不修改元素内容) |
| a.rbegin() | 从后往前的第一个迭代器 |
| a.rend() | 从后往前的最后一个迭代器 |
使用示例:
cpp
std::array<int, 5> arr = {1, 2, 3, 4, 5};
// 使用正向迭代器遍历
for (auto it = arr.begin(); it != arr.end(); ++it) {
std::cout << *it << " "; // 输出: 1 2 3 4 5
}
std::cout << std::endl;
// 使用反向迭代器遍历
for (auto it = arr.rbegin(); it != arr.rend(); ++it) {
std::cout << *it << " "; // 输出: 5 4 3 2 1
}
std::cout << std::endl;
// 使用常量迭代器遍历(不能修改元素)
for (auto it = arr.cbegin(); it != arr.cend(); ++it) {
std::cout << *it << " "; // 输出: 1 2 3 4 5
// *it = 10; // 错误:常量迭代器不能修改元素
}
std::cout << std::endl;
五、array 常用运算符
array 类重载了多种运算符,方便容器操作:
-
赋值运算符:
=:将一个 array 赋值给另一个 array(要求大小相同)
cppstd::array<int, 5> arr1 = {1, 2, 3, 4, 5}; std::array<int, 5> arr2; arr2 = arr1; // arr2 现在包含 {1, 2, 3, 4, 5} -
比较运算符:
==:判断两个 array 是否相等!=:判断两个 array 是否不相等<:判断一个 array 是否小于另一个 array(字典序)<=:判断一个 array 是否小于或等于另一个 array>:判断一个 array 是否大于另一个 array>=:判断一个 array 是否大于或等于另一个 array
cppstd::array<int, 3> arr1 = {1, 2, 3}; std::array<int, 3> arr2 = {1, 2, 4}; bool b1 = (arr1 == arr2); // false bool b2 = (arr1 < arr2); // true(第三个元素 3 < 4) -
下标运算符:
[]:访问指定位置的元素(不进行边界检查)
cppstd::array<int, 5> arr = {10, 20, 30, 40, 50}; int x = arr[0]; // x = 10 arr[1] = 25; // arr 现在包含 {10, 25, 30, 40, 50}
六、array 常用成员函数
|----------------|-----------------------|
| array的成员函数 | 含义 |
| a.at() | 访问指定位置的元素 |
| a.empty() | 判断a是否为空,只能测试长度为0(不重要) |
| a.size() | 返回数组长度 |
| a.front() | 返回第一个元素的引用 |
| a.back() | 返回最后一个元素的引用 |
| a.fill(val) | 将val赋值给每个元素 |
| a.swap() | 交换两个array的值 |
1.at 成员函数
-
功能:访问指定位置的元素(进行边界检查)
-
参数:元素的索引位置
-
返回值:指定位置的元素的引用
-
异常 :如果索引超出范围,抛出
out_of_range异常std::array<int, 5> arr = {10, 20, 30, 40, 50};
int x = arr.at(0); // x = 10
arr.at(1) = 25; // arr 现在包含 {10, 25, 30, 40, 50}try {
x = arr.at(10); // 抛出 out_of_range 异常
} catch (const std::out_of_range& e) {
std::cout << "Exception: " << e.what() << std::endl;
}
2.empty 成员函数
- 功能:判断 array 是否为空
- 参数:无
- 返回值 :如果 array 为空返回
true,否则返回false - 说明 :对于非空大小的 array,始终返回
false
cpp
std::array<int, 0> emptyArr; // 空 array
std::array<int, 5> nonEmptyArr = {1, 2, 3, 4, 5};
std::cout << emptyArr.empty(); // 输出: 1 (true)
std::cout << nonEmptyArr.empty(); // 输出: 0 (false)
3.size 成员函数
- 功能:返回 array 中元素的个数
- 参数:无
- 返回值 :元素个数,类型为
size_t - 说明:返回的是编译时确定的大小,与初始化时的大小相同
cpp
std::array<int, 5> arr = {1, 2, 3, 4, 5};
std::cout << arr.size(); // 输出: 5
std::array<double, 10> dblArr;
std::cout << dblArr.size(); // 输出: 10
4.front 成员函数
- 功能:返回 array 中第一个元素的引用
- 参数:无
- 返回值:第一个元素的引用
- 说明:如果 array 为空,行为未定义
cpp
std::array<int, 5> arr = {1, 2, 3, 4, 5};
std::cout << arr.front(); // 输出: 1
arr.front() = 10; // arr 现在包含 {10, 2, 3, 4, 5}
5.back 成员函数
- 功能:返回 array 中最后一个元素的引用
- 参数:无
- 返回值:最后一个元素的引用
- 说明:如果 array 为空,行为未定义
cpp
std::array<int, 5> arr = {1, 2, 3, 4, 5};
std::cout << arr.back(); // 输出: 5
arr.back() = 50; // arr 现在包含 {1, 2, 3, 4, 50}
6.fill 成员函数
- 功能:用指定值填充 array 中的所有元素
- 参数:要填充的值
- 返回值:无
cpp
std::array<int, 5> arr = {1, 2, 3, 4, 5};
arr.fill(0); // arr 现在包含 {0, 0, 0, 0, 0}
std::array<std::string, 3> strArr;
strArr.fill("hello"); // strArr 现在包含 {"hello", "hello", "hello"}
7.swap 成员函数
-
功能:交换两个 array 的内容
-
参数:另一个 array 对象(必须与当前 array 大小相同)
-
返回值:无
std::array<int, 3> arr1 = {1, 2, 3};
std::array<int, 3> arr2 = {4, 5, 6};arr1.swap(arr2); // arr1 现在包含 {4, 5, 6},arr2 现在包含 {1, 2, 3}
七、array 与原生数组的比较
1.优势
- 类型安全 :
array是一个模板类,提供了类型安全的接口 - 边界检查 :
at()成员函数提供了边界检查 - STL 兼容:可以使用 STL 算法和迭代器
- 大小信息 :通过
size()成员函数可以获取大小 - 赋值操作:支持直接赋值,而原生数组不支持
2.劣势
- 大小固定:编译时确定大小,不能动态调整
- 稍微的性能开销:相比原生数组,有轻微的性能开销(通常可以忽略)
3.示例:array 与原生数组的对比
cpp
#include <iostream>
#include <array>
#include <algorithm>
int main() {
// 原生数组
int nativeArr[5] = {5, 2, 8, 1, 9};
// array 容器
std::array<int, 5> arr = {5, 2, 8, 1, 9};
// 原生数组的大小需要使用 sizeof 计算
std::cout << "Native array size: " << sizeof(nativeArr) / sizeof(nativeArr[0]) << std::endl;
// array 容器直接通过 size() 获取大小
std::cout << "Array container size: " << arr.size() << std::endl;
// 原生数组不能直接赋值
// int anotherNativeArr[5];
// anotherNativeArr = nativeArr; // 错误
// array 容器可以直接赋值
std::array<int, 5> anotherArr;
anotherArr = arr;
// 都可以使用范围 for 循环
std::cout << "Native array elements: ";
for (int x : nativeArr) {
std::cout << x << " ";
}
std::cout << std::endl;
std::cout << "Array container elements: ";
for (int x : arr) {
std::cout << x << " ";
}
std::cout << std::endl;
// 都可以使用 STL 算法
std::sort(nativeArr, nativeArr + 5);
std::sort(arr.begin(), arr.end());
std::cout << "Sorted native array: ";
for (int x : nativeArr) {
std::cout << x << " ";
}
std::cout << std::endl;
std::cout << "Sorted array container: ";
for (int x : arr) {
std::cout << x << " ";
}
std::cout << std::endl;
return 0;
}
八、综合练习
1.练习 1:array 基本操作
cpp
#include <iostream>
#include <array>
int main() {
// 创建并初始化 array
std::array<int, 5> arr = {1, 2, 3, 4, 5};
// 输出原始 array
std::cout << "Original array: ";
for (int x : arr) {
std::cout << x << " ";
}
std::cout << std::endl;
// 修改元素
arr[0] = 10;
arr.at(1) = 20;
arr.back() = 50;
// 输出修改后的 array
std::cout << "Modified array: ";
for (int x : arr) {
std::cout << x << " ";
}
std::cout << std::endl;
// 使用 fill 填充
arr.fill(99);
// 输出填充后的 array
std::cout << "After fill: ";
for (int x : arr) {
std::cout << x << " ";
}
std::cout << std::endl;
// 创建另一个 array 并交换
std::array<int, 5> arr2 = {100, 200, 300, 400, 500};
arr.swap(arr2);
// 输出交换后的 array
std::cout << "After swap - arr: ";
for (int x : arr) {
std::cout << x << " ";
}
std::cout << std::endl;
std::cout << "After swap - arr2: ";
for (int x : arr2) {
std::cout << x << " ";
}
std::cout << std::endl;
// 输出 array 信息
std::cout << "Size: " << arr.size() << std::endl;
std::cout << "Empty: " << (arr.empty() ? "Yes" : "No") << std::endl;
std::cout << "Front: " << arr.front() << std::endl;
std::cout << "Back: " << arr.back() << std::endl;
return 0;
}
2.练习 2:使用 array 存储自定义类型
cpp
#include <iostream>
#include <array>
#include <string>
class Person {
public:
std::string name;
int age;
Person(std::string n = "", int a = 0) : name(n), age(a) {}
void display() const {
std::cout << "Name: " << name << ", Age: " << age << std::endl;
}
};
int main() {
// 创建存储 Person 对象的 array
std::array<Person, 3> people = {
Person("Alice", 25),
Person("Bob", 30),
Person("Charlie", 35)
};
// 遍历并显示所有元素
std::cout << "All people: " << std::endl;
for (const auto& person : people) {
person.display();
}
// 修改元素
people[0].name = "Alicia";
people.at(1).age = 31;
// 显示修改后的元素
std::cout << "\nAfter modification: " << std::endl;
for (const auto& person : people) {
person.display();
}
// 使用 fill 填充
people.fill(Person("Unknown", 0));
// 显示填充后的元素
std::cout << "\nAfter fill: " << std::endl;
for (const auto& person : people) {
person.display();
}
return 0;
}