C++ 数组
C++ 数组与容器
Section titled “C++ 数组与容器”数组是基本的数据结构,用于在连续的内存位置存储同类型元素的集合。C++ 提供了几种处理类似数组结构的方式,每种方式都有其独特的特性。
1. 内置的 C 风格数组
Section titled “1. 内置的 C 风格数组”这是从 C 语言继承来的传统数组。它存储固定大小的顺序元素集合。
声明 (Declaration):
Section titled “声明 (Declaration):”指定元素类型、数组名称和大小(必须是编译时常量):
type arrayName[arraySize];示例:声明一个名为 scores 的数组,用于存储 10 个整数。
int scores[10];初始化 (Initialization):
Section titled “初始化 (Initialization):”你可以在声明时使用花括号初始化 {} 来初始化 C 风格数组:
double balance[5] = {1000.0, 2.0, 3.4, 7.0, 50.0};
// 如果初始化时提供元素,可以省略大小;编译器会推断大小int values[] = {1, 2, 3, 4};
// 初始化前几个元素(其余元素对于静态/全局数组会零初始化,对于局部数组值不确定)float readings[100] = {1.1f, 2.2f};访问元素 (Accessing Elements):
Section titled “访问元素 (Accessing Elements):”使用数组名称后跟方括号 [] 中的索引来访问元素。数组索引是零基的(zero-based),这意味着第一个元素位于索引 0,最后一个元素位于索引 arraySize - 1。
balance[0] = 1200.0; // 改变第一个元素double thirdBalance = balance[2]; // 访问第三个元素(索引 2)
// 重要提示:访问超出边界(例如 balance[5] 或 balance[-1])// 会导致未定义行为 (Undefined Behavior) - 这是一个常见且危险的错误!内存布局 (Memory Layout):
Section titled “内存布局 (Memory Layout):”C 风格数组的元素在内存中是连续存储的。对于 double balance[5],内存看起来像这样:[balance[0]][balance[1]][balance[2]][balance[3]][balance[4]]。
C 风格数组的局限性 (Limitations of C-style Arrays):
Section titled “C 风格数组的局限性 (Limitations of C-style Arrays):”- 大小固定 (Fixed Size): 大小必须在编译时已知,并且不能更改。
- 无边界检查 (No Bounds Checking): 访问超出有效索引范围的元素虽然能编译通过,但在运行时会导致未定义行为 (Undefined Behavior)。
- 指针衰减 (Pointer Decay): 当传递给函数时,它们通常会“衰减”为指向第一个元素的指针,从而丢失了大小信息。
- 没有成员函数 (No Member Functions): 它们没有像获取大小或检查是否为空等有用的方法。
由于这些局限性,现代 C++ 强烈推荐使用标准库容器,例如 std::array 和 std::vector。
2. std::array (C++11 及更高版本)
Section titled “2. std::array (C++11 及更高版本)”std::array 是一个封装了固定大小数组的容器。它提供了 C 风格数组的效率和内存布局,同时具备标准容器的优点。
声明与初始化 (Declaration & Initialization):
Section titled “声明与初始化 (Declaration & Initialization):”包含 <array> 头文件。将类型和大小指定为模板参数。
#include <array>
std::array<int, 5> myArray = {1, 2, 3, 4, 5};std::array<double, 3> temps; // 元素未初始化(与 C 风格局部数组类似)std::array<char, 10> name{}; // 对元素进行值初始化(对于 char 为 0)访问元素与特性 (Accessing Elements & Features):
Section titled “访问元素与特性 (Accessing Elements & Features):”- 方括号访问
[]:myArray[0](无边界检查)。 at()成员函数:myArray.at(1)(提供边界检查;如果索引无效则抛出std::out_of_range异常)。size()成员函数:myArray.size()返回大小(编译时常量)。- 迭代器 (Iterators): 支持迭代器 (
begin(),end()),可用于标准算法和范围 for 循环 (range-based for loops)。 front()/back(): 访问首元素/尾元素。empty(): 检查大小是否为零(即是否为空)。data(): 返回指向底层 C 风格数组的指针。
当你需要一个通常分配在栈上的固定大小数组时,使用 std::array。
3. std::vector
Section titled “3. std::vector”std::vector 是一个动态数组。它在堆上管理其存储,允许在运行时增长或收缩大小。
声明与初始化 (Declaration & Initialization):
Section titled “声明与初始化 (Declaration & Initialization):”包含 <vector> 头文件。
#include <vector>
std::vector<int> scores; // 空 vectorstd::vector<std::string> names = {"Alice", "Bob", "Charlie"}; // 初始化列表std::vector<double> data(10); // 包含 10 个默认初始化(为 0.0)double 元素的 vectorstd::vector<int> sequence(5, 100); // 包含 5 个整数,值都为 100 的 vector访问元素与特性 (Accessing Elements & Features):
Section titled “访问元素与特性 (Accessing Elements & Features):”- 方括号访问
[]:names[0](直接访问无边界检查)。 at()成员函数:names.at(1)(提供边界检查)。size()成员函数:names.size()返回当前元素数量。push_back(): 在末尾添加一个元素(可能需要重新分配内存)。pop_back(): 移除末尾元素。resize(): 改变元素数量。clear(): 移除所有元素。empty(): 检查 vector 是否包含元素。- 迭代器 (Iterators),
front(),back(),data(): 与std::array类似。
当你需要一个大小在编译时未知或需要在执行期间改变的数组时,使用 std::vector。
现代迭代方式:基于范围的 For 循环 (Range-Based For Loop) (C++11)
Section titled “现代迭代方式:基于范围的 For 循环 (Range-Based For Loop) (C++11)”遍历标准容器(如 std::array, std::vector)和 C 风格数组(大小已知时)元素最方便的方式是基于范围的 for 循环:
#include <iostream>#include <vector>#include <array>
int main() { std::array<int, 4> fixedNums = {10, 20, 30, 40}; std::cout << "std::array elements: "; for (int num : fixedNums) { // 只读访问(创建副本) std::cout << num << " "; } std::cout << std::endl;
std::vector<std::string> words = {"C++", "is", "fun"}; std::cout << "std::vector elements (modified): "; for (std::string& word : words) { // 引用访问(允许修改) word += "!"; std::cout << word << " "; } std::cout << std::endl;
std::cout << "std::vector elements (const reference): "; for (const auto& word : words) { // 只读访问(无副本,推荐用于对象) std::cout << word << " "; } std::cout << std::endl;
return 0;}输出 (Output):
std::array elements: 10 20 30 40std::vector elements (modified): C++! is! fun!std::vector elements (const reference): C++! is! fun!数组细节 (现代视角) (Arrays in Detail (Modern Perspective)):
Section titled “数组细节 (现代视角) (Arrays in Detail (Modern Perspective)):”在 C++ 中有效使用类似数组结构的关键概念:
| 概念 (Concept) | 描述 (Description) |
|---|---|
| 多维数组 (Multi-dimensional arrays) | 对于固定大小的多维数组,使用 std::array<std::array<T, M>, N>;对于动态多维数组,使用 std::vector<std::vector<T>>。避免使用 C 风格的 T[N][M],因为它存在潜在的指针衰减问题。 |
| 指针访问 (Pointer access) | std::array 和 std::vector 都提供了 .data() 成员函数来获取指向底层连续数据的原始指针,这对于与 C API 进行互操作非常有用。 |
| 将数组传递给函数 (Passing arrays to functions) | 优先通过引用 (&) 或 const 引用 (const&) 传递 std::vector 和 std::array,以避免复制。对于连续数据的非拥有视图(来自 C 风格数组、std::array、std::vector),可以使用 std::span (C++20)。 |
| 从函数返回数组 (Return array from functions) | 函数可以直接按值返回 std::array 或 std::vector。现代编译器通常会优化掉复制(返回值优化 - Return Value Optimization - RVO)。 |