为什么代码 "RGBTRIPLE (*image)[width]" 初始化一个二维数组?

Why the code "RGBTRIPLE (*image)[width]" initialises a 2D array?

此代码来自 CS50 课程 pset4,“过滤器”任务。 概念如下:

  1. 打开图像文件 (BMP)
  2. 将所有像素读取到二维数组,其中第 1-st lvl 是高度,第 2-nd lvl 是宽度

代码如下:

// height, width are image`s property
// RGBTRIPLE is an entity (struct) of a pixel

RGBTRIPLE(*image)[width] = calloc(height, width * sizeof(RGBTRIPLE));

...

for (int i = 0; i < height; i++)
{
    // Read row into pixel array
    fread(image[i], sizeof(RGBTRIPLE), width, inptr);

    ...
}

我明白了:

  1. 我们创建一个指针 *image
  2. 我们为二维数组分配了足够的内存:calloc(height, width * sizeof(RGBTRIPLE))

但是 (*image)[width] 是什么意思?不应该是指向 width 长度数组的指针吗?如果是这样,为什么稍后我们遍历图像高度并填充 width 长度数组?

Reddit 上的一个人写道:“RGBTRIPLE (*image)[width] 声明图像是一个指向一个或多个数组的指针”。然后它开始有意义。 但我不知道“...或更多数组”部分在哪里?

这一行

RGBTRIPLE(*image)[width] = calloc(height, width * sizeof(RGBTRIPLE));

声明了一个 RGBTRIPLE(*)[width] 类型的指针,它是指向 RGBTRIPLE[width].

类型对象的指针

calloc的调用可以改写成

RGBTRIPLE(*image)[width] = calloc(height, sizeof(RGBTRIPLE[width]));

前提是编译器支持变长数组。也就是说在这个调用中分配了height类型RGBTRIPLE[width]的一维数组,即二维数组。

或者你甚至可以写

RGBTRIPLE(*image)[width] = calloc( 1, sizeof(RGBTRIPLE[height][width]));

为了清楚起见,请考虑二维数组的声明。

RGBTRIPLE image[height][width];

然后表达式中使用的数组指示符 image(极少数例外)被转换为指向其第一个元素的指针。数组元素的类型是RGBTRIPLE [width]。所以指向数组第一个元素的指针的类型是RGBTRIPLE ( * )[width].

至于这部分

But I can't get where this "...or more arrays" part?

那么严格来说是不正确的。指针可以指向一个对象。但是你可以分配一个数组,返回的指针将指向分配数组的第一个元素。

例如在这个声明中

RGBTRIPLE(*image)[width] = calloc(height, width * sizeof(RGBTRIPLE));

分配了高度一维数组,其中高度可以是任何非负数,例如 1。