双指针算术

时间:2016-11-17 06:08:08

标签: c++ c pointers pointer-arithmetic double-pointer

我有一个2D矩阵

matrix[m][n];

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

2 个答案:

答案 0 :(得分:3)

  

我知道矩阵是一个带有int **类型的双指针。

不,你没有。数组不是指针。如果您将其声明为int matrix[m][n];,那么表达式的类型 matrixint [m][n];除非matrixsizeof或一元&运算符的操作数,否则它的类型将被转换(“衰减”)到int (*)[n](指向n的指针-element数组int)。

问题是你不能通过声明一个正确类型的指针来创建任意子矩阵; C和C ++没有提供一种以这种方式“切片”数组的简单方法。您当然可以创建一个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 ++中,二维数组以 row-major 顺序 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. 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

答案 1 :(得分:1)

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

int matrix [m][n];

存储为n个元素的m个连续块。因此,您可以在技术上将其想象为内存中m * n个元素的平坦序列。您可以使用指针算法查找行的开头,或查找特定元素。但你无法以这种方式找到子矩阵。

“双”指针:

int **pmatrix;

遵循不同的逻辑:它是指向指针的指针,并作为指向n个连续元素的行的m个指针的数组。所以你的元素不一定是连续的。您可以使用指针算术和间接来查找行或特定项的开头。但这又不能解决一个子矩阵。

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

为了获得子矩阵,你必须使用垂直和水平偏移进行迭代以找到正确的元素,但如果不复制正确的元素,你无法想象以某种方式传递指向子矩阵的指针在目标大小的新矩阵中。