细分错误:CS50恢复。

时间:2020-05-29 02:58:22

标签: c cs50

该程序接受文件名作为输入,并应恢复该文件上的所有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;
}

2 个答案:

答案 0 :(得分:0)

fclose(img)是元凶。 img为NULL。为了找出原因,您可以在printf之后插入fopen。这是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]

答案 1 :(得分:0)

调用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文件将永远不会打开...然后您用{{1}来调用fclose }文件指针,这是未定义的行为,很可能导致您看到的分段错误。

代替(假设正确的'endianness'),请执行以下检查:

NULL

要考虑“错误的字节序”,您可以检查if ((buffer[0] & 0xfffffff0) == 0xffd8ffe0) { //... 中的任一字节顺序:

buffer[0]

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

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

这样,您可以保持“ JPEG开始”测试不变。