尽管我不明白你为什么要使用 4D 数组来存储俄罗斯方块游戏的形状,而且我同意 bolov 的评论,即这样的数组不应该溢出堆栈 (7*4*4*4*1 = 448字节),所以你应该检查你写的其他代码。
现在,关于如何管理 4D(N 维)动态大小的数组的问题。您可以通过两种方式做到这一点:
-
第一种方法是创建一个由 (N-1) 维数组组成的数组。如果 N = 2(表格),您最终会得到表格的“线性化”版本(普通数组),其维度等于 R * C,其中 R 是行数,C 是列数。归纳地说,你可以对 N 维数组做同样的事情,而不需要太多的努力。这种方法有一些缺点:
- 您需要事先知道除一个(“最新”)之外的所有尺寸,并且所有尺寸都是固定的。回到 N = 2 的例子:如果你在 C 列和 R 行的表上使用这个方法,你可以通过在预分配空间的末尾分配 C * sizeof() 更多字节来更改行数,但不是列数(不是没有重建整个线性化数组)。此外,不同的行必须具有相同数量的列 C(您不能在纸上绘制一个看起来像三角形的 2D 数组,这只是为了让事情变得清晰)。
- 您需要仔细管理索引:您不能简单地编写
my_array[row][column],而是必须使用my_array[row*C + column] 访问该数组。如果 N 不是 2,那么这个公式就... 有趣
-
您可以使用 N-1 个指针数组。这是我最喜欢的解决方案,因为它没有上一个解决方案的任何缺点,尽管您需要管理指向指向...的指针的指针指向指向类型的指针(但这就是您访问 my_array[7][4][4][4] 时所做的事情.
解决方案 1
假设您想使用第一个解决方案在 C 中构建一个 N 维数组。
您知道数组每个维度的长度,直到第 (N-1) 个(我们称它们为 d_1、d_2、...、d_(N-1))。我们可以归纳地构建它:
- 我们知道如何构建动态一维数组
- 假设我们知道如何构建一个 (N-1) 维数组,我们证明我们可以通过将每个可用的 (N-1) 维数组放入一维数组来构建一个 N 维数组,从而将可用尺寸增加 1。
我们还假设数组必须保存的数据类型称为T。
假设我们要创建一个包含 R (N-1) 维数组的数组。为此,我们需要知道每个 (N-1) 维数组的大小,因此我们需要计算它。
- 对于 N = 1,大小仅为
sizeof(T)
- 对于 N = 2,大小为
d_1 * sizeof(T)
- 对于 N = 3,大小为
d_2 * d_1 * sizeof(T)
您可以轻松地归纳证明存储 R (N-1) 维数组所需的字节数为R*(d_1 * d_2 * ... * d_(n-1) * sizeof(T))。这样就完成了。
现在,我们需要访问这个庞大的 N 维数组中的一个随机元素。假设我们要访问具有索引 (i_1, i_2, ..., i_N) 的项目。为此,我们将重复归纳推理:
- 对于 N = 1,i_1 元素的索引就是
my_array[i_1]
- 对于N = 2,(i_1,i_2)元素的索引可以通过认为每d_1个元素,一个新的数组开始计算,所以元素为
my_array[i_1 * d_1 + i_2]。
- 对于 N = 3,我们可以重复相同的过程并最终得到元素
my_array[d_2 * ((i_1 * d_1) + i_2) + i_3]
等等。
解决方案 2
第二种解决方案会浪费更多内存,但更容易理解和实施。
让我们坚持 N = 2 的情况,以便我们可以更好地思考。想象一下,有一个表并将其逐行拆分,并将每一行放在自己的内存槽中。现在,一行是一维数组,要创建一个二维数组,我们只需要能够拥有一个有序数组,其中包含对每一行的引用。如下图所示(最后一行是第 R 行):
+------+
| R1 -------> [1,2,3,4]
|------|
| R2 -------> [2,4,6,8]
|------|
| R3 -------> [3,6,9,12]
|------|
| .... |
|------|
| RR -------> [R, 2*R, 3*R, 4*R]
+------+
为此,您需要首先分配引用数组(长 R 个元素),然后遍历该数组并为每个条目分配指向新分配的大小为 d_1 的内存区域的指针。
我们可以轻松地将其扩展到 N 维。只需构建一个 R 维数组,并为该数组中的每个条目分配一个大小为 d_(N-1) 的新一维数组,并对新创建的数组执行相同操作,直到获得大小为 d_1 的数组。
请注意如何通过简单地使用表达式 my_array[i_1][i_2][i_3]...[i_N] 轻松访问每个元素。
例如,假设 N = 3 和 T 是 uint8_t 并且 d_1、d_2 和 d_3 在以下代码中是已知的(并且不是未初始化的):
size_t d1 = 5, d2 = 7, d3 = 3;
int ***my_array;
my_array = malloc(d1 * sizeof(int**));
for(size_t x = 0; x<d1; x++){
my_array[x] = malloc(d2 * sizeof(int*));
for (size_t y = 0; y < d2; y++){
my_array[x][y] = malloc(d3 * sizeof(int));
}
}
//Accessing a random element
size_t x1 = 2, y1 = 6, z1 = 1;
my_array[x1][y1][z1] = 32;
我希望这会有所帮助。如果您有任何问题,请随时发表评论。