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

C语言JPG恢复程序出现段错误(疑为指针/数组问题)

存储卡JPG恢复程序段错误排查与修复

核心错误点分析

  • 重复读取导致数据异常:while循环头部已经完成一次512字节块的读取,但在分支逻辑中又重复调用fread,导致每次循环实际读取2个块,不仅跳过了匹配到JPG头的关键块,还会在文件末尾触发无效读取,引发后续操作的非法内存访问。
  • 未初始化指针非法访问:在找到第一个JPG之前,img指针为NULL,此时else分支直接调用fwrite写入img,必然触发段错误。
  • 变量重定义与内存操作错误:在第一个JPG的处理分支中,重定义了file_name变量,覆盖了外部的命令行参数指针,最后free(file_name)实际是在释放系统管理的argv指针,属于非法操作;同时分支内malloc的文件名指针未被释放,造成内存泄漏。
  • JPG头判断逻辑错误:(buffer[3] & 0xf0) == 0不符合JPG文件规范,正确的第四字节应该是0xe0-0xef区间,即(buffer[3] & 0xf0) == 0xe0。

修正后的完整代码

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

typedef uint8_t BYTE;

int main(int argc, char *argv[])
{
    // 校验命令行参数数量
    if (argc != 2)
    {
        printf("Usage: ./recover <filename>\n");
        return 1;
    }

    // 打开输入的存储卡镜像文件
    FILE *input = fopen(argv[1], "r");
    if (input == NULL)
    {
        printf("file <%s> could not be opened\n", argv[1]);
        return 1;
    }

    const int BLOCK_SIZE = 512;
    BYTE buffer[BLOCK_SIZE];
    int jpeg_counter = 0;
    FILE *img = NULL;
    char output_filename[17]; // 固定长度足够存储"XXX.jpg"格式的文件名

    // 循环读取每个512字节块
    while (fread(buffer, sizeof(BYTE), BLOCK_SIZE, input) == BLOCK_SIZE)
    {
        // 判断当前块是否为JPG文件起始签名
        if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
        {
            // 如果已有打开的JPG文件,先关闭
            if (img != NULL)
            {
                fclose(img);
            }

            // 生成输出文件名(000.jpg, 001.jpg...)
            sprintf(output_filename, "%.3i.jpg", jpeg_counter);
            img = fopen(output_filename, "w");
            if (img == NULL)
            {
                fclose(input);
                return 1;
            }

            // 将当前块写入新的JPG文件
            fwrite(buffer, sizeof(BYTE), BLOCK_SIZE, img);
            jpeg_counter++;
        }
        // 若已处于JPG写入状态,继续写入当前块
        else if (img != NULL)
        {
            fwrite(buffer, sizeof(BYTE), BLOCK_SIZE, img);
        }
    }

    // 关闭所有打开的文件,释放资源
    if (img != NULL)
    {
        fclose(img);
    }
    fclose(input);

    return 0;
}

关键修正说明

  • 移除重复读取操作:仅在循环头部执行一次fread,后续直接使用buffer中的数据,确保每个块都被正确处理,不会跳过关键数据。
  • 增加空指针校验:在写入操作前检查img是否有效,避免对未初始化指针的非法访问。
  • 优化文件名存储:改用固定大小的字符数组存储输出文件名,避免malloc/free带来的内存管理错误和泄漏。
  • 修复JPG头判断:修正第四字节的判断逻辑,符合JPG文件的起始签名标准。
  • 完善资源清理:确保所有打开的文件都被正确关闭,避免资源泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 13:55:18