我的recover.c代码正确恢复了jpegs但没有通过cs50检查

时间:2016-11-26 18:22:58

标签: c cs50

这是代码。我是C语言的初学者,所以任何缩短我的代码的建议都将非常感激。我检查了所有50个图像,它们看起来很完美,但代码没有通过cs50检查。

int main(void)
{
    FILE* source = fopen("card.raw", "r");



    uint8_t jpg[512];
    int direct = 0;
    int jpgcounter = 0;
    uint8_t checkjpg[4];
    FILE* outputfile ;
    char filename[7] ;

    while(feof(source) == 0)
    {
        fread(jpg,512,1,source);

        for (int i = 0 ; i < 4 ; i++)
        {
            checkjpg[i] = jpg[i];
        }

        if( checkjpg[0] == 0xff && checkjpg[1] == 0xd8 && checkjpg[2] == 0xff && checkjpg[3] >= 0xe0 && checkjpg[3] <= 0xef )
        {

            if ( direct == 0 )
            {
              sprintf( filename, "%03d.jpg" , jpgcounter);
              outputfile = fopen(filename, "w");
              fwrite(jpg,512,1,outputfile);
              direct = 1;
            }
            else
            {
                fclose(outputfile);
                jpgcounter++;
                sprintf( filename, "%03d.jpg" , jpgcounter);
              outputfile = fopen(filename, "w");
              fwrite(jpg,512,1,outputfile);
            }

        }
        else
        {
           fwrite(jpg,512,1,outputfile) ;
        }
    }
    fclose(outputfile);
    fclose(source);
    return 0;
}

现在主要的问题是它没有通过cs50检查所以必须有一些我在card.raw或其他东西上遗漏的数据,人眼无法检测图像中的这些错误,但计算机可以。

1 个答案:

答案 0 :(得分:1)

我想我知道问题所在。您永远不会初始化outputfile。作为初学者,您应该在声明变量时始终初始化变量。永远不要写

int i;

int i = ...;

并给它一个初始值(0-1INT_MAX,无论你喜欢什么)。这对于指针非常重要。如果你写

FILE * outputfile;

指针指向哪里?嗯,它是随机的。它可能指向任何地方或任何地方。这是&#34;无效&#34;指针,在任何情况下都不能使用outputfile,因为任何使用的结果都是未定义的。但是你怎么知道它被初始化了?好吧,你不能!您无法为其分配任何可以检查的值。

更好的代码将是

FILE * outputfile = NULL;

因为现在outputfile有一个定义的值,它是NULL,这意味着您可以测试它是否已初始化

if (outputfile == NULL) {
    // Not initialized
} else {
    // Initialized
}

查看您的代码并考虑以下事项:
如果您的循环第一次运行并且第一个512字节块与0xffd8ff..的if-test不匹配会发生什么?然后你以else-case结束,这个案例做了以下

fwrite(jpg,512,1,outputfile) ;

但这里有什么价值outputfile?没有价值,它完全没有定义。您可以在任何地址访问内存,这很可能会使您的应用程序崩溃,这正是您遇到的情况。如果您已将outputfile初始化为NULL,那么正确的代码就是:

} else if (outputfile != NULL) {
    fwrite(jpg,512,1,outputfile);
}

这里有一个超级美化,清理过的代码版本。代码未经测试,我只知道它编译。我知道它也变得更大,但请考虑还有大量的评论,代码是检查和处理所有预期的错误,甚至打印到STDERR出了什么问题。如果我想要,我可以轻松压缩down to 58 lines,这比问题中的代码多7行,但是您的代码没有捕获或打印所有这些错误:

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

int main ( void ) {
    FILE * inputFile = fopen("card.raw", "r");
    if (!inputFile) { // Same as "if (inputFile == NULL)"
        fprintf(stderr, "Cannot open input file!\n");
        // Don't close it, it didn't open!
        return 1;
    }

    // Always declare variables in the smallest possible scope!
    // Don't declare anything here you only need in the loop and
    // whose value doesn't need to survive a loop iteration.
    int fileCounter = 0;
    FILE * outputFile = NULL;
    bool writeError =  false;

    for (;;) { // Endless loop, will never terminate on its own
        uint8_t cluster[512];
        // It will read one cluster or nothing at all.
        if (fread(cluster, sizeof(cluster), 1, inputFile) != 1) {
            // If we have an open output file, close it.
            if (outputFile) {
                fclose(outputFile);
                outputFile = NULL; // Not required but good style.
            }
            break; // Terminates the loop!
            // Not reached, code flow continues after the loop.
        }

        // Check if start of new _or first_ JPG file.
        if (cluster[0] == 0xFF && cluster[1] == 0xd8
            && cluster[2] == 0xFF && cluster[3] >= 0xE0 && cluster[3] <= 0xEF
        ) {
            char filename[8];
            snprintf(filename, sizeof(filename), "%03d.jpg", fileCounter++);

            // Start nof an new JPG file.
            // If we have an "old" one, time to close it
            if (outputFile) {
                fclose(outputFile);
            }
            // Open new file
            outputFile = fopen(filename, "w");
            if (!outputFile) {
                // Cannot create output file.
                writeError = true;
                break; // Terminates the loop!
                // Not reached, code flow continues after the loop.
            }
        }

        // If we have an output file, write the cluster to it.
        if (outputFile) {
            if (fwrite(cluster, sizeof(cluster), 1, outputFile) != 1) {
                // Write error.
                writeError = true;
                // Close the file.
                fclose(outputFile);
                break; // Terminates the loop!
                // Not reached, code flow continues after the loop.
            }
        }
    }

    // If we end up here, we ran into one of the "breaks"
    // and now need to find out which one.
    bool exitWithError = false;
    if (writeError) {
        exitWithError = true;
        fprintf(stderr, "Counldn't create/write to output file!\n");
    } else if (ferror(inputFile) != 0) {
        exitWithError = true;
        fprintf(stderr, "Counldn't read from input file file!\n");
    }
    // Otherwise input file was just at the end.

    // Final clanup:
    fclose(inputFile);

    return (exitWithError ? 1 : 0);
}

我与您分享此代码,因为只需了解其他人如何编写代码,学习某些编码概念可能最简单。