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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 02:05:26