My code for recover.c recovers jpegs correctly but does not pass cs50 check [closed]

六月ゝ 毕业季﹏ 提交于 2019-12-13 23:38:04

问题


Here is the code. I am a beginner at C language so any suggestions to shorten my code will be greatly appreciated. I checked all the 50 images and they look perfect but the code doesn't pass the cs50 check.

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;
}

Now the major problem is that it does not pass cs50 check so there must be some data that i missed on card.raw or something else and the human eye cannot detect these mistakes in the images but the computer can.


回答1:


I think I know what the problem is. You are never initializing outputfile. As a beginner, you should always initialize variables when you declare them. Never write

int i;

write

int i = ...;

and give it an initial value (0, -1, INT_MAX, whatever you like). This is very important for pointers. If you write

FILE * outputfile;

where is that pointer pointing to? Well, it's random. It may point anywhere or nowhere. This is an "invalid" pointer, under no circumstances you must use outputfile now as the result of any usage is undefined. But how would you know it's initialized? Well, you can't! You can't as you never assigned it any value you could check for.

Better code would be

FILE * outputfile = NULL;

as now outputfile has a defined value, it is NULL and that means you can test if it was initialed

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

Look at your code and think about the following:
What happens if your loop runs for the very first time and the first 512 byte chunk does not match the if-test for 0xffd8ff..? Then you end in the else-case and this case does the following

fwrite(jpg,512,1,outputfile) ;

but what value has outputfile here? No value, it's totally undefined. You accessing memory at any address and this is very likely to crash your application which is exactly what happens for you. If you had initialized outputfile to NULL, the correct code would have been:

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

And here comes a super beautified, cleaned up version of the code. The code is untested, I only know it compiles. I know it also got a lot bigger, but please consider there are also tons of comments and the code is checking and handling all expected errors and even prints to STDERR what went wrong. If I want I can compact it easily down to 58 lines, which is only 7 lines more than your code in the question but your code doesn't catch or print all these errors:

#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);
}

I'm sharing this code with you as learning certain coding concepts is probably easiest by just looking how other people write code.



来源:https://stackoverflow.com/questions/40821594/my-code-for-recover-c-recovers-jpegs-correctly-but-does-not-pass-cs50-check

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!