CS50恢复(Pset4)-无法恢复图像

CS50恢复(Pset4)-无法恢复图像

问题描述:

因此,我正在尝试CS50恢复练习(您需要在存储卡中搜索jpg文件,无论何时找到一个,您都可以打开一个新文件,并将找到的jpg写到新文件中).我的代码可以编译,但是当我运行check50命令时,出现以下错误:

So I'm trying CS50 Recover exercise (where you need to search for jpg files in a memory card and whenever you find one- you open a new file and write the jpg found to the new file). My code compiles but when I'm running the check50 command I'm receiving the following errors:

:( 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

有人可以帮我弄清楚我在做什么错吗?这是我的代码:

Can somebody help me figure out what am I doing wrong? This is my code:

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

int main(int argc, char *argv[])
{
// Checking if the user entered a correct input:
    if (argc!=2)
    {
        printf("You're not using it correctly!\n");
        return 1;
    }
    
// Opening the file in argv[1]
    FILE *f=fopen(argv[1], "r");

// Validating that there's a file in argv[1]
    if(f==NULL)
    {
        printf("File hasn't found\n");
        return 1;
    }
    
    unsigned char bytes[512];
    int counter=0;
    FILE *img= NULL;
    
    while (fread(bytes, 512, 1, f)==1)
    {   
        if (bytes[0]==0xff && bytes[1]==0xd8 && bytes[2]==0xff && (bytes[3]&0xf0)==0xe0)
        {
            // If it's the first jpg found:
            if (counter==0)
            {
                img=fopen("000.jpg", "w");
            }
            else
            {
                fclose(img);
                char filename[8];
                sprintf(filename,"%03i.jpg", counter);
                img= fopen(filename, "w");
                if (img==NULL)
                {
                    printf("Couldn't open file\n");
                    return 1;
                }
            }
            counter++;
            fwrite(bytes, 512, 1, img);
        }   
    }
    fclose(img);
    fclose(f);
}

您的主要问题是您没有正确处理多块文件.

Your primary problem is that you are not handling multiblock files correctly.

仅当当前块具有标题时,才执行 fwrite .否则,您将丢弃数据.

You only do the fwrite if the current block has the header. Otherwise, you are throwing away the data.

这是因为 fwrite 位于检测标题的 if 块内.

That's because the fwrite is inside the if block that detects the header.

如果,您遇到了第一个(即任意)标题,那么您将获得一个开放的输出流.因此,在那之后,您必须对每个循环迭代进行 fwrite .

If you have encountered the first (i.e. any) header, you will have an open output stream. Therefore, after that, you have to do the fwrite on each loop iteration.

由于在进入外循环之前已将 img 设置为 NULL ,因此无需特殊情况 000.jpg

Since you set img to NULL before entering the outer loop, there is no need to special case the 000.jpg

而且,如果输入文件中没有[em]标头,则最终的 fclose 会出现段错误,因为 img 指针将是 NULL .

And, if the input file did not have a header [ever], the final fclose would segfault because the img pointer would be NULL.

我用[修复]注释了这些错误.如果 #if 0 块,我已经包装了旧的/新的代码:

I've annotated the bugs [with fixes]. I've wrapped the old/new code if #if 0 blocks:

#if 0
// old/original code
#else
// new/refactored code
#endif

这是代码:

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

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

    // Checking if the user entered a correct input:
    if (argc != 2) {
        printf("You're not using it correctly!\n");
        return 1;
    }

    // Opening the file in argv[1]
    FILE *f = fopen(argv[1], "r");

    // Validating that there's a file in argv[1]
    if (f == NULL) {
        printf("File hasn't found\n");
        return 1;
    }

    unsigned char bytes[512];
    int counter = 0;
    FILE *img = NULL;

    while (fread(bytes, 512, 1, f) == 1) {
        if (bytes[0] == 0xff && bytes[1] == 0xd8 && bytes[2] == 0xff &&
            (bytes[3] & 0xf0) == 0xe0) {
// NOTE/BUG: no need to special case the first file
#if 0
            // If it's the first jpg found:
            if (counter == 0) {
                img = fopen("000.jpg", "w");
            }
            else {
                fclose(img);
#else
            if (img != NULL)
                fclose(img);
#endif
                char filename[8];

                sprintf(filename, "%03i.jpg", counter);
                img = fopen(filename, "w");
                if (img == NULL) {
                    printf("Couldn't open file\n");
                    return 1;
                }
#if 0
            }
#endif
            counter++;

// NOTE/BUG: this is only executed if the current block has a header string
#if 0
            fwrite(bytes, 512, 1, img);
#endif
        }

// NOTE/FIX: this is the correct placement for the write
#if 1
        if (img != NULL)
            fwrite(bytes, 512, 1, img);
#endif
    }

// NOTE/BUG: if the input file had _no_ header, img will be NULL
#if 0
    fclose(img);
#else
    if (img != NULL)
        fclose(img);
#endif
    fclose(f);
}


这里是完全清理和重构的代码[ #if 0 ]:

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

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

    // Checking if the user entered a correct input:
    if (argc != 2) {
        printf("You're not using it correctly!\n");
        return 1;
    }

    // Opening the file in argv[1]
    FILE *f = fopen(argv[1], "r");

    // Validating that there's a file in argv[1]
    if (f == NULL) {
        printf("File hasn't found\n");
        return 1;
    }

    unsigned char bytes[512];
    int counter = 0;
    FILE *img = NULL;

    while (fread(bytes, 512, 1, f) == 1) {
        if (bytes[0] == 0xff && bytes[1] == 0xd8 && bytes[2] == 0xff &&
            (bytes[3] & 0xf0) == 0xe0) {
            if (img != NULL)
                fclose(img);
            char filename[8];

            sprintf(filename, "%03i.jpg", counter);
            img = fopen(filename, "w");
            if (img == NULL) {
                printf("Couldn't open file\n");
                return 1;
            }
            counter++;
        }

        if (img != NULL)
            fwrite(bytes, 512, 1, img);
    }

    if (img != NULL)
        fclose(img);
    fclose(f);
}