簡體   English   中英

從 function 返回結構給我分段錯誤

[英]Returning structure from function gives me segmentation fault

所以我正在嘗試讀取 bitmap header(54 個字節)並使用 function 將其保存到結構中。 但是當我嘗試打印結果時,它給了我分段錯誤。

bmp.c

#include "bmp.h"
#include <stdlib.h>
#include <string.h>


struct bmp_header* read_bmp_header(FILE* BMP_file){
    if(BMP_file == NULL){
      return 0;
    }

    struct bmp_header* Header;

    memset(&Header, 0, sizeof(struct bmp_header));
    fread(&(Header->type), 2, 1, BMP_file); 
    fread(&(Header->size),4,1,BMP_file); 
    fread(&(Header->reserved1),2,1,BMP_file); 
    fread(&(Header->reserved2),2,1,BMP_file); 
    fread(&(Header->offset),4,1,BMP_file); 
    fread(&(Header->dib_size),4,1,BMP_file); 
    fread(&(Header->width),4,1,BMP_file); 
    fread(&(Header->height),4,1,BMP_file); 
    fread(&(Header->planes),2,1,BMP_file); 
    fread(&(Header->bpp),2,1,BMP_file); 
    fread(&(Header->compression),4,1,BMP_file); 
    fread(&(Header->image_size),4,1,BMP_file); 
    fread(&(Header->x_ppm),4,1,BMP_file); 
    fread(&(Header->y_ppm),4,1,BMP_file); 
    fread(&(Header->num_colors),4,1,BMP_file); 
    fread(&(Header->important_colors),4,1,BMP_file); 
    return Header;
}

bmp.h

#ifndef _BMP_H
#define _BMP_H

#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>


#define PADDING_CHAR "\0"

/**
 * Structure contains information about the type, size, layout, dimensions
 * and color format of a BMP file. Size of structure is 54 bytes.
*/
struct bmp_header{
    uint16_t type;              // "BM" (0x42, 0x4D)
    uint32_t size;              // file size
    uint16_t reserved1;         // not used (0)
    uint16_t reserved2;         // not used (0)
    uint32_t offset;            // offset to image data (54B)
    uint32_t dib_size;          // DIB header size (40B)
    uint32_t width;             // width in pixels
    uint32_t height;            // height in pixels
    uint16_t planes;            // 1
    uint16_t bpp;               // bits per pixel (1/4/8/24)
    uint32_t compression;       // compression type (0/1/2) 0
    uint32_t image_size;        // size of picture in bytes, 0
    uint32_t x_ppm;             // X Pixels per meter (0)
    uint32_t y_ppm;             // X Pixels per meter (0)
    uint32_t num_colors;        // number of colors (0)
    uint32_t important_colors;  // important colors (0)
} __attribute__((__packed__));


/**
 * Reads BMP header from input stream
 *
 * Reads and returns BMP header from opened input stream. The header is located
 * at it's beginning. If the stream is not opened or it is corrupted, function
 * returns `NULL`.
 *
 * @param stream opened stream, where the image data are located
 * @return `bmp_header` structure or `NULL`, if stream is not open or broken
 */
struct bmp_header* read_bmp_header(FILE* stream);


#endif

main.c

#include "bmp.c"

int main(){
  FILE *BMP_file = fopen("./assets/lenna.bmp", "rb");

  struct bmp_header* Header;
  memset(&Header, 0, sizeof(struct bmp_header));
  Header = read_bmp_header(BMP_file);
  printf("%x\n", Header->type); 
  fclose(BMP_file);
  return 0;
}

我已經嘗試通過將結構“bmp_header”添加到 function 作為參數來做到這一點(所以 function 將是無效的。但問題是 - bmp.h 不應該被觸及。

您的代碼中有多個錯誤:

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

這不會用 0 填充struct bmp_header ,而是用指針變量Header 由於該指針可能比 header 結構小得多,因此您還填充了您不應該觸摸的 memory 區域。

如果您在此越界訪問期間沒有遇到分段錯誤,那么當您訪問新創建的NULL指針時,您將立即獲得它:

fread(&(Header->type), 2, 1, BMP_file);

您必須首先在read_bmp_header中提供 memory 而不是填充 0。

main中,您執行相同的非法memset操作。 您必須完全刪除該操作。 無論如何,您之后都會分配一個新值。

您可以在不更改bmp.h的情況下通過 2 種方式解決問題:

變體 1:

在 read_bmp_header 中動態分配read_bmp_header並在main中釋放。

struct bmp_header* read_bmp_header(FILE* BMP_file){
    if(BMP_file == NULL){
      return NULL;
    }

    struct bmp_header* Header = malloc(sizeof(*Header);
    if (Header == NULL)
        return NULL;

    memset(Header, 0, sizeof(struct bmp_header));
    fread(&(Header->type), 2, 1, BMP_file);
    // TODO check result of read
    ...
    return Header;
}

int main(void)
{
   FILE *BMP_file = fopen("./assets/lenna.bmp", "rb");
   struct bmp_header* Header = read_bmp_header(BMP_file);
   fclose(BMP_file);

   printf("%x\n", Header->type); 
   free(Header); // Main must free the struct.
   return 0;
}

變體 2:

Static memory 用於read_bmp_header 不需要釋放。

struct bmp_header* read_bmp_header(FILE* BMP_file){
    static struct bmp_header Header;

    if(BMP_file == NULL){
      return NULL;
    }

    memset(&Header, 0, sizeof(struct bmp_header));
    fread(&Header.type, 2, 1, BMP_file); 
    // TODO: check result of read
    ...
    return &Header;
}

int main(void)
{
   FILE *BMP_file = fopen("./assets/lenna.bmp", "rb");
   struct bmp_header* Header = read_bmp_header(BMP_file);
   fclose(BMP_file);

   printf("%x\n", Header->type); 
   return 0;
}

此變體避免了動態 memory 分配,但一次只能處理 1 個結構並且不是線程安全的。

您正在使用該行設置指向 header 的指針。

struct bmp_header* Header;

但在我看來,您想實例化實際的 object 因此嘗試在您引用struct bmp_header的所有地方刪除 * 。

分段錯誤實際上來自在Header上運行memset() ,這實際上是一個未初始化的指針。

問題是,通過說

 struct bmp_header* Header;

您剛剛為指針變量本身分配了 memory,但指針未指向任何有效的 memory。 您需要使指針指向一個有效的 memory 位置,然后才能使用它。

也就是說,根據用法,看起來您根本不需要指針。 只需定義結構類型的變量,然后使用它。 使用

struct bmp_header Header;

應該做的工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM