Cpp学习21 std::array、C风格数组
对于 constexpr 数组,请使用 std::array; 对于非 constexpr 数组,请使用 std::vector 。
1 | std::array<int, 5> a {}; // a std::array of 5 ints |
非常量变量和运行时常量不能用于长度。
std::array 是一个聚合类型,使用聚合初始化进行初始化。
如果初始化列表中提供的初始化器数量少于定义的数组长度,则剩余的未初始化元素将进行值初始化。
尽可能将 std::array 定义为 constexpr。如果 std::array 不是 constexpr,请考虑改用 std::vector 。
std::array 的长度和索引
std::array 的长度和索引的类型为 size_type ,它始终为 std::size_t。
获取长度的方法有 arr.size(), std::size() 和 std::ssize() 三种。
为了在存在 constexpr 索引时进行编译时边界检查,我们可以使用 std::get() 函数模板,该模板接受索引作为非类型模板参数。
1 | std::cout << std::get<3>(prime); |
传递和返回 std::array
1 | template <typename T, std::size_t N> // note that this template parameter declaration matches the one for std::array |
自动非类型模板参数 C++20,略。所以说,能写类型的地方都可以考虑auto啊。
当数组不大或者对性能没要求时,可以按值返回std::array;
用 输出参数 :通过非常量引用or地址传入数组,然后在函数里修改。
类类型的 std::array 和大括号省略
std::array 的元素可以是任何对象类型,包括复合类型。(这么强?
1 | struct House |
简写(省略元素类型名,增加一层大括号):
1 | constexpr std::array<House, 3> houses { // initializer for houses |
通过 std::reference_wrapper 处理引用数组
1 | int x { 1 }; |
std::ref() 和 std::cref() 函数作为快捷方式,用于创建 std::reference_wrapper 和 const std::reference_wrapper 包装的对象。请注意,这些函数可以与 auto 一起使用,从而避免显式指定模板参数。
std::array 和枚举
基于范围的 for 循环不允许您遍历枚举的枚举值,最直接的解决方案之一是创建一个包含所有枚举值的 constexpr std::array ,然后遍历该数组。
C 风格数组
1 | int testScore[30] {}; |
应用于 C 风格的数组时, sizeof() 返回整个数组使用的字节数。
std::size() 和 std::ssize() 都是可以用的。
C 风格的数组不支持赋值。
赋值要求左操作数是可修改的左值,而 C 风格的数组不被认为是可修改的左值。
1 | int arr[] { 1, 2, 3 }; // okay: initialization is fine |
C 风格的数组退化
当在表达式中使用 C 风格的数组时,数组会被隐式转换为指向元素类型的指针,并用第一个元素的地址(索引为 0)进行初始化。通俗地说,这被称为数组衰减 (或简称衰减 )。
1 | void printElementZero(const int arr[]) // treated the same as const int* |
尽量避免使用 C 风格的数组。
- 对于只读字符串(字符串字面量、符号常量和字符串参数),建议使用
std::string_view。 - 对于可修改的字符串,建议使用
std::string。 - 对于非全局 constexpr 数组,建议使用
std::array。 - 对于非条件数组,建议使用
std::vector。
对于全局 constexpr 数组,使用 C 风格的数组是可以的。我们稍后会讨论这一点。
在现代 C++ 中,C 风格的数组通常在以下两种情况下使用:
- 用于存储 constexpr 全局(或 constexpr 静态局部)程序数据。由于此类数组可直接从程序中的任何位置访问,因此无需传递数组本身,从而避免了与数据衰减相关的问题。定义 C 风格数组的语法比
std::array更简洁。更重要的是,此类数组的索引不存在像标准库容器类那样的符号转换问题。 - 对于需要直接处理 non-constexpr C 风格字符串参数(而不是需要转换为
std::string_view)的函数或类,这样做有两个可能的原因:- 首先,将 non-constexpr C 风格字符串转换为
std::string_view需要遍历该 C 风格字符串以确定其长度。如果该函数位于性能关键代码段,并且不需要长度信息(例如,因为该函数无论如何都会遍历字符串),那么避免转换可能很有用。 - 其次,如果该函数(或类)调用其他需要 C 风格字符串的函数,那么仅仅为了转换而转换为
std::string_view可能并非最佳选择(除非您有其他需要使用std::string_view原因)。
- 首先,将 non-constexpr C 风格字符串转换为
指针运算和下标
给定一个指针 ptr , ptr + 1 返回内存中 下一个对象 的地址(基于指针指向的类型)。
下标运算 ptr[n] 的简洁语法等价于更冗长的表达式 *((ptr) + (n)) 。
*(ptr-1)返回内存中的 前一个对象 , 等效于 ptr[-1]。
从数组开头(元素 0)开始索引时,最好使用下标,这样数组索引就可以与元素对齐。
从给定元素进行相对定位时,优先使用指针运算。
C-style strings
1 | char str1[8]{}; // an array of 8 char, indices 0 through 7 |
输出 C 风格字符串时, std::cout 会一直输出字符,直到遇到空终止符为止。空终止符标记字符串的结尾,因此即使是丢失了长度信息的字符串也能被打印出来。
在现代 C++ 中,存储用户输入的文本时,使用 std::string 更安全,因为 std::string 会自动调整以容纳所需的字符数。
std::strlen() 速度很慢,因为它必须遍历整个数组,计算字符数,直到遇到空终止符为止。
C 风格的字符串符号常量
在现代 C++ 中,几乎没有理由使用 C 风格的字符串符号常量。相反,应该优先使用 constexpr std::string_view 对象,它们通常速度一样快(甚至更快),而且行为更加一致。
多维 C 风格数组
数组的维度是指选择元素所需的索引数量。仅包含一个维度的数组称为一维数组 (有时缩写为 1d 数组 )。
数组的数组称为二维数组 (有时缩写为 2d 数组 ),因为它有两个下标。
1 | int array[3][5] |
不允许省略非最左侧的尺寸
多维 std::array
把 std::array 嵌套起来。
1 | std::array<std::array<int, 4>, 3> arr {{ // note double braces |
对应的模版函数
1 | template <typename T, std::size_t Row, std::size_t Col> |
很显然这个类型名太长了,可以用别名模板来简化。
1 |
|
三维的:
1 | template <typename T, std::size_t Row, std::size_t Col, std::size_t Depth> |
用函数模板获取长度
1 | // Fetch the number of rows from the Row non-type template parameter |
std::mdspan 是在 C++23 中引入的,它是一个可修改的视图,为连续的元素序列提供了一个多维数组接口。
- 标题: Cpp学习21 std::array、C风格数组
- 作者: 铁名_IronName
- 创建于 : 2026-08-13 13:41:13
- 更新于 : 2026-08-13 16:54:29
- 链接: https://blog.ironname.top/2026/Cpp/Cpp学习21/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。