功能中动态分配的结构

时间:2019-01-02 21:49:02

标签: c arrays struct

我有一个与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);
 ....}

1 个答案:

答案 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;
}