双指针运算

Double pointer arithmetic

我有一个二维矩阵

matrix[m][n];

我知道矩阵是一个类型为int**的双指针。我想获得一个指向原始矩阵子矩阵的双指针。例如,我希望子矩阵从单元格 (1,1) 开始。我如何从原始矩阵[m][n]中得到这样的双指针?

I know that matrix is a double pointer with type int**.

不,你不知道。数组不是指针。如果声明为int matrix[m][n];,那么表达式matrix的类型就是int [m][n];除非 matrixsizeof 或一元运算符 & 的操作数,否则它将其类型转换 ("decay") 为 int (*)[n] (指向 n-int).

的元素数组

问题是你不能仅仅通过声明一个正确类型的指针来创建任意的子矩阵; C 和 C++ 没有以这种方式提供 "slice" 数组的简单方法。您当然可以创建一个 int (*)[n-1] 类型的指针并将 &matrix[1][1] 的值分配给它(使用适当的转换),但它不会执行您想要的操作。

编辑

现在我面前有一个真正的键盘,我可以对此进行一些扩展。

假设一个 3x3 矩阵声明如下:

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

我们通常将这样的矩阵形象化为

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

在C和C++中,二维数组按行优先顺序排列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]
   +---+

所以假设您想要从 m[1][1]:

开始的 2x2 子矩阵
+---+---+---+
| 0 | 1 | 2 |
+---+---+---+ 
| 3 | <strong>+---+---+</strong>
+---+ <strong>| <em>4</em> | <em>5</em> |</strong>
| 6 | <strong>+---+---+</strong>
+---+ <strong>| <em>7</em> | <em>8</em> |</strong>
      <strong>+---+---+</strong>

即对应以下数组元素:

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

     <strong>+---+ 
     | <em>4</em> | m[1][1]
     +---+
     | <em>5</em> | m[1][2]
     +---+</strong>

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

     <strong>+---+ 
     | <em>7</em> | m[2][1]
     +---+
     | <em>8</em> | m[2][2]
     +---+</strong>

这不是 m 中的连续子数组,因此 声明一个指针并将其设置为 &m[1][1] 不会执行您真正想要的操作。您需要创建一个单独的矩阵对象并将您想要的元素复制到它:

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

您可以编写一个函数来获取矩阵的 2x2 "slice",如下所示:

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. Pre-publication draft of the C 2011 standard,§6.2.5.1,¶3。
  2. Pre-publication draft of the C++ 2014 standard, §8.3.4, ¶9

定义为大小恒定的二维数组的矩阵:

int matrix [m][n];

存储为 n 个元素的 m 个连续块。因此,您可以从技术上将其想象为内存中 m*n 元素的平面序列。您可以使用指针算法来查找行的开头,或查找特定元素。但是你不能那样定位子矩阵 int。

"double"指针:

int **pmatrix;

遵循不同的逻辑:它是一个指向指针的指针,作为一个 m 指针数组,指向 n 个连续元素的行。所以你的元素不一定是连续的。您可以使用指针算法和间接寻址来定位行或特定项目的开头。但这同样无法寻址子矩阵。

matrix 和 pmatrix 都可以与 1D 或 2D 索引一起使用,但编译器会生成不同的代码来寻址元素。

为了获得子矩阵,您必须使用垂直和水平偏移进行迭代以找到正确的元素,但是如果您不复制目标大小的新矩阵中的右元素。