【问题标题】:Why the code "RGBTRIPLE (*image)[width]" initialises a 2D array?为什么代码“RGBTRIPLE (*image)[width]”会初始化一个二维数组?
【发布时间】:2021-09-21 23:42:38
【问题描述】:

此代码来自 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 length 数组的指针吗?如果是这样,为什么稍后我们遍历图像高度并填充 width 长度数组?

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

【问题讨论】:

    标签: c multidimensional-array dynamic-memory-allocation cs50 implicit-conversion


    【解决方案1】:

    这一行

    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]

    至于这部分

    但我不知道这个“...或更多数组”部分在哪里?

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

    例如在这个声明中

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

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

    【讨论】:

    • 更好RGBTRIPLE(*image)[width] = calloc(height, sizeof(*image));
    • @Vlad 感谢您的帮助 看起来我现在好多了,但仍然不确定我的理解是否正确。我可以这样说吗: 1. 首先,我们为 2D 数组分配足够的内存 2. 然后,我们创建一个指针 image,它实际上对我们的 2D 数组一无所知,只保存内存中第一个分配字节的地址 3 . 稍后,当我们运行一个循环+fread(),分配的内存将被RGBTRIPLE[width]数组填满,这样我们就得到了一个二维数组?所以后面我们可以用这个指针(第一个字节地址)让“C”给我们image[i][j],比如?
    • @NeMaksym 假设你有一个二维数组 int a[M][N];然后你可以声明一个 [pointer 指向数组的第一个元素,如 int ( *p )[N] = a;使用指向数组第一个元素的指针和指针算法,您可以使用表达式 p[i] 访问数组的任何“行”。
    • @NeMaksym 例如在这个调用中 fread(image[i], sizeof(RGBTRIPLE), width, inptr);表达式 image[i] 产生动态分配的二维数组的第 i 个“行”。在此调用中,一维数组 image[i] 又被转换为指向其第一个元素的指针。
    猜你喜欢
    • 1970-01-01
    • 2012-06-24
    • 2021-01-13
    • 1970-01-01
    • 2012-11-29
    • 2021-04-04
    相关资源
    最近更新 更多