从函数返回结构给我分段错误
Returning structure from function gives me segmentation fault
所以我正在尝试读取位图 header(54 个字节)并使用函数将其保存到结构中。但是当我尝试打印结果时,它给我分段错误。
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 "[=11=]"
/**
* 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" 作为参数添加到函数中来实现(因此该函数将无效。但问题是 - bmp.h 不应该被触及。
您正在使用该行实例化指向 header 的指针。
struct bmp_header* Header;
但在我看来,您想实例化实际的 object,因此请尝试删除您引用的所有地方的 * struct bmp_header
。
分段错误实际上将来自 运行 memset()
on Header
这实际上是一个单元化指针。
问题是
struct bmp_header* Header;
您刚刚为指针变量本身分配了内存,但指针并未指向任何有效内存。您需要先将指针指向有效的内存位置,然后才能使用它。
也就是说,根据用法,您似乎根本不需要指针。只需定义一个结构类型的变量,然后使用它。使用
struct bmp_header Header;
应该完成这项工作。
您的代码中有多个错误:
memset(&Header, 0, sizeof(struct bmp_header));
这不是用0填充struct bmp_header
而是指针变量Header
。由于此指针可能比 header 结构小得多,因此您还填充了不应触摸的内存区域。
如果您在此 out-of-bounds 访问期间没有得到分段错误,您将在访问新创建的 NULL
指针后立即得到它:
fread(&(Header->type), 2, 1, BMP_file);
您必须先在 read_bmp_header
中提供内存,而不是填充 0。
在main
中你做了同样的非法memset
操作。您必须完全删除该操作。无论如何,您之后都会分配一个新值。
在不改变的情况下,您可以通过两种方式解决问题bmp.h
:
变体 1:
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:
静态内存用于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;
}
此变体避免了动态内存分配,但一次只能处理 1 个结构并且不是线程安全的。
所以我正在尝试读取位图 header(54 个字节)并使用函数将其保存到结构中。但是当我尝试打印结果时,它给我分段错误。
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 "[=11=]"
/**
* 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" 作为参数添加到函数中来实现(因此该函数将无效。但问题是 - bmp.h 不应该被触及。
您正在使用该行实例化指向 header 的指针。
struct bmp_header* Header;
但在我看来,您想实例化实际的 object,因此请尝试删除您引用的所有地方的 * struct bmp_header
。
分段错误实际上将来自 运行 memset()
on Header
这实际上是一个单元化指针。
问题是
struct bmp_header* Header;
您刚刚为指针变量本身分配了内存,但指针并未指向任何有效内存。您需要先将指针指向有效的内存位置,然后才能使用它。
也就是说,根据用法,您似乎根本不需要指针。只需定义一个结构类型的变量,然后使用它。使用
struct bmp_header Header;
应该完成这项工作。
您的代码中有多个错误:
memset(&Header, 0, sizeof(struct bmp_header));
这不是用0填充struct bmp_header
而是指针变量Header
。由于此指针可能比 header 结构小得多,因此您还填充了不应触摸的内存区域。
如果您在此 out-of-bounds 访问期间没有得到分段错误,您将在访问新创建的 NULL
指针后立即得到它:
fread(&(Header->type), 2, 1, BMP_file);
您必须先在 read_bmp_header
中提供内存,而不是填充 0。
在main
中你做了同样的非法memset
操作。您必须完全删除该操作。无论如何,您之后都会分配一个新值。
在不改变的情况下,您可以通过两种方式解决问题bmp.h
:
变体 1:
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:
静态内存用于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;
}
此变体避免了动态内存分配,但一次只能处理 1 个结构并且不是线程安全的。