第五节 · 瓶子与漏水防护 · 数组库与再探原生数组
我们已经学习了 vector,它是 C++ 中最常用的动态数组。但有时候,我们确实知道数组的大小,而且不需要动态改变它。这时候,C++11 引入的 std::array 可能是更好的选择。
同时,理解原生数组的细节,对于深入理解 C++ 也是非常必要的。
std::array
std::array 是对原生数组的封装,它的大小在编译时确定,不能改变:
#include <array>
#include <iostream>
using namespace std;
int main()
{
// 声明一个包含 5 个整数的 array
array<int, 5> arr = {1, 2, 3, 4, 5};
// 访问元素
cout << arr[0] << endl; // 1
cout << arr.at(1) << endl; // 2(带边界检查)
// 获取大小
cout << arr.size() << endl; // 5
// 遍历
for (int x : arr)
{
cout << x << " ";
}
cout << endl;
return 0;
}array vs 原生数组
std::array 的优势:
知道自己的大小:
arr2.size()返回 5,而原生数组不能这样。可以赋值和比较:
array支持=、==、<等运算符。支持迭代器:可以使用
begin()、end()等。更安全:
at()方法有边界检查。可以作为函数返回值:原生数组不能直接返回。
再探原生数组
虽然 vector 和 array 更加安全和方便,但理解原生数组仍然很重要,因为:
很多旧代码使用原生数组
与 C 语言交互时需要用到
理解底层原理有助于写出更好的代码
数组名是指向首元素的指针
但要注意,数组名和指针并不完全相同:
字符数组与 C 风格字符串
C 风格字符串就是以空字符 \0 结尾的字符数组:
C 风格字符串的危险之处在于容易越界:
这就是为什么我们更推荐使用 std::string。
数组作为函数参数
当数组作为函数参数时,会退化为指针:
以下三种声明方式是等价的:
使用 std::array 可以避免这个问题:
多维数组
多维数组在内存中是连续存储的,按行优先顺序:
多维数组作为参数
使用指针遍历数组
这种模式与标准库容器的迭代器非常相似,这也是 C++ 设计迭代器时参考的原型。
C++11 提供了 std::begin() 和 std::end() 函数,可以用于原生数组:
总结对比
大小
编译时确定
编译时确定
运行时可变
内存位置
栈或静态区
栈或静态区
堆
边界检查
无
at() 有
at() 有
赋值
不支持
支持
支持
作为参数
退化为指针
保持类型
保持类型
作为返回值
不能
可以
可以
选择建议:
大小固定且已知:优先使用
std::array大小动态变化:使用
std::vector与 C 代码交互:可能需要使用原生数组
习题
使用
std::array存储一周七天的名称,并遍历输出。编写一个函数,接收一个原生整数数组和它的大小,返回数组中的最大值。
使用二维数组实现一个简单的井字棋棋盘,并编写函数打印棋盘状态。
Last updated