简体   繁体   中英

Segmentation Fault on CS50's pset4

I'm driving myself crazy trying to figure out what is happening with me code.

I'm currently in CS50's pset4. Recover Challenge.

For those who don't know what is it about: We're given a file called card.raw in which there are some deleted photos. Our task is to implement a program that can do a bit of forensics (idyllically) and recover the lost photos.

Hereby I attach my code:

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


int main(int argc, char *argv[])
{
    if (argc != 2)
    {

        fprintf(stderr, "Usage: ./recover file\n");
        return 1;
    }

    //declaring pointer infile and giving the address of argv[1];
    char *infile = argv[1];

    //Opening file
    FILE *raw_data; 
    raw_data = fopen(infile, "r");

    //Checking for NULL error
    if(raw_data == NULL)
    {
        fprintf(stderr, "Could not open file.\n");
        return 2;
    }


    uint8_t buffer[512];                //Delcaring unsigned int variable type. Array of 512 bytes.
    int counter = 0;                    //Declaring counter for counting jpegs files

    FILE *outfile;                    //Setting pointer named outfile for printing here

    char filename[8];                 //declaring 'filename' variable for storing the file's name


    //While we can reads blocks of memory of 512 bytes from raw_data (aka the address from the infile) into buffer:
    while (fread(buffer, 512, 1, raw_data))
    {
        //Condition for tracking the first bytes that form a JPEG file
        if(buffer[0] == 0xff && 
           buffer[1] == 0xd8 && 
           buffer[2] == 0xff &&
          (buffer[3] & 0xf0) == 0xe0)
          {


              if(counter == 0)                              //If this is the 1st file, then name the file with 
                                                            //counter value with 3 digits (%03d)
              {                                             
                  sprintf(filename, "%03d.jpg", counter);   // And 3 digits (%i3)
                  outfile = fopen(filename, "w");           //Open file named outfile in write mode
                  counter++;
              }

              else                              //If this is not the first JPG opened, firstly close the 
              {                                 // current open file, and then open a new one with the 
                  fclose(outfile);              // current counter value and 3 digits for its name
                  sprintf(filename, "%03d.jpg", counter);
                  outfile = fopen(filename, "w");   //Open file named 'outfile' in write mode 
                  counter++;

              }


          }

        fwrite(buffer, 1, sizeof(buffer), outfile); /* Write function that takes buffer data (aka the 
                                                       pointer to the array of elements to be written, 
                                                       writes 1 byte of elements of the syze buffer (512)
                                                       and it writes it to the output, aka 'outfile' */
    }
    fclose(outfile);            //Remember to close the last file once we get out of the while-loop
}

Here's the tricky part:

I've successfully recovered all the problem images. But, if I run the code several times, let's say for example, 5 times, I end up having a Segmentation Fault.

When I run check50, I get the following message (I will attach an image with both the segmentation fault after some successful runs and the check50 veredict). Click here to see the image

I just can't get it. I supose there might be some trouble with memory, but I just don't know what is it.

Thank you very much for your time and your help guys. StackOVerFlow is always such a nice place to seek for guidance.

EDIT

If I run echo $? once the Segmentation Fault has prompted, I get a value of 139.

Here's the terminal prompt screenshot

EDIT

Just as @Thomas Dickey has pointed out, the program was writing on a file regardless of having an open file yet or not.

I've updated and fixed a bit my code in order to keep it cleaner, and added an if condition in order to fix it.

Here's the solution:

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


int main(int argc, char *argv[])
{
if (argc != 2)
{

    fprintf(stderr, "Usage: ./recover file\n");
    return 1;
}

//declaring pointer infile and giving the address of argv[1];
char *infile = argv[1];

//Opening file
FILE *raw_data; 
raw_data = fopen(infile, "r");

//Checking for NULL error
if(raw_data == NULL)
{
    fprintf(stderr, "Could not open file.\n");
    return 2;
}

uint8_t buffer[512];                //Delcaring unsigned int variable type. Array of 512 bytes.

int counter = 0;                    //Declaring counter for counting jpegs files

FILE *outfile;                    //Setting pointer named outfile for printing here

char filename[8];                 //declaring 'filename' variable for storing the file's name


//While we can reads blocks of memory of 512 bytes from raw_data (aka the address from the infile) into buffer:
while (fread(buffer, 512, 1, raw_data))
{
    //Condition for tracking the first bytes that form a JPEG file
    if(buffer[0] == 0xff && 
       buffer[1] == 0xd8 && 
       buffer[2] == 0xff &&
      (buffer[3] & 0xf0) == 0xe0)
      {

          if(counter != 0)                              
          {           
              fclose(outfile);                      //If this is not the first JPG opened, close previous file
          }

          sprintf(filename, "%03d.jpg", counter);  //print stream to 'filename' the value of 'counter' in 3 digits  
          outfile = fopen(filename, "w");           //Open file named outfile in write mode
          counter++;                                //Add 1 to counter

      } 
      if(counter != 0)                          //Don't start writing on a file until the first jpeg is found
      {
        fwrite(buffer, sizeof(buffer), 1, outfile);          /* - Write function that takes buffer data
                                                                    (aka the array of elements to be written) , 
                                                                - Write a block of 512 bytes of elements 
                                                                    (aka the size of buffer), 
                                                                - 1 block of 512 bytes at a time, 
                                                                - And it writes it to the output, aka 'outfile' */
      }                                                         

}
fclose(outfile);            //Remember to close the last file once we get out of the while-loop
return 0;

}

The program only opens the output file if the header looks okay, but writes to the output irregardless. If you read a file that doesn't have a jpeg header, it'll break.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM