Чтение из заголовка файла bmp - PullRequest
0 голосов
/ 12 апреля 2020

Я пишу программу для чтения заголовка bmp. Я написал некоторый код, который работал, когда все это было в main. Как реализовать этот код как собственную функцию, а затем внедрить его в main?

Вот весь код:

#include <stdio.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <stdin.h> 

struct bmp_header { 
    uint16_t type; 
    uint32_t size; 
    uint16_t reserved1;     
    uint16_t reserved2;    
    uint32_t offset;        
    uint32_t dib_size;  
    uint32_t width;         
    uint32_t height;        
    uint16_t planes;       
    uint16_t bpp;            
    uint32_t compression;    
    uint32_t image_size;    
    uint32_t x_ppm;         
    uint32_t y_ppm;          
    uint32_t num_colors;     
    uint32_t important_colors; 
}; 


void read_bmp(FILE *BMPFile,struct bmp_header* Header) {  
    fread(&(Header->type), 2, 1, BMPFile); 
    fread(&(Header->size),4,1,BMPFile); 
    fread(&(Header->reserved1),2,1,BMPFile); 
    fread(&(Header->reserverd2),2,1,BMPFile); 
    fread(&(Header->offset),4,1,BMPFile); 
    fread(&(Header->dib_size),4,1,BMPFile); 
    fread(&(Header->width),4,1,BMPFile); 
    fread(&(Header->height),4,1,BMPFile); 
    fread(&(Header->planes),2,1,BMPFile); 
    fread(&(Header->bpp),2,1,BMPFile); 
    fread(&(Header->compression),4,1,BMPFile); 
    fread(&(Header->image_size),4,1,BMPFile); 
    fread(&(Header->x_ppm),4,1,BMPFile); 
    fread(&(Header->y_pp),4,1,BMPFile); 
    fread(&(Header->num_colors),4,1,BMPFile); 
    fread(&(Header->important_colors),4,1,BMPFile); 
} 

int main() { 
    FILE *BMPFile = fopen("image.bmp","rb"); 
    if(BMPFile == NULL) 
    { 
        return; 
    } 

    struct bmp_header* Header; 
    read_bmp(BMPFile,Header); 
    fclose(BMPFile); 

    return 0; 
} 

Соответствующие части версии программы со всеми Операция чтения в main, которая работала как ожидалось, описана ниже

int main( void )
{
    FILE *BMPFile = fopen ("lenna.bmp", "rb");

    if (BMPFile == NULL)
    {
        return 0;
    }

    struct bmp_header Header;

    memset(&Header, 0, sizeof(Header));

    fread(&Header.type, 2, 1, BMPFile);
    fread(&Header.size),4,1,BMPFile); 
    fread(&Header.reserved1),2,1,BMPFile); 
    fread(&Header.reserverd2),2,1,BMPFile); 
    fread(&Header.offset),4,1,BMPFile); 
    fread(&Header.dib_size),4,1,BMPFile); 
    fread(&Header.width),4,1,BMPFile); 
    fread(&Header.height),4,1,BMPFile); 
    fread(&Header.planes),2,1,BMPFile); 
    fread(&Header.bpp),2,1,BMPFile); 
    fread(&Header.compression),4,1,BMPFile); 
    fread(&Header.image_size),4,1,BMPFile); 
    fread(&Header.x_ppm),4,1,BMPFile); 
    fread(&Header.y_pp),4,1,BMPFile); 
    fread(&Header.num_colors),4,1,BMPFile); 
    fread(&Header.important_colors),4,1,BMPFile);

    /* Header fields print section */
    /* ...                         */
}

Ответы [ 2 ]

0 голосов
/ 13 апреля 2020

Когда рабочий код перестает работать, полезно сосредоточиться на изменениях между двумя версиями кода. Итак, почему ваш оригинальный код работает правильно? Это выглядит так:

int main( void )
{
    FILE *BMPFile = fopen ("lenna.bmp", "rb");

    if (BMPFile == NULL)
    {
        return 0;
    }

    struct bmp_header Header;

    memset(&Header, 0, sizeof(Header));

    fread(&Header.type, 2, 1, BMPFile);
    ...
}
  1. Вы объявляете Header типа struct bmp_header в стеке main (как локальную переменную). Таким образом, структура будет точно распределена в течение всего времени жизни программы .
  2. Вы memset отправляете на 0
  3. Вы передаете адреса полей Header непосредственно fread

В новой версии в программе у вас есть функция, определенная как

void read_bmp(FILE *BMPFile,struct bmp_header* Header);

, поэтому вам нужно передать указатель на struct bmp_header. По этой причине вы объявляете

struct bmp_header * Header;

и вызываете read_bmp(BMPFile,Header);.

Чем отличается рабочая версия? Ну, указатель ! Объявляя указатель, вы говорите компилятору, что он содержит адрес, в этом случае адрес структуры, требуемый для read_bmp().

Но вы никогда не говорите компилятору, какой адрес есть, так что fread с в пределах read_bmp() будет записывать в случайное место, вызывающее ошибку сегментации.


Что делать

Вам необходимо перейти к read_bmp() a действительный struct bmp_header адрес, и у вас есть два варианта .

  1. Вы можете выделить Header в стеке, как вы делали раньше, и передать его адрес до read_bmp(), через & оператора. Это должна была быть ваша первая попытка, поскольку она действительно была похожа на ваше рабочее решение.
    struct bmp_header Header;

    read_bmp(BMPFile, &Header);
Вы можете объявить Header как указатель, но вам нужно будет динамически распределять его память через malloc:
    struct bmp_header * Header = malloc(sizeof(struct bmp_header));

    read_bmp(BMPFile, Header);
0 голосов
/ 13 апреля 2020

Вы должны создать функцию типа struct bmp_header *. Затем создайте указатель struct bmp_header в своей функции и выделите память (размер заголовка == 54B) для возвращаемой ссылки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...