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

CS50 Pset4 recover程序未通过check50检测求助

SD卡图像恢复程序调试求助

我写了个从数码相机SD卡恢复删除图像的程序,运行check50时最后三项检测没通过,000.jpg、中间图像和049.jpg都恢复不出来,还报程序超时等待退出,用调试工具没解决问题,求技术帮助。

我的代码

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

// Buffer to store card data

// recover deleted images
int main(int argc, char *argv[])
{
// count is 2
    if(argc < 2)
    {
        printf("usage: ./recover image.raw\n");
        return 1;
    }
// Read file
char *file = argv[1];

FILE *card = fopen(file, "r");
unsigned char* buffer = malloc(512);

// Check that file is valid
if (fopen(file, "r") == NULL)
{
    printf("could not open %s.\n", file);
    return 1;
}


char* filename = malloc(3 * sizeof(int));

//JPGs created
 int img_count = 0;
 int test_counter = 0;
 FILE *img = NULL;
 
 // Read 512 chars
 while (test_counter == 0)
{
    fread(buffer, sizeof(char), 512, card);
// Detect JPEG
    if(buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && buffer[3] && 0xf0 == 0xe0)
    {

// Write JPEG
            sprintf(filename, "%0x3i.jpg", img_count);
            img = fopen(filename, "w");
            img_count++;

       while (true)
        {
            fread(buffer, sizeof(char), 512, card);

            if(buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && buffer[3] && 0xf0 == 0xe0)
            {
            sprintf(filename, "%0x3i.jpg", img_count);
            img = fopen(filename, "a");
            img_count++;
            test_counter++;
            fwrite(buffer, sizeof(char), 512, img);
            break;
            }
        else
            {
            fwrite(buffer, sizeof(char), 512, img);
            break;
        }
        }


        while (fread(buffer, sizeof(char), 512, card)!= 0)

        if(buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && buffer[3] && 0xf0 == 0xe0)
        {
// Pointer for JPG created
            fclose(img);
            sprintf(filename, "%0x3i.jpg", img_count);
            img = fopen(filename, "a");
            img_count++;
        }

            fwrite(buffer, sizeof(char), 512, img);
        }
}
free(buffer);
fclose(img);
return 0;
}

问题分析与修复方案

核心错误点

  1. 循环逻辑完全混乱

    • 外层while(test_counter == 0)只会执行一次,无法遍历整个raw文件,导致大部分图像没被处理。
    • 内部嵌套的while(true)每次只读取一个512字节块就break,完全没实现“持续写入直到下一个JPEG头出现”的逻辑。
  2. JPEG头检测条件错误
    原代码里buffer[3] && 0xf0 == 0xe0是逻辑错误,正确的JPEG起始第四字节检测应该是(buffer[3] & 0xf0) == 0xe0——需要用位运算判断高四位是否为0xe。

  3. 文件名格式化错误
    sprintf(filename, "%0x3i.jpg", img_count)里的格式符错误:%0x是十六进制输出,这里需要三位十进制的文件名(比如000.jpg),应该用%03d。

  4. 文件操作错误

    • 新建JPEG文件时用"a"追加模式是错的,应该用"w"覆盖模式(因为是新文件)。
    • 重复fopen且未关闭旧文件,会导致文件资源泄漏,还可能写入混乱。
    • 原代码重复打开了两次card文件,应该直接检查第一次fopen返回的card指针是否为NULL。
  5. 未处理文件读取边界
    没有检查fread的返回值,当读到文件末尾(返回值小于512)时,依然按512字节写入,会导致垃圾数据,甚至程序崩溃。

修正后的代码

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

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        printf("usage: ./recover image.raw\n");
        return 1;
    }

    FILE *card = fopen(argv[1], "r");
    if (card == NULL)
    {
        printf("could not open %s.\n", argv[1]);
        return 1;
    }

    unsigned char *buffer = malloc(512);
    if (buffer == NULL)
    {
        fclose(card);
        printf("memory allocation failed.\n");
        return 1;
    }

    char filename[8]; // 足够存"000.jpg" + '\0'
    FILE *img = NULL;
    int img_count = 0;
    size_t bytes_read;

    // 遍历整个raw文件
    while ((bytes_read = fread(buffer, sizeof(unsigned char), 512, card)) > 0)
    {
        // 检测JPEG起始头
        if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
        {
            // 如果之前有打开的图像文件,先关闭
            if (img != NULL)
            {
                fclose(img);
            }

            // 生成新文件名并打开文件
            sprintf(filename, "%03d.jpg", img_count);
            img = fopen(filename, "w");
            if (img == NULL)
            {
                fclose(card);
                free(buffer);
                printf("could not create %s.\n", filename);
                return 1;
            }
            img_count++;
        }

        // 如果当前有打开的图像文件,写入数据
        if (img != NULL)
        {
            fwrite(buffer, sizeof(unsigned char), bytes_read, img);
        }
    }

    // 关闭剩余的文件和释放内存
    if (img != NULL)
    {
        fclose(img);
    }
    fclose(card);
    free(buffer);
    return 0;
}

修正说明

  • 简化了循环逻辑:用一个while循环遍历整个raw文件,每次读取512字节块。
  • 修复了JPEG头检测的位运算逻辑。
  • 文件名格式改为%03d,确保生成三位十进制文件名。
  • 每次检测到新JPEG头时,先关闭之前的图像文件,再创建新文件。
  • 处理了fread的返回值,写入时按实际读取的字节数写入,避免文件末尾的垃圾数据。
  • 增加了内存分配失败的判断,提升程序健壮性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 20:40:25