【问题标题】:CS50 Recover Problem- recovered images do not matchCS50 恢复问题 - 恢复的图像不匹配
【发布时间】:2020-11-07 04:50:16
【问题描述】:

check50 v3.1.2 生成的 cs50/problems/2020/x/recover 结果 :) recover.c 存在。
:) recover.c 编译。
:) 处理缺乏法医图像
:( 正确恢复 000.jpg 恢复的图像不匹配
:( 正确恢复中间图像 恢复的图像不匹配
:( 正确恢复 049.jpg 恢复的图像不匹配

我不知道我为什么会遇到这个问题。请帮助我,这可能是因为我对文件基础或其他内容不清楚。

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

typedef uint8_t BYTE;

int main(int argc, char *argv[])
{
    //to check for command-line arguments
    if( argc !=2 )
    {
        printf("Usage: ./recover imagename");
        return 1;
    }
    
    //file pointer from where to read
    FILE *inptr = fopen(argv[1], "r");

    if( inptr == NULL)
    {
        fprintf(stderr, "File couldn't open");
        return 1;
    }

    BYTE buffer[512]; //buffer for storing input data from file
    char FILENAME[8]; //output file name storage
    int counter=0; //to handle naming of file
    FILE *outptr = NULL; //file pointer where to write

    while(fread(buffer, 512, 1, inptr))
    {
        if(buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
        {
            sprintf(FILENAME, "%03i.jpg", counter);
            outptr = fopen(FILENAME, "a");
            if(outptr != NULL)
            {
                fclose(outptr);
                counter++;
            }
        }
        if(outptr != NULL)
        {
            fwrite(buffer, 512, 1, outptr);
        }
    }
    fclose(outptr);
    fclose(inptr);
}

【问题讨论】:

  • 您需要先将关闭文件的位置移动到打开新文件的位置。现在你打开它并立即关闭它。您还应该使用“wb”作为模式。
  • first if(outptr != NULL) 块[跟随 fopen] 移动到上面 @987654326 @。我们要关闭 previous 打开的输出文件。正如你所拥有的那样,关闭序列紧跟 new 文件的打开序列之后。如果您仍然遇到问题,请参阅我对cs50 的回答 [无耻自我宣传] 在此处恢复:stackoverflow.com/questions/64638544/…
  • 有人请把评论变成答案。

标签: c cs50 recover


【解决方案1】:

您的代码有一个块乱序导致您创建空文件。在您的代码中,您有以下内容:

        sprintf(FILENAME, "%03i.jpg", counter);
        outptr = fopen(FILENAME, "a");
        if(outptr != NULL)
        {
            fclose(outptr);
            counter++;
        }

使用sprintf() 创建新文件名,然后使用fopen() 打开文件。如果打开成功,您立即使用fclose()关闭文件并在将任何内容写入文件之前增加counter。不是你想要的。

相反,您想检查当前是否打开了一个输出文件,如果是,您想关闭当前文件,然后打开下一个输出文件进行写入。 (建议使用 mode "wb" 而不是 "a" 打开)。重新排列,您将拥有:

            if(outptr != NULL)  /* if output file open, close before opening next */
            {
                fclose(outptr);
                counter++;
            }
            sprintf(FILENAME, "%03d.jpg", counter);
            outptr = fopen(FILENAME, "wb");     /* open in write, not append mode */

现在您的文件将保持打开状态,因此您可以将恢复的 jpg 写入文件。

避免硬编码文件名或使用幻数

您可以使用文件名,但您应该为代码中使用的数字声明常量。为什么?当您在代码顶部#define 一个常量时,您提供了一个方便的位置来调整任何固定值,而无需选择所有循环限制和函数调用来进行更改。此外,在为文件名等声明缓冲区时,不要吝啬缓冲区大小...。将 1000 个字符过长的缓冲区设置为一个字符过短会好得多。

您可以简单地使用#define 来定义一个或多个常量,或者使用全局enum 来实现相同的目的。在这里你可以这样做:

#define BLKSZ  512      /* if you need a constant, #define one (or more) */
#define MAXFN 1024      /*         (don't skimp on buffer size)          */
...

然后你的用途是:

    ...
    BYTE buffer[BLKSZ];     /* don't use MagicNumbers, use a constant */
    char FILENAME[MAXFN];   /* ditto */
    ...
    while (fread(buffer, BLKSZ, 1, inptr))
    {
        if (buffer[0] == 0xff && buffer[1] == 0xd8 && 
            buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
        {
            if(outptr != NULL)  /* if output file open, close before opening next */
            {
                fclose(outptr);
                counter++;
            }
            sprintf(FILENAME, "%03d.jpg", counter);
            outptr = fopen(FILENAME, "wb");     /* open in write, not append mode */
        }
        if(outptr != NULL)
        {
            fwrite(buffer, BLKSZ, 1, outptr);
        }
    }

(注意:你想通过换行来控制长行,以防止不必要的换行,这会使代码难以阅读。最近 Linux 内核样式指南提出了建议的字符- 80 到 100 个字符的行——不过,在 StackOverflow 上,您会注意到您的行开始需要滚动条,超过 90 个字符)

现在,如果有任何变化,您需要更改两个简单的常量。

通过重新排序 fclose() 调用,您的程序现在可以很好地恢复来自 card.raw 的所有 50 个 jpg 文件。

如果您还有其他问题,请告诉我。

【讨论】:

  • @DavidRankin,它帮助很大,下次我会记得添加常量而不是使用幻数。一切都注意到了!
  • 很好,很高兴为您提供帮助。还请查看我和@CraigEstey 在您最初的问题下留下的链接,以了解编写恢复程序的另外两种方法。使用相同的部分,然后只需添加一些额外的注意事项或方法来完成每个部分。祝你的编码好运!
  • 谢谢@RetiredNinja!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多