我有一个与bmp相关的学校项目,并且我对事物的动态分配方面有些困惑(因为我被要求使用它)。 我试图做的是使用指针传递我的数组,以便即使函数结束后数组也会更改其值,这就是我使用**的原因。但是,由于这一点,代码最终以崩溃而告终(因为没有它,它就可以平稳运行)。我确定这是我对*和&的错误使用,但我不知道在哪里以及如何修复它。
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);
....}
答案 0 :(得分:0)
请注意,这是我的主要评论开头。
也就是说,使函数返回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;
}
更新:
它足够神奇了。唯一的问题是我需要能够通过函数中的“引用”传递数组并让函数提供修改后的数组,这就是为什么我坚持使用
**
和void
的原因。根据您的建议,您是否知道我的代码可能出什么问题?您说linear[i]->b
错了。
好的,处理“返回”双星参数(例如whatever **retptr
)的最简单/最好的方法是尽可能忽略。
也就是说,该函数在内部处理较简单的whatever *ptr
。这样更快,因为在每个每个语句中只有一个取消引用级别,而没有没有双重取消引用。
返回值(即双星指针)仅在一次的末尾设置。
这里是我的示例经过重做以使用您的原始函数原型[但进行了其他清理]。请注意,仅更改了两行(函数原型和函数的最后一行):
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;
}
有时,需要在函数顶部读取“返回值”指针,并将其设置在底部。
这是单链接列表的“推尾”功能:
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:
好吧,现在我们可以进行一些操作了,可以在适当的休息时间之后进行优化了。
保留当前可以使用的版本作为参考/交叉检查。
fread
对单个字节的调用比较昂贵。
由于您的代码一次执行I / O字节操作,因此我们可以将fread
调用替换为fgetc
。这应该稍微快一点:
for (i = 0; i < count; ++i, ++pix) {
pix->b = fgetc(fin) & 0xFF;
pix->g = fgetc(fin) & 0xFF;
pix->r = fgetc(fin) & 0xFF;
}
但是,我们希望尽可能多地阅读一个块。要在一个fread
调用中读取整个图片,则需要一个临时数组,例如unsigned char image[count];
。这可能是 太多的内存,而读取大图像可能会遇到缓存命中/丢失问题。
但是我们可以一次做行(例如unsigned char row[width * 3];
)。这更容易处理,并且可能会产生更好或更好的结果,因此这可能是一个不错的折衷方案。
此可能或不更快。这就是为什么我们保留其他版本和基准以确定最快/最好的原因。
请注意,此代码假定X维度上的像素在物理上相邻(合理的可能性),但即使矩阵已转置也仍然有效。最后,它仍然按照原始代码以线性顺序读取count
个像素:
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;
}