C语言读取BMP像素忽略填充报错,求错误原因排查
读取BMP像素时跳过填充的错误分析与修正
问题描述
尝试用C语言读取BMP文件像素并忽略填充,但程序退出码为-1,编译器无具体报错。相关函数代码如下:
void readPixelsBMP(FILE* file, struct Pixel** pArr, int width, int height) { int padding = (width%4); for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { unsigned char b,g,r; fread(&b, sizeof(unsigned char), 1, file); fread(&g, sizeof(unsigned char), 1, file); fread(&r, sizeof(unsigned char), 1, file); pArr[i][j].b = b; pArr[i][j].g = g; pArr[i][j].r = r; if (j == height - 1) { //this line is the problem \/ fseek(file, sizeof(char) * padding, SEEK_CUR); } } } }
期望通过fseek跳过填充但引发错误,现分析错误点并修正:
错误点分析
- 循环顺序完全颠倒:BMP像素数据按行优先存储,外层循环应该遍历行数(
height),内层遍历每行的像素数(width)。你现在外层循环width、内层height,相当于按列读取,不仅逻辑错误,还会导致数组访问越界,触发程序崩溃。 - Padding计算错误:BMP要求每行字节数必须是4的倍数,每个像素占3字节(BGR顺序),正确的padding计算公式是
(4 - (width * 3) % 4) % 4——你直接用width%4,完全没考虑每个像素的3字节,导致计算的填充长度错误。 - 跳过填充的时机错误:填充是在每一行所有像素读取完成后存在的,应该在内层循环(每行像素)结束后执行
fseek,而不是当j == height-1时执行——这个条件判断的是列遍历到最后一行,和行结束毫无关系。 - 数组索引越界:因为循环顺序颠倒,
pArr[i][j]中i是宽度索引、j是高度索引,但二维数组pArr应该是height行width列,直接访问会超出数组边界,导致内存错误。
修正后的代码
void readPixelsBMP(FILE* file, struct Pixel** pArr, int width, int height) { // 正确计算每行的填充字节数 int row_size = width * 3; int padding = (4 - row_size % 4) % 4; // 外层循环遍历行数(height),内层遍历每行的像素数(width) for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { unsigned char b, g, r; // 读取单个像素的BGR分量 fread(&b, sizeof(unsigned char), 1, file); fread(&g, sizeof(unsigned char), 1, file); fread(&r, sizeof(unsigned char), 1, file); // 对应到数组的行和列(i是行,j是列) pArr[i][j].b = b; pArr[i][j].g = g; pArr[i][j].r = r; } // 每行像素读取完成后,跳过填充字节 fseek(file, padding, SEEK_CUR); } }
额外说明
- 确保
pArr已经正确分配内存:是一个height个元素的指针数组,每个指针指向width个struct Pixel的内存块。 - 调用该函数前,文件指针必须已经定位到BMP像素数据的起始位置(即跳过文件头和信息头之后)。
内容的提问来源于stack exchange,提问作者Ashton S
相关产品推荐
相关产品推荐

