Рассмотрим это обычное распределение массива:
int* a = malloc(sizeof(int) * 10);
Тип "int *" - это, конечно, указатель на int и sizeof (* a) == sizeof (int). Когда мы делаем [3], это преобразуется в:
*(a + 3)
который (при условии, что sizeof (long) == sizeof (void *)) разыменовывает адрес:
(long)a + 3*sizeof(*a) == (long)a + 3*sizeof(int)
Способ думать о вашем примере кода состоит в том, что тип "int (* rptr) [COLS]" является указателем на (статический, одномерный) массив int размера COLS. Другими словами, sizeof (* rptr) == COLS * sizeof (int). Однако, как и в случае с «int *», мы можем выделить массив этих объектов одномерного массива фиксированного размера. Индексирование "rptr [row]" преобразуется в:
*(rptr + row)
который разыменовывает адрес:
(long)rptr + row*sizeof(*rptr) == (long)rptr + row*COLS*sizeof(int)
Результирующий тип - "int [COLS]", поэтому он может быть снова проиндексирован с помощью "[col]". Вычисление адреса заканчивается тем, что вы хотите:
(long)rptr + row*COLS*sizeof(int) + col*sizeof(int)
Это решение упоминается в http://c -faq.com / aryptr / dynmuldimary.html и работает только в том случае, если число столбцов (или вообще все, кроме первого измерения) фиксировано в время компиляции. Синтаксис становится немного грязным, так как количество измерений увеличивается. Если вам нужно более одного измерения, которое будет определяться динамически во время выполнения, см. Эту страницу для других стратегий.