Динамически распределяемая структура в функции - PullRequest
0 голосов
/ 03 января 2019

У меня есть школьный проект, связанный с 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 голосов
/ 03 января 2019

Обратите внимание, что это предваряется моими главными комментариями.

То есть функция return 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 внутренне.Это на быстрее , поскольку существует только один уровень разыменования и не a double разыменование для каждого оператора.

Возвращаемое значение (то есть указатель двойной звезды) устанавливается только в конце один раз .

Вот мой пример, переработанный для использования вашего исходного прототипа функции [но с моей другой очисткой].Обратите внимание, что изменяются только две строки (прототип функции и последняя строка функции):

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

UPDATE # 2:

Хорошо, теперь, когда у нас есть что-то , работающее , пришло время оптимизировать это [после подходящего периода отдыха: -)].

СохранитьСейчас рабочая версия используется в качестве эталонной / перекрестной проверки.

fread вызовы для отдельных байтов несколько дороги.

Поскольку ваш код выполняет байтовый ввод-вывод, мы можемзамените 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...