2D 数组的机制实际上比它们最初看起来要容易,但通常教得不好。尽管如此,快速破译事物确实需要大量经验,即使是经验丰富的开发人员有时也不得不停下来思考片刻(或两片)。基本上,当您看到诸如 int a[5][10] 之类的 2D 数组(我将数组的大小更改为 5 以简化事情)时,您需要停止将其视为 2D。把它想象成一维的。第一个下标指定此一维数组中的元素数量,就像任何其他一维数组一样。当您对数组进行索引时,例如 a[3],您将访问索引 3 处的对象。这与任何其他数组没有什么不同。假设“a”是这样定义的:
// Note: The size of the array, 5, can be omitted
int a[5] = {5, 10, 15, 20, 25};
然后下标产生这个:
a[0] = 5
a[1] = 10
a[2] = 15
a[3] = 20
a[4] = 25
这很容易,大多数人都能做到。但如果你现在这样做:
// Note: Like above, the size of the array, 5, can be omitted
int a[5][10] = {{ 5, 10, 15, 20, 25, 30, 35, 40, 45, 50},
{ 55, 60, 65, 70, 75, 80, 85, 90, 95, 100},
{105, 110, 115, 120, 125, 130, 135, 140, 145, 150},
{155, 160, 165, 170, 175, 180, 185, 190, 195, 200},
{205, 210, 220, 225, 230, 235, 240, 245, 250, 255}};
你仍然有一个由 5 个元素组成的一维数组,你可以像前面的例子一样对它下标,产生以下内容(不是真正的语法,只是你应该如何思考它):
a[0] = 5 10 15 20 25 30 35 40 45 50
a[1] = 55 60 65 70 75 80 85 90 95 100
a[2] = 105 110 115 120 125 130 135 140 145 150
a[3] = 155 160 165 170 175 180 185 190 195 200
a[4] = 205 210 220 225 230 235 240 245 250 255
这里唯一的区别是每个元素不是像上一个示例那样是一个“int”,而是每个元素都是一个数组(由 10 个整数组成)。因此,当您下标时,每个索引(0 到 4)都会返回该行的 10 个整数数组。例如,a[3] 返回包含值 155 到 200 的 10 个整数的数组。元素本身是一个“int[10]”,因此您可以这样对待它。 IOW,你得到的就是这个:
int b[10] = {155, 160, 165, 170, 175, 180, 185, 190, 195, 200};
因此,例如,与 b[7] = 190、a[3][7] = 190 的方式相同,因为 a[3] 有效地返回了 b 的等价物(一个 10整数),然后 [7] 下标抓取该数组索引 7 处的元素,就像 b[7] 一样。此外,同样 b 是指向数组第一个元素的指针(因为所有数组名称都衰减为指向数组第一个元素的指针),在这种情况下为 155(即“b”衰减为一个 int * 指向 155),a[3] 返回(衰减为)相同的东西。为什么?因为它返回了所描述的 b 的等价物,并且就像 b 一样,它衰减为指向其第一个元素的指针。 IOW,就像这是真的:
int *p = b; // "b" decays into a pointer to its first element (an "int")
int val = *p; // Equals 155
这也是真的:
int *p = a[3]; // a[3] returns the equivalent of "b", an int[10], and this decays into a pointer to its first element, just like "b"
int val = *p; // Equals 155
最后,就像 FredOverflow 提到的那样,这也是真的:
int (*p)[10] = a;
语法需要习惯,但它非常有意义。由于每个数组名称都衰减为指向其第一个元素的指针,因此“a”因此衰减为指向其第一个元素的指针。那是什么元素?好吧,“a”的每个元素都是一个由 10 个整数组成的数组,即“int[10]”,因此“a”必须衰减为指向这些“int[10]”元素中的第一个元素的指针。上面的语法就是声明这个指针的方式。它将“p”定义为指向 10 个整数数组的指针。由于 C++ 优先规则,需要(圆)括号。如果你删除它们,你会得到这个:
int *p[10] = a; // Compiler error!
它将“p”声明为一个由 10 个元素组成的数组,其中每个元素都是一个指向 int 的指针。它与 IOW 不同,因此需要括号来更改优先级(以及此声明的含义)。使用前面显示的正确语法,“p”因此将指向第一个元素(“int[10]”数组包含元素 5 到 50),p + 1 将指向第二个元素(“int[10] " 包含元素 55 到 100 的数组)等。奖励点:因此以下会做什么?
(*(p + 3))[5]
它返回 180,因为 (p + 3) 返回指向“a[3]”处的 10 个整数数组的指针,当使用 * 运算符取消引用时,您会在此位置获得实际的“int[10]”数组.然后 [5] 下标在该数组中产生值 180。
毫无疑问,要弄清楚这一点仍然需要大量练习,但我希望这会有所帮助。