CS50x Pset4 recover程序仅恢复图片部分内容的问题求助
CS50x Pset4 Recover 代码修复指南
你的代码只能恢复图片的部分内容,核心问题出在几个关键细节上,下面逐个拆解并给出修复方案:
核心错误点
- 文件头检测逻辑错误:你写的
buffer[0] = 255是赋值操作,不是比较!这会把buffer的第一个字节强行改成255,不仅导致后续的JPG头检测失效,还会破坏要写入的原始数据。正确写法是buffer[0] == 255。 - 文件名缺少终止符:
img_recovered是长度为8的char数组,但你只赋值了前7个字符(0-6位),没有加字符串终止符'\0'。fopen读取文件名时会越界读取内存垃圾数据,导致文件名错误,无法正确写入文件。 - 频繁开关文件:每读一个512字节块就打开、写入、关闭文件,不仅效率极低,还可能因为文件系统缓存问题导致数据丢失。正确做法是保持当前文件打开,直到遇到新的JPG头再关闭。
- 文件打开模式错误:处理二进制文件必须用二进制模式打开,即读用
"rb",写用"wb",追加用"ab"。虽然CS50的Linux环境下文本模式和二进制模式差异不大,但跨平台会出问题,且符合规范。 - 冗余变量设计:用
j来判断是否开始写入图片不够直观,直接用一个FILE*指针跟踪当前打开的文件更清晰。
修复后的代码
#include <stdint.h> #include <stdio.h> #include <stdlib.h> typedef uint8_t BYTE; int main(int argc, char *argv[]) { if (argc != 2) { printf("Usage: ./recover forensic_image_file\n"); return 1; } // 二进制模式打开取证图片 FILE *for_image = fopen(argv[1], "rb"); if (for_image == NULL) { printf("Could not open %s.\n", argv[1]); return 1; } char img_recovered[8]; int img_count = -1; BYTE buffer[512]; // 跟踪当前打开的图片文件 FILE *current_img = NULL; while (fread(buffer, 1, 512, for_image) == 512) { // 正确检测JPG文件头:0xff 0xd8 0xff 0xe0-0xef if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0) { // 如果已有打开的文件,先关闭 if (current_img != NULL) { fclose(current_img); } img_count++; // 生成标准格式的文件名 sprintf(img_recovered, "%03d.jpg", img_count); // 二进制模式创建新文件 current_img = fopen(img_recovered, "wb"); if (current_img == NULL) { printf("Could not create %s.\n", img_recovered); fclose(for_image); return 1; } // 写入当前块 fwrite(buffer, 1, 512, current_img); } else if (current_img != NULL) { // 如果当前有打开的文件,继续写入 fwrite(buffer, 1, 512, current_img); } } // 循环结束后关闭最后一个打开的文件 if (current_img != NULL) { fclose(current_img); } fclose(for_image); return 0; }
关键修改说明
- 把文件头检测的赋值
=改成比较==,并调整第四个字节的检测为位运算(buffer[3] & 0xf0) == 0xe0,更准确匹配JPG的起始标记范围。 - 用
sprintf生成三位数字的文件名,既简洁又避免手动赋值时的终止符遗漏问题。 - 使用
current_img指针跟踪当前打开的文件,避免频繁开关,直到遇到新JPG头才关闭旧文件。 - 所有文件操作都用二进制模式(
rb/wb),保证二进制数据不被篡改。
内容的提问来源于stack exchange,提问作者Aryan Raj
相关产品推荐
相关产品推荐

