Давайте посмотрим одну инструкцию за раз:
int iarray[10];
зарезервирует 10 байтов целого размера в памяти. Если sizeof(int) == 4
, он зарезервирует 40 байтов. Давайте предположим, что диапазон памяти установлен в диапазоне от 0x10 до 0x37.
int *p = iarray
резервирует 4 байта (если мы предположим, что мы работаем на 32-битном процессоре) и сохраняет начальный адрес в 40 байтах, зарезервированных впредыдущая инструкция. p
- это сокращение, которое мы используем для ссылки на эти 4 байта. Допустим, эти 4 байта хранятся в 0x50 - 0x53.
int **q = &p
резервирует еще 4 байта, которые будут содержать начальный адрес p (0x50). q может храниться в 0x60-0x63.
Оператор индекса массива в c ++ для указателей является сокращением для арифметики указателей. Например, q[N]
- это то же самое, что и *(q + N)
, поэтому в моем примере q[0]
даст вам значение по адресу 0x60-0x63, которое равно 0x50. Если вы снова используете оператор индекса, он будет применен к новому адресу (0x50), поэтому q[0][2]
эквивалентно p[2]
, то есть iarray[2]
.
q[1]
эквивалентно *(q + 1) = *(0x60 + 0x4) =*(0x64)
,Если вы посмотрите выше, мы никогда не резервируем адрес 0x64, поэтому мы читаем из памяти, которой мы не владеем - неопределенное поведение.