首页 > 解决方案 > CS50 PSET4 recover.c - 我只恢复 25 jpg's

问题描述

我正在学习 CS50 课程并卡在 PSET4 上。我编写了一个从 card.raw 中恢复 JPG 的代码。问题是我在运行我的程序后只得到 25 个选择(从 000.jpg 到 024.jpg),应该有 50 个。我不知道为什么会这样。你能给我指点吗:)

我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

char *name[9] = {"card.raw"};
int i;
int a = -1;
char recovered[sizeof "050.jpg"];


uint8_t buffer[512];

int main(int argc, char *argv[])
{
    //Check for valid quantity of command line arguments
    if (argc != 2 || (strcmp (argv[1], *name) != 0))
    {
    printf("Usage: ./recover image\n");
    return 1;
    }

    FILE *card = fopen(argv[1], "r");

    //Check if file card.raw exists
    if (card == NULL)
    {
        printf("Could not open file\n");
        return 1;
    }

    while(fread(&buffer, 512, 1, card))
    {
        if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && ((buffer[3] & 0xf0) == 0xe0))
        {
            a++;
            sprintf(recovered, "%03d.jpg", a);
            FILE *output = fopen(recovered,"w");
            if (output == NULL)
            {
                printf("Could not create file %03d/n",a);
                return 1;
            }
            fwrite(buffer, 512, 1, output);


            while(fread(&buffer, 512, 1, card))
            {
                 if ( !(buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && ((buffer[3] & 0xf0) == 0xe0)))
                 {
                     fwrite(buffer, 512, 1, output);
                 }
                 else
                 {
                     break;
                 }

            }
            fclose(output);

        }
    }
    fclose(card);
    return 0;
}

标签: ccs50recover

解决方案


有几个问题。

你有两个嵌套循环。你只想要一个

当内部循环检测到标题时,您会跳出循环。

但是,只有外循环打开输出文件。

它进行新的读取,因此它永远不会看到内部循环检测到的标头,也不会打开下一个输出文件。

因此,您只能获得一半的输出文件。而且,它们都已损坏,因为它们具有第一个文件中的标头和数据,而只有第二个文件中的数据。这在整个过程中交替重复。

FILE *output是循环范围的。它应该是功能范围的。

recovered以非常规的方式定义。最好只用大量来定义它。这可以防止编译器将其标记为太小。编译器假设a可能是(例如)1000000000,并且sprintf会溢出recovered

name也以非正统的方式定义。

i从未使用过。


这是一个重构和注释的版本。它可以编译,但我没有测试过:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

const char *name = "card.raw";

int a = -1;
char recovered[1000];

uint8_t buffer[512];

int
main(int argc, char **argv)
{

    // Check for valid quantity of command line arguments
    if (argc != 2 || (strcmp(argv[1], name) != 0)) {
        printf("Usage: ./recover image\n");
        return 1;
    }

    FILE *card = fopen(argv[1], "r");

    // Check if file card.raw exists
    if (card == NULL) {
        printf("Could not open file\n");
        return 1;
    }

    FILE *output = NULL;

    while (fread(buffer, sizeof(buffer), 1, card)) {
        // detect new input header
        if ((buffer[0] == 0xff) && (buffer[1] == 0xd8) &&
            (buffer[2] == 0xff) && ((buffer[3] & 0xf0) == 0xe0)) {

            // close previous output stream
            if (output != NULL)
                fclose(output);

            // open new output stream
            ++a;
            sprintf(recovered, "%03d.jpg", a);
            output = fopen(recovered, "w");
            if (output == NULL) {
                printf("Could not create file %03d/n", a);
                return 1;
            }
        }

        // write data to output stream
        // this writes both the header and data for a given output file
        if (output != NULL)
            fwrite(buffer, sizeof(buffer), 1, output);
    }

    // close the last output stream
    if (output != NULL)
        fclose(output);

    fclose(card);

    return 0;
}

推荐阅读