CS50 Pset4 Recover程序无法正确恢复图像,求调试帮助
CS50 Pset4 Recover 代码调试问题
以下是我的作业代码:
#include <stdio.h> #include <stdlib.h> #include <stdint.h> typedef uint8_t BYTE; int main(int argc, char *argv[]) { if (argc < 2 || argc > 2) { printf("Usage: ./recover IMAGE\n"); return 1; } FILE *file = fopen(argv[1], "r"); if (file == NULL) { printf("Could not open file.\n"); return 1; } char filename[8]; BYTE arr1[512]; int count = 0; int i = 0; FILE *img; while (fread(arr1, sizeof(BYTE), 512, file) != 0) { if (arr1[0] == 0xff && arr1[1] == 0xd8 && arr1[2] == 0xff && (arr1[3] & 0xf0) == 0xe0 && count == 0) { sprintf(filename, "%03i.jpg", count); count++; img = fopen(filename, "w"); fwrite(arr1, sizeof(BYTE), 512, img); } else if (arr1[0] != 0xff && arr1[1] != 0xd8 && arr1[2] != 0xff && (arr1[3] & 0xf0) != 0xe0 && count != 0) { fwrite(arr1, sizeof(BYTE), 512, img); } else if (arr1[0] == 0xff && arr1[1] == 0xd8 && arr1[2] == 0xff && (arr1[3] & 0xf0) == 0xe0 && count != 0) { fclose(img); sprintf(filename, "%03i.jpg", count); count++; img = fopen(filename, "w"); fwrite(arr1, sizeof(BYTE), 512, img); } else { continue; } } fclose(file); }
代码可正常编译,能识别出50张图像,但恢复的图像不匹配,且存在内存问题。check50检测结果如下:
:) recover.c exists. :) recover.c compiles. :) handles lack of forensic image :( recovers 000.jpg correctly recovered image does not match :( recovers middle images correctly recovered image does not match :( recovers 049.jpg correctly recovered image does not match :| program is free of memory errors can't check until a frown turns upside down
问题分析与修正
1. 非JPEG块写入条件逻辑错误
第二个else if的条件完全错误:你写的arr1[0] != 0xff && arr1[1] != 0xd8 && arr1[2] != 0xff && (arr1[3] & 0xf0) != 0xe0要求四个字节同时不符合JPEG头特征才写入,但实际上只要当前块不是完整JPEG头,就应该写入到当前打开的文件中。正确条件应为判断当前块不是JPEG头,即!(arr1[0] == 0xff && arr1[1] == 0xd8 && arr1[2] == 0xff && (arr1[3] & 0xf0) == 0xe0)。
原条件会漏掉大量应写入的块,导致恢复的图像数据不完整,自然和正确图像不匹配。
2. 未关闭最后一个打开的图像文件
循环结束后仅关闭了源文件file,但最后一个打开的img文件未关闭,会导致该文件缓冲区数据未完全写入磁盘,同时造成内存泄漏,触发内存错误检测问题。
3. 未初始化img指针
FILE *img;未初始化为NULL,若源文件开头无JPEG头,img会成为野指针,存在潜在内存访问风险。
修正后的代码
#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 IMAGE\n"); return 1; } FILE *file = fopen(argv[1], "r"); if (file == NULL) { printf("Could not open file.\n"); return 1; } char filename[8]; BYTE arr1[512]; int count = 0; FILE *img = NULL; // 初始化指针为NULL while (fread(arr1, sizeof(BYTE), 512, file) == 512) // 严谨判断是否读满512字节 { // 检测JPEG头 if (arr1[0] == 0xff && arr1[1] == 0xd8 && arr1[2] == 0xff && (arr1[3] & 0xf0) == 0xe0) { // 若已打开图像文件,先关闭 if (img != NULL) { fclose(img); } // 创建新文件 sprintf(filename, "%03i.jpg", count); img = fopen(filename, "w"); count++; // 写入当前块 fwrite(arr1, sizeof(BYTE), 512, img); } // 若已打开图像文件,且当前块不是JPEG头,继续写入 else if (img != NULL) { fwrite(arr1, sizeof(BYTE), 512, img); } // 否则(未找到第一个JPEG头),跳过当前块 else { continue; } } // 关闭最后一个打开的图像文件 if (img != NULL) { fclose(img); } fclose(file); return 0; }
额外优化说明
- 将
argc判断简化为argc != 2,逻辑更清晰。 - 循环条件改为
fread(...) == 512,确保每次读取完整的512字节块(题目中源文件按512字节对齐,此判断更严谨)。 - 重构条件判断逻辑,去掉冗余重复判断,代码更简洁易读。
内容的提问来源于stack exchange,提问作者SeveredAsif
相关产品推荐
相关产品推荐

