我有一个与bmp和im相关的学校项目,我有点拘泥于事物的动态分配方面(因为我被要求使用它)。
我要做的是使用指针传递数组,这样即使在函数结束后数组也会更改其值,这就是我使用**的原因。然而,由于这一点,代码最终崩溃了(因为没有它,代码运行得很顺利),我确信这是我对*的错误使用,但我不知道在哪里以及如何修复它。
typedef struct pixel{unsigned int r,g,b;}pixel;
void liniarizare(char *filename,pixel **liniar)
{int i;
... (i calculate size which is surely correct and declare fin;size=width*height*sizeof(pixel)
*liniar=(pixel*)malloc(size);
for (i=0;i<width*height;i++)
{fread(&liniar[i]->b,1,1,fin);
fread(&liniar[i]->g,1,1,fin);
fread(&liniar[i]->r,1,1,fin);
}
}
...
int main()
{...
pixel *liniar
liniarizare(filename,&liniar);
....}
最佳答案
请注意,这是我的头条评论。
也就是说,让函数返回pixel *
。并且,使用一个额外的unsigned char
变量来防止将一个字节读入unsigned int
以下是我认为应该有效的简化版本:
typedef struct pixel {
unsigned int r;
unsigned int g;
unsigned int b;
} pixel;
pixel *
liniarizare(char *filename)
{
int i;
int count = width * height;
int size = sizeof(pixel) * count;
pixel *liniar = malloc(size);
pixel *pix = liniar;
unsigned char byte;
for (i = 0; i < count; ++i, ++pix) {
fread(&byte,1,1,fin);
pix->b = byte;
fread(&byte,1,1,fin);
pix->g = byte;
fread(&byte,1,1,fin);
pix->r = byte;
}
return liniar;
}
int
main(void)
{
pixel *liniar;
liniar = liniarizare(filename);
return 0;
}
更新:
奇迹般地足够了。唯一的问题是,我需要能够通过函数中的“reference”传递数组,并让函数提供修改后的数组,这就是为什么我坚持使用
**
和void
的原因。你知道我的代码有什么问题吗?你说了些错话。好吧,处理“return”双星参数(例如
linear[i]->b
)的最简单/最好的方法是尽可能忽略这一点。也就是说,函数在内部处理更简单的
whatever **retptr
。这更快,因为在每个语句上只有一个解引用级别,而没有一个双解引用。返回值(即双星指针)只在末尾设置一次。
下面是我的示例,它被修改为使用您的原始函数原型(但与我的其他清理一起使用)。请注意,只更改了两行(函数原型和函数的最后一行):
typedef struct pixel {
unsigned int r;
unsigned int g;
unsigned int b;
} pixel;
void
liniarizare(char *filename,pixel **retval)
{
int i;
int count = width * height;
int size = sizeof(pixel) * count;
pixel *liniar = malloc(size);
pixel *pix = liniar;
unsigned char byte;
for (i = 0; i < count; ++i, ++pix) {
fread(&byte,1,1,fin);
pix->b = byte;
fread(&byte,1,1,fin);
pix->g = byte;
fread(&byte,1,1,fin);
pix->r = byte;
}
*retval = liniar;
}
int
main(void)
{
pixel *liniar;
liniarizare(filename,&liniar);
return 0;
}
有时需要在函数的顶部读取“返回值”指针,并在底部进行设置。
这里有一个“push to tail”函数,用于单链表:
void
push(node **list,node *new)
{
node *head;
node *prev;
node *cur;
head = *list;
prev = NULL;
for (cur = head; cur != NULL; cur = cur->next)
prev = cur;
if (prev != NULL)
prev->next = new;
else
head = new;
new->next = NULL;
*list = head;
}
更新2:
好吧,现在我们有了一些工作,是时候优化它了(在适当的休息期之后:-)。
保留当前工作版本作为参考/交叉检查。
whatever *ptr
对单个字节的调用有些昂贵。由于您的代码在一次I/O中执行字节操作,我们可以用
fread
替换fread
调用。这应该稍微快一点:for (i = 0; i < count; ++i, ++pix) {
pix->b = fgetc(fin) & 0xFF;
pix->g = fgetc(fin) & 0xFF;
pix->r = fgetc(fin) & 0xFF;
}
不过,我们想尽可能多地读一段。要在一个
fgetc
调用中读取整个图像,需要一个fread
的临时数组。这可能是内存太多,读取大图像可能会遇到缓存命中/未命中问题。但我们可以一次排一排(例如
unsigned char image[count];
)。这更容易处理,而且可能产生好的或更好的结果,所以这可能是一个很好的折衷方案。这可能更快,也可能更快。这就是为什么我们会保留其他版本并进行基准测试,以确定最快/最好的版本。
注意,这段代码假设X维中的像素在物理上是相邻的[一种合理的可能性],但是即使矩阵被转置,仍然可以工作最后,它仍然按照原始代码的线性顺序读取
unsigned char row[width * 3];
像素:typedef struct pixel {
unsigned int r;
unsigned int g;
unsigned int b;
} pixel;
void
liniarizare_by_row(char *filename,pixel **retval)
{
int i;
int yidx;
int count = width * height;
int size = sizeof(pixel) * count;
int w3 = width * 3;
pixel *liniar = malloc(size);
pixel *pix = liniar;
unsigned char row[w3];
for (yidx = 0; yidx < height; ++yidx) {
fread(row,sizeof(row),1,fin);
for (i = 0; i < w3; i += 3, ++pix) {
pix->b = row[i + 0];
pix->g = row[i + 1];
pix->r = row[i + 2]
}
}
*retval = liniar;
}
int
main(void)
{
pixel *liniar;
pixel *liniar_fast;
liniarizare(filename,&liniar);
liniarizare_fast(filename,&liniar_fast);
return 0;
}
关于c - 功能中动态分配的结构,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/54013617/