Арифметика с двойным указателем

У меня есть 2D матрица

matrix[m][n];

Я знаю, что матрица - это двойной указатель с типом int**, Я хотел бы получить двойной указатель, указывающий на подматрицу исходной матрицы. Например, я хочу, чтобы подматрица запускалась для ячейки (1,1). Как я могу получить такой двойной указатель из исходной матрицы [m][n]?

2 ответа

Решение

Матрица, определенная как двумерный массив постоянного размера:

    Int matrix [m][n];

хранится как m смежных блоков из n элементов. Поэтому вы можете технически представить это как плоскую последовательность m * n элементов в памяти. Вы можете использовать арифметику указателей, чтобы найти начало строки или найти конкретный элемент. Но вы не можете найти подматрицу int таким образом.

Двойной указатель:

    int **pmatrix;

подчиняется другой логике: это указатель на указатель и выглядит как массив из m указателей, указывающих на строки из n последовательных элементов. поэтому ваши элементы не обязательно являются последовательными. Вы можете использовать арифметику указателя и косвенность, чтобы найти начало строки или определенного элемента. Но опять же это не может адресовать подматрицу.

И матрица, и матрица pmatrix могут использоваться с одномерным или двумерным индексированием, но компилятор генерирует другой код для адресации элементов.

Для получения подматриц вы должны выполнять итерации, чтобы найти правильные элементы, используя вертикальные и горизонтальные смещения, но вы не можете себе представить, как передать указатель на подматрицу, если не копируете нужные элементы в новую матрицу размера цели

Я знаю, что матрица - это двойной указатель с типом int**.

Нет, ты не Массивы не указатели. Если вы объявили это как int matrix[m][n]; затем тип выражения matrix является int [m][n]; если matrix операнд sizeof или одинарный & операторы, его тип будет преобразован ("распад") в int (*)[n] (указатель на n элемент массива int).

Проблема в том, что вы не можете создавать произвольные подматрицы, просто объявив указатель правильного типа; C и C++ не предоставляют простой способ "разрезать" массивы таким способом. Вы, конечно, можете создать указатель типа int (*)[n-1] и назначьте значение &matrix[1][1] к нему (с соответствующим приведением), но он не будет делать то, что вы хотите.

РЕДАКТИРОВАТЬ

Теперь, когда передо мной настоящая клавиатура, я могу немного подробнее остановиться на этом.

Давайте представим матрицу 3х3, объявленную следующим образом:

int m[3][3] = {{0,1,2},{3,4,5},{6,7,8}};

Мы обычно визуализируем такую ​​матрицу как

+---+---+---+
| 0 | 1 | 2 |
+---+---+---+
| 3 | 4 | 5 |
+---+---+---+
| 6 | 7 | 8 |
+---+---+---+

В C и C++ 2-мерные массивы располагаются в мажорном порядке 1, 2, поэтому вышеуказанная матрица будет представлена ​​в памяти как

   +---+
m: | 0 | m[0][0]
   +---+
   | 1 | m[0][1]
   +---+
   | 2 | m[0][2]
   +---+
   | 3 | m[1][0]
   +---+ 
   | 4 | m[1][1]
   +---+
   | 5 | m[1][2]
   +---+
   | 6 | m[2][0]
   +---+ 
   | 7 | m[2][1]
   +---+
   | 8 | m[2][2]
   +---+

Предположим, вы хотите, чтобы подматрица 2x2 начиналась с m[1][1]:

+---+---+---+
| 0 | 1 | 2 |
+---+---+---+ 
| 3 | +---+---+
+---+ | 4 | 5 |
| 6 | +---+---+
+---+ | 7 | 8 |
      +---+---+

Это соответствует следующим элементам массива:

   +---+
m: | 0 | m[0][0]
   +---+
   | 1 | m[0][1]
   +---+
   | 2 | m[0][2]
   +---+
   | 3 | m[1][0]
   +---+

     +---+ 
     | 4 | m[1][1]
     +---+
     | 5 | m[1][2]
     +---+

   +---+
   | 6 | m[2][0]
   +---+

     +---+ 
     | 7 | m[2][1]
     +---+
     | 8 | m[2][2]
     +---+

Это не смежный подмассив внутри m так что просто объявив указатель и установив его &m[1][1] не буду делать то, что вы действительно хотите. Вам нужно будет создать отдельный матричный объект и скопировать в него нужные элементы:

int subm[2][2] = {{m[1][1], m[1][2]}, {m[2][1], m[2][2]}};

Вы можете написать функцию для захвата 2x2 "среза" вашей матрицы следующим образом:

void slice2x2( int (*mat)[3], int (*submat)[2], size_t startx, size_t starty )
{
  for ( size_t i = 0; i < 2; i++ )
    for ( size_t j = 0; j < 2; j++ )
      submat[i][j] = mat[startx + i][starty + j];
}

int main( void )
{
  int matrix[3][3] = {{0,1,2},{3,4,5},{6,7,8}};
  int submat[2][2];

  slice2x2( matrix, submat, 1, 1 );

  // do something with submat
}


  1. Предварительная публикация проекта стандарта C 2011, §6.2.5.1, №3.
  2. Предварительная публикация проекта стандарта C++ 2014, §8.3.4, №9

Другие вопросы по тегам