第五节 · 瓶子与漏水防护 · 数组库与再探原生数组

我们已经学习了 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 的优势:

  1. 知道自己的大小arr2.size() 返回 5,而原生数组不能这样。

  2. 可以赋值和比较array 支持 ===< 等运算符。

  3. 支持迭代器:可以使用 begin()end() 等。

  4. 更安全at() 方法有边界检查。

  5. 可以作为函数返回值:原生数组不能直接返回。


再探原生数组

虽然 vectorarray 更加安全和方便,但理解原生数组仍然很重要,因为:

  1. 很多旧代码使用原生数组

  2. 与 C 语言交互时需要用到

  3. 理解底层原理有助于写出更好的代码

数组名是指向首元素的指针

但要注意,数组名和指针并不完全相同:

字符数组与 C 风格字符串

C 风格字符串就是以空字符 \0 结尾的字符数组:

C 风格字符串的危险之处在于容易越界:

这就是为什么我们更推荐使用 std::string


数组作为函数参数

当数组作为函数参数时,会退化为指针:

以下三种声明方式是等价的:

使用 std::array 可以避免这个问题:


多维数组

多维数组在内存中是连续存储的,按行优先顺序:

多维数组作为参数


使用指针遍历数组

这种模式与标准库容器的迭代器非常相似,这也是 C++ 设计迭代器时参考的原型。

C++11 提供了 std::begin()std::end() 函数,可以用于原生数组:


总结对比

特性
原生数组
std::array
std::vector

大小

编译时确定

编译时确定

运行时可变

内存位置

栈或静态区

栈或静态区

边界检查

at() 有

at() 有

赋值

不支持

支持

支持

作为参数

退化为指针

保持类型

保持类型

作为返回值

不能

可以

可以

选择建议:

  • 大小固定且已知:优先使用 std::array

  • 大小动态变化:使用 std::vector

  • 与 C 代码交互:可能需要使用原生数组


习题

  • 使用 std::array 存储一周七天的名称,并遍历输出。

  • 编写一个函数,接收一个原生整数数组和它的大小,返回数组中的最大值。

  • 使用二维数组实现一个简单的井字棋棋盘,并编写函数打印棋盘状态。

Last updated