cs50 recover.c中的分段错误

时间:2017-03-19 16:46:13

标签: c cs50

这是一个接受文件名作为输入的程序,应恢复该文件中的所有 jpegs 。它一次读取 512字节,检查新jpeg的开始。

程序编译,当我运行它时,虽然它给出了分段错误。请帮我解决这个问题。

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

#define BLOCK 512 

int main(int argc, char *argv[])
{
    // buffer is 512 bytes
    uint8_t buffer[512];
    // declaring Filename;
    char Filename[8];

    if (argc != 2)
    {
        fprintf(stderr, "Input should be exactly one argument!\n");
        return 1;
    }

    char *infile = argv[1];

    FILE *inptr = fopen(infile, "r");
    if (inptr == NULL)
    {
        fprintf(stderr, "Could not open file.\n");
        return 2;
    }

    int jpegcounter = 0;
    FILE *img;

    // check if return value fread is equal to 1
    while (fread(&buffer, BLOCK, 1, inptr) == 1) 
    {

        if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff    && (buffer[3] & 0xf0) == 0xe0)
        {
                // if this is the first jpeg code encountered
                if (jpegcounter == 0)
                {
                    // create first jpeg file
                    sprintf(Filename, "%03d.jpg", jpegcounter);
                    // open the file in writing mode
                    img = fopen(Filename, "w");
                    // write the 512 bytes block into the file
                    fwrite(&buffer, BLOCK, 1, img); 
                }
                // if this is not the first jpeg code encountered
                else
                {
                    fclose(img);
                    // add 1 to jpegcounter for new jpeg name
                    jpegcounter ++;
                    // create the next jpeg file
                    sprintf(Filename, "%03d.jpg", jpegcounter);
                    // open the file in writing mode
                    img = fopen(Filename, "w");
                    // write the 512 bytes block into the file
                    fwrite(&buffer, BLOCK, 1, img);
                }
        }
        // if no new jpeg code is encountered
        else if (buffer[0] != 0xff || buffer[1] != 0xd8 || buffer [2]    != 0xff || (buffer[3] & 0xf0) != 0xe0)
            {
                // write the 512 bytes block into the currently opened file
                fwrite(&buffer, BLOCK, 1, img); // this is the line debugger points out as an error
            }
    }
    // close current image
    fclose(img);
    // close memory card file
    fclose(inptr);
    // success
    return 0;
}

2 个答案:

答案 0 :(得分:0)

问题可能是img未打开。有两种方法可以实现。

img = fopen(Filename, "w");的两个实例中,您都没有检查它是否已打开。它可能会失败。

第二种情况是,如果第一个if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)为假,else if (buffer[0] != 0xff || buffer[1] != 0xd8 || buffer [2] != 0xff || (buffer[3] & 0xf0) != 0xe0)为真,则img将不会打开。

查看没有所有代码的代码,您可以清楚地看到问题。

FILE *img;

while (fread(&buffer, BLOCK, 1, inptr) == 1) 
{
    if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
    {
        // The code in here might not happen.
    }
    else if (buffer[0] != 0xff || buffer[1] != 0xd8 || buffer [2]    != 0xff || (buffer[3] & 0xf0) != 0xe0)
    {
        // img might be uninitialized
        fwrite(&buffer, BLOCK, 1, img);
    }
}

通过观察您总是fwrite(&buffer, BLOCK, 1, img);可以大大简化代码。唯一改变的是它是否属于新文件。

如果我们将img初始化为NULL,我们可以确保始终打开文件句柄。

int jpegcounter = 0;

// Set img to NULL so we can know to open the first file.
// Don't open it here because the input file might be empty.
FILE *img = NULL;

while (fread(&buffer, BLOCK, 1, inptr) == 1) 
{
    // If we need a new file, or if one isn't opened.
    if ( is_new_jpeg(buffer) || img == NULL ) {
        // Close the previous file, if any.
        if( img != NULL ) {
            fclose(img);
        }

        // Open a new file.
        img = open_new_jpeg_file( jpegcounter );

        jpegcounter++;
    }

    fwrite(&buffer, BLOCK, 1, img);
}

// If the input was empty we might not have opened an image.
if( img != NULL ) {
    fclose(img);
}
fclose(inptr);

请注意,我已经移动了打开jpeg文件的逻辑,并检测到文件中的各种标志为自己的函数。这极大地简化了代码,并使测试这些组件变得容易。

答案 1 :(得分:0)

我做了以下修改,以避免将args传递给gdb。

False

这是我放在调试目录中的一个jpeg。 OP代码有效。我成功地完成了代码,直到我返回0;

唯一的问题是原始文件和输出文件之间存在109个字节的差异。可能是EOF条件。

可能是传递的args中存在拼写错误