You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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);
}

关键修复说明

  1. 改为指针传递:store_img和is_BMP函数接收结构体指针,确保主函数中的变量能被正确更新。
  2. 处理BMP行对齐:计算每行实际字节数,读取和写入时分别跳过/补充填充字节,避免数据错位。
  3. 添加暂停逻辑:主函数末尾加入getchar(),让程序执行完后等待用户输入,防止闪退。
  4. 调用BMP校验:在主函数中读取文件头后调用is_BMP验证格式,提前终止错误流程。
  5. 优化调色板读取:根据biClrUsed动态读取调色板数量,兼容不同格式的256色BMP。

内容的提问来源于stack exchange,提问作者hojun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 04:47:33