分段错误:CS50 recover.c

Segmentation Fault: CS50 recover.c

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

当我 运行 程序编译时,它给出了一个分段错误。请告诉我如何解决这个问题。

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

int main(int argc, char *argv[])
{
    // check for proper usage
    if (argc != 2)
    {
        printf("Usage: 1 command line argument\n");
        return 1;
    }

    // check if file can be opened
    FILE *file = fopen(argv[1], "r");
    if (file == NULL)
    {
        printf("Cannot be opened\n");
        return 2;
    }

    // read 512 bytes into buffer until end of card
    int buffer[128];
    int counter;
    counter = 0;
    char filename[8];
    FILE *img = NULL;

    while(fread(buffer, 4, 128, file) == 128)
    {
        //check if start of new JPEG
        if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
        {
            //check if first JPEG
            if (counter == 0)
            {
                sprintf(filename, "%03i.jpg", counter);
                img = fopen(filename, "w");
                fwrite(buffer, 4, 128, img);
                counter += 1;
            }
            else if (counter > 0)
            {
                fclose(img);
                sprintf(filename, "%03i.jpg", counter);
                img = fopen(filename, "w");
                fwrite(buffer, 4, 128, img);
                counter += 1;
            }
        }
        else if (counter > 0)
        {
            fwrite(buffer, 4, 128, img);
        }
    }
    fclose(img);
    fclose(file);
    return 0;
}

fclose(img) 是罪魁祸首。 img 为空。为了找出原因,您可以在 fopen 之后插入一些 printf。这是 link 用于调试将来的任何段错误。

$ ./recover card.raw

  Memory access error: invalid parameter; abort execution.
  # fclose's parameter (0x0) is not a valid FILE pointer.
  # Stack trace (most recent call first) of the error.
  # [0]  file:/recover.c::55, 5
  # [1]  [libc-start-main]

调用 fread(buffer, 4, 128, file) 将 512 个字节读取(如您所说)到 128 个整数的数组中。但是,当您随后使用以下代码测试新 JPEG 文件的开头时:

if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
{
    //...

您正在检查数组中前四个整数中每个整数的低字节,而不是(您应该这样做)检查前四个字节 数组。这四个字节都将在第一个整数元素(buffer[0]).

因此,您的程序将永远找不到新 JPEG 的开头,因此,img 文件将永远不会打开...然后您将调用 fclose 并使用 NULL 文件指针,这是未定义的行为,可能会导致您看到的分段错误。

相反(假设 'endianness' 正确),执行以下检查:

if ((buffer[0] & 0xfffffff0) == 0xffd8ffe0)
{
    //... 

为了允许 'wrong endianness',您可以检查 buffer[0]:

中的任一字节顺序
if ((buffer[0] & 0xfffffff0) == 0xffd8ffe0 || (buffer[0] & 0xf0ffffff) == 0xe0ffd8ff)
{
    //... 

更好的是,只需读取(和写入)缓冲区的内容 - 一个 512 字节的数组,代码如下:

unsigned char buffer[512];
//...
while(fread(buffer, 1, 512, file) == 512)
{
    //...

这样,您可以保持 'JPEG start' 测试原样。