【问题标题】:Segmentation fault while reading larger .bmp file读取较大的 .bmp 文件时出现分段错误
【发布时间】:2013-04-14 09:24:37
【问题描述】:

编译时出现分段错误。

当我尝试在 main() 中填充表数组时,我认为与第一个 for 循环中的内存分配有关吗?

如果我调用较小的文件而不是使用“较大”的 table.bmp 文件,它会起作用。

我不明白为什么? (我对此很陌生)

任何帮助将不胜感激。

提前致谢

#include <stdio.h>
#include <string.h>
#include <malloc.h>

unsigned char *read_bmp(char *fname,int* _w, int* _h)
{
    unsigned char head[54];
    FILE *f = fopen(fname,"rb");

    // BMP header is 54 bytes
    fread(head, 1, 54, f);

int w = head[18] + ( ((int)head[19]) << 8) + ( ((int)head[20]) << 16) + ( ((int)head[21]) << 24);
int h = head[22] + ( ((int)head[23]) << 8) + ( ((int)head[24]) << 16) + ( ((int)head[25]) << 24);

// lines are aligned on 4-byte boundary
int lineSize = (w / 8 + (w / 8) % 4);
int fileSize = lineSize * h;

unsigned char *img = malloc(w * h), *data = malloc(fileSize);

// skip the header
fseek(f,54,SEEK_SET);

// skip palette - two rgb quads, 8 bytes
fseek(f, 8, SEEK_CUR);

// read data
fread(data,1,fileSize,f);



// decode bits
int i, j, k, rev_j;
for(j = 0, rev_j = h - 1; j < h ; j++, rev_j--) {
    for(i = 0 ; i < w / 8; i++) {
        int fpos = j * lineSize + i, pos = rev_j * w + i * 8;
        for(k = 0 ; k < 8 ; k++)
            img[pos + (7 - k)] = (data[fpos] >> k ) & 1;
    }`enter code here`
}

free(data);
*_w = w; *_h = h;
return img;
}

int main()
{

int w, h, i, j, x, y, b=0, butpos=0;

//Get array data

unsigned char* imgtable = read_bmp("table.bmp", &w, &h);
int table[w][h];

printf("w=%i \n", w);
printf("h=%i \n", h);

//make table array

 for(j = 0 ; j < h ; j++)
{

    for(i = 0 ; i < w ; i++)
        table[j][i] = imgtable[j * w + i] ? 0 : 1;

}

【问题讨论】:

  • 现在可能是开始学习如何使用调试器的好时机。
  • 我尝试使用 Valgrind 但出现配置错误
  • 从 gdb 开始 - 这应该可以让您快速轻松地解决问题。
  • 我运行 gdb 并得到以下信息 - 程序收到信号 SIGSEGV,分段错误。 /gnu/gcc/releases/respins/4.5.3-3/gcc4-4.5.3-3/src/gcc-4.5.3/libgcc/../gcc/config/i386/cygwin.asm的_alloca(): 45 45 在 /gnu/gcc/releases/respins/4.5.3-3/gcc4-4.5.3-3/src/gcc-4.5.3/libgcc/../gcc/config/i386/cygwin.asm跨度>
  • 不要只是“运行 gdb”——单步调试代码,检查每一步的局部变量,看看代码是否真的按预期运行。在我看来,您尝试读取的字节数比文件中实际存在的字节数多,对于初学者来说,除此之外可能还有其他错误。

标签: c memory-management segmentation-fault


【解决方案1】:

您正在尝试在堆栈上分配图像数据。当图像太大时,这会导致堆栈溢出。这段代码就是问题所在:

int main()
{

    int w, h, i, j, x, y, b=0, butpos=0;

    //Get array data

    unsigned char* imgtable = read_bmp("table.bmp", &w, &h);
    int table[w][h];  // <-- HERE
    ...

这是使用 C99 的一项称为可变长度数组 (VLA) 的功能,其中一个非常量大小的数组(在本例中为 2D w by h 数组,其中wh 直到运行时才知道)在堆栈上分配。

在您的堆栈跟踪中提到函数 _alloca 应该已经提示您这一点 - alloca(3) 函数在堆栈上分配动态内存量。而且由于您没有在任何地方明确地调用alloc(),它一定来自VLA的使用。

正如您所提到的,解决方法是将图像数据分配在堆上,而不是在堆栈上:

data = malloc(h * w * sizeof(*data));
table = malloc(h * sizeof(*table));
for (i = 0; i < h; i++)
{
    table[i] = &data[i * w];
}

...

free(table);
free(data);

【讨论】:

    【解决方案2】:

    如果有人遇到类似的问题,那似乎是内存分配的问题。

    以下解决方案对我有用;

    unsigned char* img = read_table("table.bmp", &w, &h); 
    int *data;
    int **table;   
    
    data = malloc(h * w * sizeof(*data));
    table = malloc(h * sizeof(*table));
    for (i = 0; i < h; ++i)
    {
        table[i] = &data[i * w];
    }   
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-14
      • 2015-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多