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
相关产品推荐
相关产品推荐

