Допустим, определение a
выглядит примерно так:
int a[2][2] = {{1, 2}, {3, 4}};
Вот как выглядит символ a
:
[ 1 ][ 2 ][ 3 ][ 4 ]
В C, когда вы выполняете арифметику с указателем, фактическая величина, на которую значение указателя увеличивается или уменьшается, зависит от размера типа, хранящегося в массиве. Тип, содержащийся в первом измерении a
, равен int[2]
, поэтому, когда мы просим C вычислить значение указателя (a + 1), он берет местоположение, названное a
, и увеличивает его на размер * 1012. *, в результате чего указатель ссылается на ячейку памяти, содержащую целочисленное значение [3]. Так что да, когда вы разыменовываете этот указатель, а затем добавляете к нему 2, результатом является целочисленное значение 5. Когда вы затем пытаетесь разыменовать это целочисленное значение, это не имеет смысла.
Итак, давайте предположим, что массив содержит указатели:
char const * one = "one",
two = "two",
three = "three",
four = "four";
char const * a[2][2] = {{one, two}, {three, four}};
Добавьте 1 к a, а затем разыменуйте его, и вы получите указатель на символ, ссылающийся на строку «три». Добавьте к этому два, и вы получите указатель на короткую строку «ree». Разыщите его, и вы получите значение char 'r', но только благодаря счастливой случайности вы избежали ошибки защиты памяти.