<p>void 无法保存二维数组维度信息,还原时必须额外传递行数、列数及元素类型,并在编译期确定列数才能正确转为 int()[M] 类型。</p>

void* 接收二维数组时,原始维度信息已丢失
直接把 int arr[3][4] 转成 void* 传出去,编译器不会保留行数、列数、元素类型——void* 只存地址,不存布局。还原时若只靠指针本身,根本无法知道是 3×4 还是 2×6,更别说正确解引用。
所以关键不是“怎么还原”,而是“怎么让调用方能安全还原”。必须额外传递至少两个信息:
-
rows和cols(或总长度 + 步长) - 原始元素类型(比如是
int还是double),否则指针偏移会错
还原成 int[N][M] 形式需要编译期确定 M
C++ 中固定大小二维数组的指针类型本质是“指向含 M 个元素的数组”的指针,即 int (*)[M]。还原时必须知道列数 M,且该值得是编译期常量。
示例:若原始是 int a[5][7],传 void* p = (void*)a,还原必须写成:
立即学习“C++免费学习笔记(深入)”;
int (*arr)[7] = static_cast<int (*)[7]>(p); // ✅ 列数 7 必须写死 std::cout << arr[2][3]; // 正确访问
如果试图用变量 int cols = 7; 去构造 int (*)[cols],会编译失败——C++ 不支持变长数组类型(VLA 是 C99 特性,C++ 标准不承认)。
运行时尺寸怎么办?用一维视图 + 手动索引
当行数、列数只能在运行时确定(比如函数参数传入 rows, cols),就别强求 arr[i][j] 语法。最稳妥的方式是转成一维指针,靠计算还原:
- 传参时:确保原数组内存连续(
int arr[R][C]满足),传void* p = (void*)arr+R+C - 接收方:
int* flat = static_cast<int>(p);</int> - 访问
arr[i][j]→ 写成flat[i * cols + j]
这是唯一不依赖模板/宏、兼容所有标准 C++ 的方案。注意:不能用 reinterpret_cast<int></int> ——那会把首地址当“指向指针的指针”,大概率段错误。
更现代的做法:避免 void*,改用模板或 span
真正的问题往往出在设计上。void* 是 C 风格的泛型退路,C++ 有更好选择:
- 模板函数:接收
auto& arr或std::array<:array c>, R>&</:array>,维度和类型全保留在类型系统里 - C++20
std::span:传std::span<int></int>+ 显式rows/cols,既安全又免拷贝 - 甚至直接用
std::vector<:vector>></:vector>(但注意它不是连续内存,不适合高性能场景)
如果接口已被 C 库或旧代码锁定必须用 void*,那就老老实实把尺寸和类型作为额外参数传进去——少一个都可能在某次边界访问时崩掉。


















