Skip to content

C++ 数组

数组是基本的数据结构,用于在连续的内存位置存储同类型元素的集合。C++ 提供了几种处理类似数组结构的方式,每种方式都有其独特的特性。

这是从 C 语言继承来的传统数组。它存储固定大小的顺序元素集合。

指定元素类型、数组名称和大小(必须是编译时常量):

type arrayName[arraySize];

示例:声明一个名为 scores 的数组,用于存储 10 个整数。

int scores[10];

你可以在声明时使用花括号初始化 {} 来初始化 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};

使用数组名称后跟方括号 [] 中的索引来访问元素。数组索引是零基的(zero-based),这意味着第一个元素位于索引 0,最后一个元素位于索引 arraySize - 1。

balance[0] = 1200.0; // 改变第一个元素
double thirdBalance = balance[2]; // 访问第三个元素(索引 2)
// 重要提示:访问超出边界(例如 balance[5] 或 balance[-1])
// 会导致未定义行为 (Undefined Behavior) - 这是一个常见且危险的错误!

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。

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。

std::vector 是一个动态数组。它在堆上管理其存储,允许在运行时增长或收缩大小。

声明与初始化 (Declaration & Initialization):

Section titled “声明与初始化 (Declaration & Initialization):”

包含 <vector> 头文件。

#include <vector>
std::vector<int> scores; // 空 vector
std::vector<std::string> names = {"Alice", "Bob", "Charlie"}; // 初始化列表
std::vector<double> data(10); // 包含 10 个默认初始化(为 0.0)double 元素的 vector
std::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 40
std::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)。