首页 > 解决方案 > 在 C 编程中从图像文件返回 3D 数组

问题描述

我目前正在尝试将位图图像文件转换为 3D 数组。在 start = 1 后 3 次尝试后程序卡住了。我不知道出了什么问题。

uint8_t*** loadImage(const int size[3], const char url[]){
uint8_t*** output_array;
output_array = malloc((size[0] * size[1]) * 3 * sizeof(uint8_t));
uint8_t byte, RGB = 0, start = 0; int x = 0, y = 0; uint64_t i;
FILE * fp = fopen(url, "rb");
if(fp == NULL){
    perror("Unable to open file!");
    exit(1);
} else {
    for(i = 0; y < size[1]; i++) {
        fread(&byte, sizeof(uint8_t), 1, fp);
        if(start == 1){
            //it ends here in the 3rd rotation after start
            if(RGB < 2){
                output_array[x][y][RGB] = byte;
                RGB++;
            }
            else if (RGB >= 2 && x <= size[0]) {
                x++;
                output_array[x][y][0] = byte;
                RGB = 1;
            }
            else if(RGB >= 2 && x > size[0]){
                y++;
                x = 0;
                RGB = 1;
                output_array[0][y][0] = byte;      
            }
        }
        else if(byte == 255 && start == 0){
        //trying to find the starting position, which is always white(255)
            start = 1;
        }
}}
fclose(fp);
return output_array;
}

标签: cfile

解决方案


分配一个三维数组

该语句为类型的对象output_array = malloc((size[0] * size[1]) * 3 * sizeof(uint8_t));分配空间。但并不指向一个. 它的类型是,这意味着它指向一个。因此,它需要空间来存放类型的对象。size[0] * size[1] * 3uint8_toutput_arrayuint8_tuint8_t ***uint8_t **uint8_t **

可能有人告诉过你,数组是指针,因此uint8_t ***是一个三维数组。那是错误的。uint8_t ***是指向指向 a 的指针的指针uint8_t(或者,如果它们指向多个对象中的第一个,则指向指向多个对象的指针的指针uint8_t)。从您的代码来看,您似乎想要一个多维数组,而不是一堆指针。

正确执行 a 的“最简单”方法malloc是声明一个指向您想要的东西的指针。如果您想要一个由 3 个数组组成的size[0]数组的数组,那么它将用1声明,并且指向它的指针将用 声明。然后你可以用2分配空间:size[1]uint8_tuint8_t SomeName [size[0]] [size[1]] [3];uint8_t (*Pointer) [size[0]] [size[1]] [3];

uint8_t (*Pointer) [size[0]] [size[1]] [3] = malloc(sizeof *Pointer);

使用指针指向的东西需要使用*运算符,因此您可以使用(*Pointer)[i][j][k]. 但是,您可以改为使自己成为指向数组第一个元素的指针:

uint8_t (*Pointer) [size[0]] [size[1]] [3] = malloc(sizeof *Pointer);
uint8_t (*output_array) [size[1]] [3] = *Pointer;

这首先设置Pointer为指向一个三维数组。然后*Pointer指定第一个数组,但它会自动转换为指向该数组第一个元素的指针。(第一个元素是一个二维数组。)该指针用于初始化output_array,因此output_array指向几个二维数组中的第一个。现在您可以像使用output_array数组一样使用它:您可以将元素引用为output_array[i][j][k]并返回该指针return output_array

然而,大多数人并不像我上面展示的那样使用这两行。我用它来说明,展示我们想要分配的单个对象(一个三维数组)以及如何sizeof为你计算它的大小。大多数人将这些行合并为一行,分配多个包含的数组,效果相同:

uint8_t (*output_array) [size[1]] [3] = malloc(size[0] * sizeof *output_array);

返回数组

定义的数组uint8_t [size[0]] [size[1]] [3]可变长度数组,因为它的维度不是 C 标准定义的整数常量。这种类型称为可变修改类型,指向它的指针也是如此。函数不能返回可变修改的类型,所以这个函数不能返回指向它创建的数组的指针,甚至不能返回指向它的第一个元素的指针,因为子数组也是可变修改的。

一种解决方法是将指针转换为void *并返回它。首先,修改数组声明以返回void *

void *loadImage(const int size[3], const char url[])

然后,在调用者中,将返回值放入所需类型的指针中:

uint8_t (*output_array) [size[1]] [3] = loadImage(size, url);

另一种选择是让调用者传递他们希望设置为指向新数组的指针的地址(通过其第一个元素)。该功能将更改为:

void loadImage(const int size[3], const char url[],
    uint8_t (**returned_array) [size[1]] [3])
{
    …
    *returned_array = output_array;
}

调用者将更改为:

    uint8_t (*output_array) [size[1]] [3];
    loadImage(size, url, &output_array);

脚注

1括号之间的空格只是为了便于阅读,因为这里的括号太多了。您可以根据需要在源代码中使用或不使用该间距。

2这要求您的 C 实现支持可变长度数组。这些目前在 C 标准中是可选的,但由常见的 C 编译器支持,尽管在为 C++ 编译时可能不支持。


推荐阅读