Я получаю сообщение об ошибке чтения сегментации на BMP, используя fread.Как я могу это исправить, пожалуйста? - PullRequest
1 голос
/ 14 сентября 2011

Это застряло у меня, как я могу это исправить? Я знаю, что у меня нет проверки ошибок, но они не требуются, я думаю, так как они ограничены моим рабочим столом Это явно не может быть EOF. Это для структуры infoheader, fileheader работает нормально. Мне нужно взять новую строку или что-то?

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

typedef struct
{
    unsigned char fileMarker1;       /* 'B' */                       
    unsigned char fileMarker2;       /* 'M' */ 
    unsigned int   bfSize;             
    unsigned short unused1;           
    unsigned short unused2;           
    unsigned int   imageDataOffset;  /* Offset to the start of image data */
}FILEHEADER; 

typedef struct                       
{ 
    unsigned int   biSize;            
    int            width;            /* Width of the image */ 
    int            height;           /* Height of the image */ 
    unsigned short planes;             
    unsigned short bitPix;             
    unsigned int   biCompression;      
    unsigned int   biSizeImage;        
    int            biXPelsPerMeter;    
    int            biYPelsPerMeter;    
    unsigned int   biClrUsed;          
    unsigned int   biClrImportant;     
}INFOHEADER; 

typedef struct                        
{ 
    unsigned char  b;         /* Blue value */ 
    unsigned char  g;         /* Green value */ 
    unsigned char  r;         /* Red value */ 
 }IMAGECOMPONENT; 

 int fileheadfunc(FILE *image);
 int infoheadfunc(FILE *image);

 int main( int argc, char *argv[] )
 {
    char *filename; /* *threshholdInput = argv[2]; */
    FILE *image;
    int filehead, infohead;
    filename = argv[1];
    /* int threshhold = atoi(threshholdInput); */

    if (argc != 2) 
    {
              printf(" Incorrect Number Of Command Line Arguments\n");
              return(0);
    }

    image = fopen( filename, "r");

        if (image == NULL)
    {
    fprintf(stderr, "Error, cannot find file %s\n", filename);
    exit(1);
    }

    filehead = fileheadfunc(image);
    infohead = infoheadfunc(image);
    fclose(image);

   return(0);             
}

int fileheadfunc(FILE *image)
{
    FILEHEADER *header;
    long pos;

    fseek (image , 0 , SEEK_SET);

    fread( (unsigned char*)header, sizeof(FILEHEADER), 1, image );


    if ( (*header).fileMarker1 != 'B'  || (*header).fileMarker2 != 'M' )
    {
    fprintf(stderr, "Incorrect file format");
    exit(1);
    }

    printf("This is a bitmap!\n");
    pos = ftell(image);
printf("%ld\n", pos);
printf("%zu\n", sizeof(FILEHEADER));

return(0);
}

int infoheadfunc(FILE *image)
{
    INFOHEADER *iheader;

    fseek (image, 0, SEEK_CUR ); 
    fread( (unsigned int*)iheader, sizeof(INFOHEADER), 1, image );

    printf("Width: %i\n", (*iheader).width);
    printf("Height: %i\n", (*iheader).height);

    return(0);
}

Ответы [ 2 ]

3 голосов
/ 14 сентября 2011

Вы фактически не выделяете хранилище для структур данных заголовка BMP, например, вам нужно изменить это:

int fileheadfunc(FILE *image)
{
    FILEHEADER *header;
    long pos;

    fseek(image, 0, SEEK_SET);

    fread((unsigned char*)header, sizeof(FILEHEADER), 1, image);

    ...

к этому:

int fileheadfunc(FILE *image)
{
    FILEHEADER header; // <<<
    long pos;

    fseek(image, 0, SEEK_SET);

    fread(&header, sizeof(FILEHEADER), 1, image); // <<<

    ...

Кроме того, как ранее отмечалось в одном из комментариев выше, вам нужно #pragma pack(1) (или эквивалент, если вы не используете gcc или gcc-совместимый компилятор) перед вашими определениями структуры, чтобы исключить нежелательное заполнение. (Примечание: используйте #pragma pack() после определения структуры для восстановления нормального заполнения / выравнивания структуры.)

2 голосов
/ 14 сентября 2011

Есть две проблемы с кодом:

Выравнивание

По соображениям производительности компилятор, если не указано иное, будет размещать поля структуры на своих "естественных границах", фактически оставляя неинициализированнымипромежутки между полями размера байта.Добавьте

#pragma pack(1) 

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

Распределение

Как уже сказал Пол Р., вы должны выделитьпространство для заголовков, а не просто предоставить указатель на структуры.Тот факт, что fileheadfunc работает, является совпадением, просто не было ничего такого, что могло бы быть разбито, когда данные записывались за пределами выделенного пространства.

Последнее, просто для предотвращения: если вы когда-нибудь захотитечтобы вернуть структуры чтения в вызывающую программу, не просто возвращайте указатель на структуру, выделенную в функции, так как это вызовет проблемы, аналогичные тем, что у вас есть.Выделите их в вызывающей функции и передайте указатель на эту переменную в функции чтения заголовка.

РЕДАКТИРОВАТЬ уточнение относительно последней точки:

НЕ

FILEHEADER * fileheadfunc(FILE *image)
{
    FILEHEADER header;
    ...
    return &header; // returns an address on the function stack that will 
                    // disappear once you return
}

DO

int fileheadfunc(FILE *image, FILEHEADER *header)
{
    ...
}

, который будет вызываться следующим образом

...
FILEHEADER header;
returnvalue = fileheaderfunc(imagefile,&header);

EDIT2: только что заметил, что способ чтения DIB-заголовка неправильный.Есть несколько вариантов этого заголовка, с разными размерами.Поэтому после прочтения заголовка файла сначала необходимо прочитать 4 байта в целое число без знака и на основе прочитанного значения выбрать правильную структуру заголовка DIB для использования (не забудьте, что вы уже прочитали ее первое поле!) Или сообщите пользователю, с которым вы столкнулисьнеподдерживаемый формат файла.

...