C语言BMP图像加载保存程序无输出闪退问题求助
问题分析与修复方案
你的C语言BMP加载保存代码编译通过但运行无输出、闪退,核心问题集中在参数传递、BMP格式规范处理和程序退出逻辑上,以下是问题点拆解和修复后的完整代码:
核心问题点
- 值传递导致主函数变量未更新:
store_img函数中对BITMAPFILEHEADER和BITMAPINFOHEADER的修改仅作用于函数内的副本,主函数中的原始变量始终是未初始化的垃圾值,不仅打印无效,还可能引发内存访问错误。 - BMP行对齐未处理:BMP图像的每行像素数据必须按4字节对齐,直接读取
xsize*ysize字节会导致数据读取错位,触发内存异常。 - 重复打开文件:主函数和
store_img重复打开输入文件,冗余操作易导致文件指针混乱。 - 无程序暂停逻辑:Windows控制台程序执行完毕后直接退出,用户来不及查看打印信息。
- 未调用BMP校验函数:代码中定义了
is_BMP但未实际调用,无法提前验证文件格式合法性。
修复后的完整代码
#include <stdio.h> #include <windows.h> #define xsize 570 // x尺寸 #define ysize 456 // y尺寸 #define INPUTFILENAME "robot2.bmp" #define OUTPUTFILENAME "testout.bmp" int is_success_open_file(FILE *filename); int is_BMP(BITMAPFILEHEADER *hf); void store_img(BITMAPFILEHEADER *hf, BITMAPINFOHEADER *hInfo, RGBQUAD hRGB[], unsigned int InputImg[xsize][ysize], unsigned int OutputImg[xsize][ysize]); void make_img(BITMAPFILEHEADER *hf, BITMAPINFOHEADER *hInfo, RGBQUAD hRGB[], unsigned int OutputImg[xsize][ysize]); int main(void) { BITMAPFILEHEADER hf; // 文件信息头结构体变量声明 BITMAPINFOHEADER hInfo; // 图像信息头结构体变量声明 RGBQUAD hRGB[256]; // 用于存储调色板信息的数组声明 FILE *fp; // 文件指针 unsigned int InputImg[xsize][ysize]; unsigned int OutputImg[xsize][ysize]; // 输出图像数组 fp = fopen(INPUTFILENAME, "rb"); if (is_success_open_file(fp) == 1) { getchar(); return 1; } // 读取文件头并校验BMP格式 fread(&hf, sizeof(BITMAPFILEHEADER), 1, fp); if (is_BMP(&hf) == 1) { fclose(fp); getchar(); return 1; } // 调用store_img函数,传递指针更新主函数变量 store_img(&hf, &hInfo, hRGB, InputImg, OutputImg); // 打印图像信息 printf("size of BITMAPINFOHEADER = %d\n", hInfo.biSize); // BITMAPINFOHEADER结构体大小 printf("WIDTH OF IMG = %d\n", hInfo.biWidth); // 图像宽度 printf("HEIGHT OF IMG = %d\n", hInfo.biHeight); // 图像高度 printf("BYTE SIZE OF IMG = %d\n", hf.bfSize); // 文件总字节大小 printf("IS IMG BMP? = %hx. if result : 4d42, it means BMP\n", hf.bfType); // 判断是否为BMP文件 printf("NUMBER OF USED COLORS = %d\n", hInfo.biClrUsed); // 实际使用颜色数 printf("BIT PER PIXEL = %d\n", hInfo.biBitCount); // 每像素位数(区分彩色/黑白) fclose(fp); // 暂停程序,避免闪退 printf("\nPress any key to exit..."); getchar(); return 0; } int is_success_open_file(FILE *filename) { if (filename == NULL) { printf("failed to open file\n\n"); return 1; } else { printf("successed to open file\n\n"); return 0; } } int is_BMP(BITMAPFILEHEADER *hf) { if (hf->bfType != 0x4D42) // 判断是否为位图文件 { printf("file is not BMP\n\n"); return 1; } else { printf("file is BMP.\n\n"); return 0; } } void store_img(BITMAPFILEHEADER *hf, BITMAPINFOHEADER *hInfo, RGBQUAD hRGB[], unsigned int InputImg[xsize][ysize], unsigned int OutputImg[xsize][ysize]) { FILE *fp = fopen(INPUTFILENAME, "rb"); if (!fp) return; fread(hf, sizeof(BITMAPFILEHEADER), 1, fp); fread(hInfo, sizeof(BITMAPINFOHEADER), 1, fp); // 读取调色板,根据实际使用颜色数读取,兼容256色BMP int colorCount = hInfo->biClrUsed ? hInfo->biClrUsed : 256; fread(hRGB, sizeof(RGBQUAD), colorCount, fp); // 处理BMP行对齐:每行字节数必须是4的倍数 int rowBytes = ((hInfo->biWidth * hInfo->biBitCount + 31) / 32) * 4; // 定位到像素数据起始位置 fseek(fp, hf->bfOffBits, SEEK_SET); // 逐行读取像素数据,跳过对齐填充字节 for (int y = 0; y < ysize; y++) { fread(InputImg[y], sizeof(unsigned int), xsize, fp); fseek(fp, rowBytes - xsize * sizeof(unsigned int), SEEK_CUR); } fclose(fp); // 复制图像数据到输出数组 for(int i = 0; i < xsize; i++) { for(int k =0; k < ysize; k++) { OutputImg[i][k] = InputImg[i][k]; } } make_img(hf, hInfo, hRGB, OutputImg); } void make_img(BITMAPFILEHEADER *hf, BITMAPINFOHEADER *hInfo, RGBQUAD hRGB[], unsigned int OutputImg[xsize][ysize]) { FILE *fp = fopen(OUTPUTFILENAME, "wb"); if (!fp) return; fwrite(hf, sizeof(BITMAPFILEHEADER), 1, fp); fwrite(hInfo, sizeof(BITMAPINFOHEADER), 1, fp); int colorCount = hInfo->biClrUsed ? hInfo->biClrUsed : 256; fwrite(hRGB, sizeof(RGBQUAD), colorCount, fp); // 处理行对齐,写入时补充填充字节 int rowBytes = ((hInfo->biWidth * hInfo->biBitCount + 31) / 32) * 4; int pixelBytesPerRow = xsize * sizeof(unsigned int); unsigned char padding[3] = {0}; // 最多3个填充字节 for (int y = 0; y < ysize; y++) { fwrite(OutputImg[y], pixelBytesPerRow, 1, fp); // 写入对齐填充字节 int paddingBytes = rowBytes - pixelBytesPerRow; if (paddingBytes > 0) { fwrite(padding, paddingBytes, 1, fp); } } fclose(fp); }
关键修复说明
- 改为指针传递:
store_img和is_BMP函数接收结构体指针,确保主函数中的变量能被正确更新。 - 处理BMP行对齐:计算每行实际字节数,读取和写入时分别跳过/补充填充字节,避免数据错位。
- 添加暂停逻辑:主函数末尾加入
getchar(),让程序执行完后等待用户输入,防止闪退。 - 调用BMP校验:在主函数中读取文件头后调用
is_BMP验证格式,提前终止错误流程。 - 优化调色板读取:根据
biClrUsed动态读取调色板数量,兼容不同格式的256色BMP。
内容的提问来源于stack exchange,提问作者hojun
相关产品推荐
相关产品推荐

