Я считаю, что проще рассуждать о массивах, если вы не пытаетесь думать о 2D-массиве как о чем-то особенном. Это не так. Это просто массив массивов.
int **p
- неправильный тип для использования. Массив массивов int
не может быть преобразован в указатель на указатель на int
.
. Массив может превратиться в указатель на свой первый элемент. Так какой тип первого элемента массива из 3 массивов по 4 int
с? Это массив 4 int
с. Это означает, что тип, в который распадется int[3][4]
, не int**
, это int (*)[4]
: указатель на массив из 4 int
с.
int ar[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
// ar decays to a pointer to its first element, which is an array of 4 ints,
// so p is a pointer to an array of 4 ints, pointing to the first element of ar
int (*p)[4] = ar;
// You can then dereference p, yielding an array of 4 ints.
// That array decays to a pointer to its first element, which is an int,
// so q is a pointer to an int, pointing to the first element of the first element
// of ar
int *q = *p;
// To get the 3rd element of the first element of ar, shift q 2 positions and then
// dereference the resulting pointer
std::cout << *(q + 2); // output the desired element
Live Демо
Конечно, вам не нужно промежуточные переменные p
и q
. Вы можете просто сделать все в одной строке:
int ar[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
// 1. ar decays to a pointer to its first element
// 2. Dereference the pointer that ar decayed into
// 3. The array yielded by the dereference in (2) decays into a pointer to
// its first element
// 4. Offset the pointer that results from (3) by two positions
// 5. Dereference the pointer from (4) to access the third element of the
// first element of ar
std::cout << *(*ar + 2);
Live Demo
Хотя это довольно сложная отдельная строка, поэтому дополнительные промежуточные переменные могут помочь сделать ее более ясно, что происходит.