Обратите внимание, что это предваряется моими главными комментариями.
То есть функция 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;
}