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

CS50 Pset4 Recover仅恢复4张JPEG而非50张的代码问题排查

CS50 Pset4 recover 任务代码修复

代码无法正常恢复JPEG的核心原因是基础配置和逻辑存在多处错误,具体如下:

核心故障点

  • 块大小配置完全错误:题目使用的存储卡镜像遵循FAT文件系统规范,每个存储块固定为512字节。你定义的BLOCK_SIZE = 152直接导致fread每次读取的数据块边界完全错位,JPEG文件头签名检测逻辑绝大多数时候无法命中正确位置,读取的内容也和实际文件存储顺序不匹配,这是只能找到4张图、内容全错、第一张图写入量异常的最主要原因。
  • JPEG起始块重复写入:检测到JPEG签名的代码分支中,你已经对当前块执行了一次fwrite写入,后续通用写入分支又会对同一块内容执行第二次写入,导致每个JPEG的文件头块重复存储,文件结构直接损坏。
  • 空指针操作隐患:输入文件打开失败的分支中,你对值为NULL的input指针执行fclose,属于C语言未定义行为;程序运行结束时如果没找到任何JPEG,img指针为NULL时直接fclose也会触发同类错误。
  • 文件打开模式错误:读写二进制镜像、图片类二进制文件必须使用二进制模式打开,你用文本模式"w"打开输出文件、"r"打开输入镜像,在Windows环境下会自动转义特殊字节、截断内容,导致写入的图片损坏。
  • 文件关闭判断逻辑不严谨:原代码用name_count > 0判断是否需要关闭上一个打开的图片文件,逻辑耦合度高,一旦计数变量出现异常就会导致文件句柄泄漏。

修复后可正常运行的代码

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

typedef uint8_t BYTE;
const int BLOCK_SIZE = 512;
bool is_a_jpeg(BYTE *buffer);

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

    // 以二进制读模式打开存储卡镜像
    FILE *input = fopen(argv[1], "rb");
    if (input == NULL)
    {
        printf("Could not open file.\n");
        return 2;
    }

    FILE *img = NULL;
    int name_count = 0;
    BYTE buffer[BLOCK_SIZE];
    char filename[8];
    bool found = false;

    // 逐块遍历镜像内容
    while (fread(buffer, BLOCK_SIZE, 1, input) == 1)
    {
        // 检测到新JPEG的文件头签名
        if (is_a_jpeg(buffer))
        {
            // 已经打开过图片文件的话先关闭上一个
            if (found)
            {
                fclose(img);
            }
            // 生成三位序号的文件名
            sprintf(filename, "%03d.jpg", name_count);
            // 以二进制写模式打开新的图片文件
            img = fopen(filename, "wb");
            if (img == NULL)
            {
                fclose(input);
                return 3;
            }
            name_count++;
            found = true;
        }
        // 已定位到图片时写入当前块
        if (found)
        {
            fwrite(buffer, BLOCK_SIZE, 1, img);
        }
    }

    // 释放文件句柄,避免空指针操作
    if (found)
    {
        fclose(img);
    }
    fclose(input);
    return 0;
}

// JPEG签名校验逻辑
bool is_a_jpeg(BYTE *buffer)
{
    return buffer[0] == 0xff &&
           buffer[1] == 0xd8 &&
           buffer[2] == 0xff &&
           (buffer[3] & 0xf0) == 0xe0;
}

修复效果说明

  • 块大小修正为512字节后,读取逻辑完全对齐存储卡的存储边界,JPEG签名检测可以正常命中全部50张图片的起始位置。
  • 移除了重复写入的fwrite调用,每个数据块仅写入一次,不会出现文件内容重复损坏的问题。
  • 所有文件操作切换为二进制模式,兼容Windows、Linux等不同运行环境,不会出现字节转义导致的文件损坏。
  • 调整了文件关闭的判断逻辑,去掉所有空指针fclose操作,避免未定义行为导致的程序异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 12:21:19