是的,这是有道理的,不,它甚至没有谈论“参差不齐”或“参差不齐”的数组。只是当我们说
int a[NUM_ROWS][NUM_COLS];
我们正在创建的是一个数组a,它是一个数组是......其他数组。你可以这样想:
+---------------------------------------+
| +--------+--------+--------+--------+ |
a: [0]: | | | | | | |
| +--------+--------+--------+--------+ |
+ +
| +--------+--------+--------+--------+ |
[1]: | | | | | | |
| +--------+--------+--------+--------+ |
+ +
| +--------+--------+--------+--------+ |
[2]: | | | | | | |
| +--------+--------+--------+--------+ |
+---------------------------------------+
(这里NUM_COLS显然是4,NUM_ROWS是3。)
二维(或更多)维数组 100% 类似于简单的一维数组——您只需要仔细考虑类比即可。如果a 是一个数组,那么在需要其值的表达式中对a 的任何提及都会导致指向数组第一个元素&a[0] 的指针。因此,鉴于我们正在讨论的二维数组a,a 的值是&a[0],并且是指向NUM_COLS 整数数组的指针。
如果多维数组下标要正常工作,它必须以这种方式工作。如果我们写a[i][j],那将被解释为(a[i])[j]。 a 像往常一样变成指向数组第一个元素的指针,但 a[i] 等效于 *(a + i),其中指针算术最终被指向元素的大小缩放 - 即,在引擎盖,它更像*(a+ i * sizeof(*a))。所以sizeof(*a) 必须是sizeof(int [NUM_COLS]) 或NUM_COLS * sizeof(int)。这样a[i] 会为您获取i'th 子数组,然后j 可以选择子数组的一个单元格——int 大小的单元格。
最后一点:我已经通俗地谈论了“多维数组”,但严格来说,正如这里的许多常客喜欢指出的那样,C 没有多维数组;它只有一维数组,而我们认为的二维数组实际上是我们在这里看到的一维数组,其元素恰好是其他一维数组。 (如果 C 有真正的多维数组,下标可能看起来像 a[i,j] 而不是 a[i][j]。)
附录:尽管您提到了指针算术,而我也提到了指针算术,但重要的是要意识到 a 的定义中不涉及指针。只有当我们尝试“获取”a 的值,或者解释 a[i] 如何等同于 *(a + i) 时,才会出现指针。
对于确实涉及指针的数据结构,我们可以对比一下代码描述的情况
int *a2[NUM_ROWS];
for(i = 0; i < NUM_ROWS; i++)
a2[i] = malloc(NUM_COLS * sizeof(int));
这给了我们一个非常不同的内存布局:
+-----+
a2: | | +--------+--------+--------+--------+
| *------->| | | | |
| | +--------+--------+--------+--------+
+-----+
| | +--------+--------+--------+--------+
| *------->| | | | |
| | +--------+--------+--------+--------+
+-----+
| | +--------+--------+--------+--------+
| *------->| | | | |
| | +--------+--------+--------+--------+
+-----+
这就是通常所说的“参差不齐”或“参差不齐”的数组,因为在这种情况下,显然不需要所有行都具有相同的长度。然而,几乎神奇的是,“参差不齐”数组中的单元格也可以使用a2[i][j] 表示法访问。为了获得充分的活力,我们可以使用
int **a3 = malloc(NUM_ROWS * sizeof(int *));
for(i = 0; i < NUM_ROWS; i++)
a3[i] = malloc(NUM_COLS * sizeof(int));
导致这种内存布局:
+-----+
a3: | |
| * |
| | |
+--|--+
|
|
V
+-----+
| | +--------+--------+--------+--------+
| *------->| | | | |
| | +--------+--------+--------+--------+
+-----+
| | +--------+--------+--------+--------+
| *------->| | | | |
| | +--------+--------+--------+--------+
+-----+
| | +--------+--------+--------+--------+
| *------->| | | | |
| | +--------+--------+--------+--------+
+-----+
a3[i][j] 也在这里工作。
(当然,在构建“动态数组”的实际代码中,例如a2 和a3,我们必须检查以确保malloc 没有返回NULL。)