CS50 的 pset4 上的分段错误

Segmentation Fault on CS50's pset4

我快把自己逼疯了,想弄清楚我的代码发生了什么。

我目前在 CS50 的 pset4 中。恢复挑战。

对于那些不知道它是关于什么的人: 我们得到了一个名为 card.raw 的文件,其中有一些已删除的照片。我们的任务是实施一个程序,该程序可以(田园诗般地)进行一些取证并恢复丢失的照片。

特此附上我的代码:

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

这是棘手的部分:

我已经成功恢复了所有问题图像。 但是,如果我多次 运行 代码,比方说,5 次,我最终会出现分段错误。

当我 运行 check50 时,我收到以下消息(我将在成功 运行s 和 check50 veredict 后附上包含分割错误的图像)。 Click here to see the image

我就是听不懂。我想可能是内存有问题,但我只是不知道它是什么。

非常感谢您的宝贵时间和您的帮助。 Whosebug 始终是寻求指导的好地方。

编辑

如果我 运行 echo $? 一旦出现分段错误提示,我得到值 139。

Here's the terminal prompt screenshot

编辑

正如@Thomas Dickey 指出的那样,无论是否打开文件,程序都在写入文件。

我已经更新并修复了一些我的代码以使其更清晰,并添加了一个 if 条件以修复它。

解决方法如下:

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

}

如果 header 看起来没问题,程序只会打开输出文件,但无论如何都会写入输出。如果您读取一个没有 jpeg header 的文件,它就会损坏。