第5.9章: 多维 C 风格数组

English

概述

多维 C 风格数组就是元素本身也是 C 风格数组的数组。 最常见的形式是二维数组,你可以把它想象成由行和列组成的表格。

在本章中,你将学到:

1. 声明多维 C 风格数组

二维数组通过同时指定两个维度来声明:


int a[2][3]{
    {1, 2, 3},
    {4, 5, 6}
};

这表示:

2. 内存布局:行主序

C++ 以行主序存储多维数组。 这意味着整个第一行先存储,然后是第二行,依此类推。


int a[2][3] = {
    {1, 2, 3},
    {4, 5, 6}
};

Memory (addresses vary):

Address: 1000 1004 1008 1012 1016 1020
Memory: [ 1 ][ 2 ][ 3 ][ 4 ][ 5 ][ 6 ]
              ↑    ↑    ↑    ↑    ↑    ↑
             a[0][0] ...        ...  a[1][2]

尽管数组看起来像一张网格,它其实存储为一个连续的块。

3. 索引多维数组

使用多个 [] 运算符访问元素:


int x = a[0][1];   // 2
int y = a[1][2];   // 6

表达式 a[i] 指第 i 行,它本身 是一个含 3 个 int 的数组。


int b[3] = a[0];   // ❌ error: cannot copy arrays

但你可以取它的地址:


int (*row0)[3] = ::std::addressof(a[0]);

a[0] 的类型是 int[3]。 &a[0] 的类型是 int (*)[3]。

4. 多维数组的退化

与一维数组一样,多维数组在大多数表达式中也会退化——但 只有最外层维度会退化。


int a[2][3];

int (*p)[3] = a;   // decay: a → pointer to array of 3 int

重点:

这就是为什么:


int *p0 = a[0];   // decay: a[0] → &a[0][0]

而:


int (*p1)[3] = a;   // pointer to row

5. 多维数组的指针算术

对 int (*)[3] 做指针算术会按整行移动。


int (*p)[3] = a;

int (*p_next)[3] = p + 1;   // moves to a[1]

而对 int* 做指针算术则按单个元素移动。


int *q = a[0];     // points to a[0][0]
int *q2 = q + 4;   // points to a[1][1]

这能成立,是因为整个 2×3 数组是连续的。

6. 使用 ::std::ranges::begin 与 ::std::ranges::end

你可以为外层维度获取迭代器:


#include 

int a[2][3]{{1,2,3},{4,5,6}};

int (*first)[3] = ::std::ranges::begin(a);
int (*last)[3]  = ::std::ranges::end(a);

它们计算的是:

它们不会搜索 '\0',因为这不是字符串。

7. 更高维的数组

你可以扩展到任意维度:


int a[2][3][4];

这是一个含 2 个元素的数组, 每个元素是一个含 3 个元素的数组, 每个元素又是一个含 4 个 int 的数组。

内存依然是一整块连续区域。

要点