Механика двумерных массивов на самом деле проще, чем кажется на первый взгляд, но обычно она плохо изучена. Тем не менее, чтобы быстро расшифровать вещи, требуется большой опыт, и даже опытным разработчикам иногда приходится останавливаться и думать на мгновение (или два). По сути, когда вы видите 2D-массив, например int a [5] [10] (я изменяю размер вашего массива на 5, чтобы упростить задачу), вам нужно перестать думать об этом как о 2D. Думайте об этом как 1D вместо этого. Первый нижний индекс определяет количество элементов в этом одномерном массиве, как и любой другой одномерный массив. Когда вы индексируете в массив, например, [3], вы получаете доступ к объекту по индексу 3. Это ничем не отличается от любого другого массива. Допустим, вместо этого «а» было определено так:
// 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}};
У вас все еще есть одномерный массив, и вы можете добавить в него индекс, как и в предыдущем примере, получив следующее (не настоящий синтаксис, как вы должны думать об этом):
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] возвращает массив из 10 целых чисел, содержащий значения от 155 до 200. Сам элемент является "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, 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. Это не то же самое, поэтому скобки требуются для изменения приоритета (и, следовательно, смысла этого объявления). Используя приведенный выше правильный синтаксис, «p» будет указывать на первый элемент (массив «int [10]», содержащий элементы с 5 по 50), p + 1 будет указывать на второй элемент («int [10]»). "массив, содержащий элементы от 55 до 100) и т. д. Бонусные баллы: Что будет делать следующее?
(*(p + 3))[5]
Возвращает 180, потому что (p + 3) возвращает указатель на массив из 10 целых чисел в «a [3]», а при разыменовании с помощью оператора * вы получаете фактический массив «int [10]» в этом месте , Затем индекс [5] возвращает значение 180 в этом массиве.
Без сомнения, все еще потребуется много практики, чтобы разобраться с этим, но я надеюсь, что это поможет.