c - 在 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;
}
解决方案
分配一个三维数组
该语句为类型的对象output_array = malloc((size[0] * size[1]) * 3 * sizeof(uint8_t));
分配空间。但并不指向一个. 它的类型是,这意味着它指向一个。因此,它需要空间来存放类型的对象。size[0] * size[1] * 3
uint8_t
output_array
uint8_t
uint8_t ***
uint8_t **
uint8_t **
可能有人告诉过你,数组是指针,因此uint8_t ***
是一个三维数组。那是错误的。uint8_t ***
是指向指向 a 的指针的指针uint8_t
(或者,如果它们指向多个对象中的第一个,则指向指向多个对象的指针的指针uint8_t
)。从您的代码来看,您似乎想要一个多维数组,而不是一堆指针。
正确执行 a 的“最简单”方法malloc
是声明一个指向您想要的东西的指针。如果您想要一个由 3 个数组组成的size[0]
数组的数组,那么它将用1声明,并且指向它的指针将用 声明。然后你可以用2分配空间:size[1]
uint8_t
uint8_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++ 编译时可能不支持。
推荐阅读
- c# - 不支持的媒体类型 415,但在 Postman 中工作正常
- python - Pandas 在 to_html() 之后将列与数字右对齐
- javascript - 迭代嵌套的 JSON 对象并将数据附加到变量
- elasticsearch - 在嵌套对象上处理 Stats 聚合中的缺失值
- docker - Swagger 页面有未捕获的异常烧瓶 restplus
- c++ - 获取加密的正文响应 WinHttp HTTPS
- python - 日期时间总是给出 1200HRS
- if-statement - 如何根据条件在 Excel 单元格中创建警报
- java - 当作为 java 进程启动时,八度绘图对话框不显示
- r - R - 如何使用循环根据匹配名称列表复制和更改数据帧