在C语言中对多维数组进行索引

4
我熟悉可以像这样访问多维数组:arr[rows][cols]。当我将其想象为网格或坐标系并查找点时,这是有意义的。但是,我对下面的行感到困惑。我理解它正在获取指向某个结构体的指针,该结构体位于结构体数组中,但是我很难想象这可能代表什么坐标系中的位置......顺便说一下,它是一张位图,SOMETHING 是一个像素。
//what does this line mean   SOMETHING *o = original + row*cols + col;



for (row=0; row < rows; row++)
 for (col=0; col < cols; col++) {
  SOMETHING* o = original + row*cols + col;
  SOMETHING* n = (*new) + row*cols + (cols-1-col);
  *n = *o;
}

那是一个糟糕的变量命名选择。 - ajay
5个回答

5

想一想数组在内存中的布局方式。多维数组只是一个数组的数组,所以假设你有一个像SOMETHING[10][10]这样的数组。

内存布局将会是:

[0][0], [0][1], .. [0][9], [1][0], [1][1].. [9][9]

这实际上与分配 sizeof(SOMETHING)*100 完全相同。

代码 SOMETHING* o = original + row*cols + col; 是在说“创建一个类型为 SOMETHING 的对象的指针”。

指针地址应该是:

  • original 的内存地址,

  • 加上行数乘以列数,

这将把它放到一行的开头,

  • 然后再加上特定的列数

就可以到达数组中对象的确切位置了。


2
请注意,为了使此代码正常工作,original 的类型需要是 SOMETHING *,而不是 SOMETHING 的二维数组。否则,指针算术运算会按行递增,而不是按 SOMETHING 元素递增,并返回一个数组(表示一行),而不是单个的 SOMETHING 元素。 - Dmitri

5

一个二维数组如下:

{{00,01,02,03},
 {10,11,12,13},
 {20,21,22,23},
 {30,31,32,33}}

将按顺序放置在内存中。就像这样:

 {00,01,02,03,10,11,12,13,20,21,22,23,30,31,32,33}

因此,当您使用 a[i][j] 访问数组时,您也可以使用 a + i *(ELEMENTS_IN_ROW) + j 访问该数组。

1

有一个指针名为original,它可能位于原点([0][0])。您正在进行简单的算术运算以指向当前坐标。

假设它是一个5x5的数组,现在您在第3行第4列([2][3])

要从原点到达[2][3],您必须移动:

  • 第一行5个单位
  • 第二行5个单位
  • 第三行3个单位

总共13个单位。

row*cols + col给出了2*5 + 313

因此,如果您从origin移动row*cols + col个单位,则可以到达当前位置。


0

行列坐标在与其他不同的东西混合时往往会导致一些混淆...例如典型的图像坐标系统,其中原点是左上角。

矩阵的坐标表示为(行,列)。这相当于图像坐标中的(y,x):通过增加行数,向下移动;增加列数,向右移动。

在您的代码中,2D空间只是遵循C(行优先)和图像(按行)的典型约定。因此,您可以阅读:

SOMETHING* o = original + row*cols + col;

如下

SOMETHING* o = original + iy*width + ix;

请注意,这与在C中使用静态2D数组相同,因此以下两者是等效的:
original[NROWS][NCOLS];
...
SOMETHING *o = &original[row][col];

或者

SOMETHING original[HEIGHT][WIDTH];
...
SOMETHING *o = &original[iy][ix];

有一个非常重要的限制,即在这种情况下,维度必须在编译时知道。在您的情况下,您正在处理动态二维数组,这是C语言不支持的。

总之,如果SOMETHING是一个像素,让我猜一下...

struct SOMETHING {
  unsigned char r;
  unsigned char g;
  unsigned char b;
};

这意味着以其中任何一种方式寻址的元素只有3个字节长,并且它们是连续排列的。


0

事实上,你所想象的二维网格实际上是由连续的线性内存表示的。

因此,要访问索引为(r,c)的坐标,您需要从数组的基地址开始,然后通过将行索引(r)乘以每行中的列数来跳到第r行 - 再次强调,我们是在一个线性方向上移动。这将带您到第r行的第一列。从这里,您将指针递增c列,然后就到达了目的地。

因此,在您的代码中,我假设original是您的数组的起始位置。因此,该行代码:

original + row*cols + col

正在准确地执行我上面所描述的操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接