Арифметика с двойным указателем
У меня есть 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
}
- Предварительная публикация проекта стандарта C 2011, §6.2.5.1, №3.
- Предварительная публикация проекта стандарта C++ 2014, §8.3.4, №9