C语言 我使用 fread 在 BMP 上获得分段错误读取信息标题.请问我该如何解决这个问题



这让我很卡住,我该如何解决这个问题?我知道我没有错误检查,但我猜它们不是必需的,因为它仅限于我的桌面。它显然不可能是EOF。它适用于信息标题结构,文件头工作正常。我需要换一条新线吗?

#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 Argumentsn");
              return(0);
    }
    image = fopen( filename, "r");
        if (image == NULL)
    {
    fprintf(stderr, "Error, cannot find file %sn", 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("%ldn", pos);
printf("%zun", 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: %in", (*iheader).width);
    printf("Height: %in", (*iheader).height);
    return(0);
}

您实际上并没有为 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()来恢复正常的结构填充/对齐方式。

代码有两个问题:

对准

出于性能原因,编译器将在其"自然边界"上排列结构字段,从而有效地在字节大小字段之间留下未初始化的间隙。 加

#pragma pack(1) 

在结构定义之前,你应该没问题。 它也很容易测试:只需打印出结构大小,没有和编译指示包,你就会看到差异。

分配

正如 Paul R 已经说过的,你应该为标题分配空间,而不仅仅是提供指向结构的指针。 fileheadfunc工作的事实是一个巧合,当数据被写入分配的空间之外时

,没有任何方式被粉碎。

最后一个,只是为了预防:如果你想将读取结构返回到调用程序,不要只返回一个指向函数中分配的结构的指针,因为这会导致问题类似于你现在拥有的未分配变量。 在调用函数中分配它们,并将指向该变量的指针传递给标头读取函数。

编辑关于最后一点的澄清:

不要

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

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

会这样称呼

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

编辑2:刚刚注意到您读取DIB标头的方式不正确。 该标头有多种变体,大小不同。 因此,在读取文件头后,您首先需要将 4 个字节读取到无符号的 int 中,并根据读取的值选择要使用的正确 DIB 标头结构(不要忘记您已经阅读了它的第一个字段!(或告诉用户您遇到了不受支持的文件格式。

最新更新