C/C++ 中多維數組在內存中按**行優先**連續存儲,一維數組可通過索引映射模擬多維訪問,無需額外內存分配。本文以 a[24] 為例,推導轉 b[4][6]、c[2][3][4] 的索引公式,給出生產級泛型實現,並驗證數據一致性。
[R][C]:邏輯 (r,c) → 物理索引 r * C + c。[D][R][C]:邏輯 (d,r,c) → 物理索引 (d * R + r) * C + c = d * R * C + r * C + c。#include <iostream>
#include <cstdlib>
#include <ctime>
#include <iomanip>
using namespace std;
// 將一維數組視為二維 [rows][cols] 訪問
void PrintAs2D(int* arr, int rows, int cols) {
cout << "=== 二維視圖 [" << rows << "][" << cols << "] ===\n";
for (int r = 0; r < rows; ++r) {
for (int c = 0; c < cols; ++c) {
int idx = r * cols + c;
cout << '[' << r << "][" << c << "]=" << setw(3) << arr[idx] << ' ';
}
cout << '\n';
}
}
// 將一維數組視為三維 [dep][rows][cols] 訪問
void PrintAs3D(int* arr, int dep, int rows, int cols) {
cout << "\n=== 三維視圖 [" << dep << "][" << rows << "][" << cols << "] ===\n";
for (int d = 0; d < dep; ++d) {
for (int r = 0; r < rows; ++r) {
for (int c = 0; c < cols; ++c) {
int idx = (d * rows + r) * cols + c;
cout << "a[" << d << "][" << r << "][" << c << "]=" << setw(3) << arr[idx] << ' ';
}
cout << '\n';
}
cout << '\n';
}
}
int main() {
const int TOTAL = 24;
int* a = new int[TOTAL];
// 填充隨機數
srand(static_cast<unsigned>(time(nullptr)));
for (int i = 0; i < TOTAL; ++i) a[i] = rand() % 100;
cout << "原始一維數據:\n";
for (int i = 0; i < TOTAL; ++i) cout << a[i] << ' ';
cout << "\n\n";
// 映射為 4×6 二維
PrintAs2D(a, 4, 6);
// 映射為 2×3×4 三維
PrintAs3D(a, 2, 3, 4);
// 驗證:修改三維視圖元素,一維數組同步變化
int idx = (1 * 3 + 2) * 4 + 3; // a[1][2][3]
a[idx] = 999;
cout << "\n修改 a[1][2][3]=999 後,一維數組對應位置: " << a[23] << '\n';
delete[] a;
return 0;
}
原始一維數據:
83 86 77 15 93 35 86 92 49 21 62 27 90 59 63 26 40 26 72 36 11 68 67 29
=== 二維視圖 [4][6] ===
[0][0]= 83 [0][1]= 86 [0][2]= 77 [0][3]= 15 [0][4]= 93 [0][5]= 35
[1][0]= 86 [1][1]= 92 [1][2]= 49 [1][3]= 21 [1][4]= 62 [1][5]= 27
[2][0]= 90 [2][1]= 59 [2][2]= 63 [2][3]= 26 [2][4]= 40 [2][5]= 26
[3][0]= 72 [3][1]= 36 [3][2]= 11 [3][3]= 68 [3][4]= 67 [3][5]= 29
=== 三維視圖 [2][3][4] ===
a[0][0][0]= 83 a[0][0][1]= 86 a[0][0][2]= 77 a[0][0][3]= 15
a[0][1][0]= 93 a[0][1][1]= 35 a[0][1][2]= 86 a[0][1][3]= 92
a[0][2][0]= 49 a[0][2][1]= 21 a[0][2][2]= 62 a[0][2][3]= 27
a[1][0][0]= 90 a[1][0][1]= 59 a[1][0][2]= 63 a[1][0][3]= 26
a[1][1][0]= 40 a[1][1][1]= 26 a[1][1][2]= 72 a[1][1][3]= 36
a[1][2][0]= 11 a[1][2][1]= 68 a[1][2][2]= 67 a[1][2][3]= 29
修改 a[1][2][3]=999 後,一維數組對應位置: 999
template <typename T>
class ArrayView {
T* data_;
std::vector<size_t> strides_; // 步長數組
public:
ArrayView(T* data, std::initializer_list<size_t> dims) : data_(data) {
size_t stride = 1;
for (auto it = dims.end() - 1; it != dims.begin() - 1; --it) {
strides_.insert(strides_.begin(), stride);
stride *= *it;
}
}
// 任意維度索引訪問 (需配合參數包或 vector)
T& operator()(std::initializer_list<size_t> idx) {
size_t offset = 0;
auto s = strides_.begin();
for (size_t i : idx) offset += i * (*s++);
return data_[offset];
}
};
// 用法
ArrayView<int> view2d(a, {4, 6});
view2d({2, 3}) = 100; // 等價 a[2*6+3]
ArrayView<int> view3d(a, {2, 3, 4});
view3d({1, 2, 3}) = 200; // 等價 a[(1*3+2)*4+3]
| 場景 | 說明 |
|---|---|
| 網絡/文件序列化 | 多維數組扁平化傳輸,接收端按協議維度重構 |
| GPU/計算庫互操作 | CUDA/OpenCL 核函數常要求一維指針,宿主端多維邏輯映射 |
| 避免動態多維分配開銷 | 單次 new T[N] 替代多次 new,提升緩存局部性 |
| 舊代碼接口適配 | 老 API 接收 int*,新邏輯用多維語義 |
ArrayView 內部 assert。alignas/#pragma pack。std::vector/std::mdspan (C++23)。