Search code examples
cif-statementpointersglobal-variablescs50

Is there anyway to use a file pointer outside of a if condition in C


My problem starts from the while loop. I have an if condition and inside of the if condition I create a file and write to it. But naturally, I can't use the pointer outside of the condition. I'm new to C and I'm looking for a way to make that pointer global variable like in python. Here is my code:

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

//define chunk size
const int chunksize = 512;

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        fprintf(stderr,"Usage: ./recover image\n");
        return 1;
    }

    // open memory card file
    FILE *inptr = fopen(argv[1], "r");
    if (inptr == NULL)
    {
        fprintf(stderr, "Could not open %s.\n", argv[1]);
        return 2;
    }

    //create a variable to store memory size
    fseek(inptr, 0L, SEEK_END);
    long int memorysize = ftell(inptr);
    rewind(inptr);

    //find how many chunk does memory card contain
    int nofchunks = memorysize / chunksize;

    //create a file counter
    int nofjpeg = 0;

    while(nofchunks > 0)
    {
        //create a temporary storage
        unsigned char chunk[chunksize];

        // read a 512 byte chunk from memory card
        fread(&chunk, chunksize, 1, inptr);
        
        FILE *outptr = NULL;

        //check the chunk if it is a JPEG by looking first 4byte of the chunk
        if (chunk[0] == 0xff && chunk[1] == 0xd8 && chunk[2] == 0xff && (chunk[3] & 0xf0) == 0xe0)
        {
            nofjpeg++;

            //create a temporary file name
            char filename[8];

            if (nofjpeg == 1)
            {
                //create a new file name
                sprintf(filename, "%03i.jpg", nofjpeg);

                //open the file in write mode
                outptr = fopen(filename, "w");
                if (outptr == NULL)
                {
                    fprintf(stderr, "Could not open %s.\n", argv[1]);
                    return 2;
                }
                fwrite(&chunk, chunksize, 1, outptr);
            }
            else
            {
                //close the previous file
                fclose(outptr);

                //create a new file name
                sprintf(filename, "%03i.jpg", nofjpeg);

                //open the file in write mode
                outptr = fopen(filename, "w");
                if (outptr == NULL)
                {
                    fprintf(stderr, "Could not open %s.\n", argv[1]);
                    return 2;
                }
                fwrite(&chunk, chunksize, 1, outptr);
            }

        }
        else if(nofjpeg > 1)
        {
        fwrite(&chunk, chunksize, 1, outptr);
        }
        nofchunks--;
    }
}

You can see that inside of the first inner if condition I open the file and write to it. And I need to close that file inside the following else condition. You can also see I also use that pointer following the outer if condition.


Solution

  • Declare the file pointer before the if statement but assign it a null value. It is then available after the if statement. Inside the if statement you can assign it a value which will persist after the if statement. Following the if statement you should check to make sure it's not null before de-referencing it.

    //check the chunk if it is a JPEG by looking first 4byte of the chunk
    FILE *outptr = (FILE*) NULL;   // Declare before the if and assign to NULL cast to type FILE*
    
    if (chunk[0] == 0xff && chunk[1] == 0xd8 && chunk[2] == 0xff && (chunk[3] & 0xf0) == 0xe0)
    {
        nofjpeg++;
    
        //create a temporary file name
        char filename[8];
    
    
        if (nofjpeg == 1)
        {
            //create a new file name
            sprintf(filename, "%03i.jpg", nofjpeg);
    
            //open the file in write mode
            outptr = fopen(filename, "w");   // Assign inside the if statement, but don't declare.
            if (outptr == NULL)
            {
                fprintf(stderr, "Could not open %s.\n", argv[1]);
                return 2;
            }
            fwrite(&chunk, chunksize, 1, outptr);
        }
        else
        {
            //close the previous file  ... this is likely a logical error; it should be NULL at this point, so there's nothing to close.
            if (outptr) fclose(outptr);   // Check to see if pointer is null before use.
    
            //create a new file name
            sprintf(filename, "%03i.jpg", nofjpeg);
    
            //open the file in write mode
            outptr = fopen(filename, "w");
            if (outptr == NULL)
            {
                fprintf(stderr, "Could not open %s.\n", argv[1]);
                return 2;
            }
            fwrite(&chunk, chunksize, 1, outptr);
        }
    
    }
    else if(nofjpeg > 1)
    {
        // This is likely a logical error; outptr will be NULL here
        if (outptr) fwrite(&chunk, chunksize, 1, outptr);
    }
    nofchunks--;