【问题标题】:segmentation fault (c language)分段错误(c语言)
【发布时间】:2021-10-15 15:58:46
【问题描述】:

在 CS50 课程的第 4 周尝试从 raw 文件中恢复 jpgs 时,我遇到了这个 seg fault 错误,我不明白它是为什么或如何引起的,我只能说根据valgrind110 导致此问题

我是 c 语言的新手

int main(int argc, char *argv[])
{
    // check if one command arg is passed
    if (argc > 2 )
    {
        printf("Usage: ./recover image\n");
        return 1;
    }

    // try to open file to read from
    FILE *file = fopen(argv[1], "r");
    if (!file)
    {

        return 1;
    }


    BYTE bytes[512];
    int x =0 ;
    char num[10];


    FILE* output =NULL;

    while (fread(&bytes, 512, 1, file) == 1)
    {
        // first step create file name 
        sprintf(num, "%03i.jpg",x);

        // check for start of jpg file 
        if (bytes[0]==0xff && bytes[1] ==0xd8 && bytes[2]== 0xff && (bytes[3] & 0xf0) == 0xe0 )
        {   
            printf("Found file {%i}", x);
            output = fopen(num , "w");
            fwrite(&bytes ,512 ,1 ,output);
            x++;
        }
        else
        {
            fwrite(&bytes , 512 , 1 , output);
        }
    }
    return 0;
}

valgrind 的输出

==12934== Invalid read of size 4
==12934==    at 0x4A1C521: fwrite (iofwrite.c:37)
==12934==    by 0x4014CA: main (recover.c:110)
==12934==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==12934== 
==12934== 
==12934== Process terminating with default action of signal 11 (SIGSEGV)
==12934==  Access not within mapped region at address 0x0
==12934==    at 0x4A1C521: fwrite (iofwrite.c:37)
==12934==    by 0x4014CA: main (recover.c:110)
==12934==  If you believe this happened as a result of a stack
==12934==  overflow in your program's main thread (unlikely but
==12934==  possible), you can try to increase the size of the
==12934==  main thread stack using the --main-stacksize= flag.
==12934==  The main thread stack size used in this run was 8388608.
==12934== 
==12934== HEAP SUMMARY:
==12934==     in use at exit: 472 bytes in 1 blocks
==12934==   total heap usage: 2 allocs, 1 frees, 4,568 bytes allocated
==12934== 
==12934== LEAK SUMMARY:
==12934==    definitely lost: 0 bytes in 0 blocks
==12934==    indirectly lost: 0 bytes in 0 blocks
==12934==      possibly lost: 0 bytes in 0 blocks
==12934==    still reachable: 472 bytes in 1 blocks
==12934==         suppressed: 0 bytes in 0 blocks
==12934== Rerun with --leak-check=full to see details of leaked memory
==12934== 
==12934== For lists of detected and suppressed errors, rerun with: -s
==12934== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
zsh: segmentation fault  valgrind ./recover card.raw

【问题讨论】:

  • 你能解释一下this
  • @G.M.我也想过,但这不可能。请注意,bytes 衰减为 BYTE*&bytes 变为 *(BYTE[512]) 并转换为 void* 始终到相同的地址,所以问题必须是别的东西。
  • 我会尝试使用地址清理程序运行它以获得更好的错误描述。类似:gcc -O2 -g -fsanitize=address,undefined main.c -o test && ./test valgrind 这里不是很有帮助。
  • 真正的问题应该是:这条线output = fopen(num , "w");成功了吗?另请注意else 声明它可以尝试写入未打开的文件。
  • 将代码分割成更小的块。请注意,您也在泄漏文件描述符。

标签: c cs50 null-pointer


【解决方案1】:

拿这个

int main(int argc, char *argv[])
{
    // check if one command arg is passed
    if (argc > 2 )
    {
        printf("Usage: ./recover image\n");
        return 1;
    }

    // try to open file to read from
    FILE *file = fopen(argv[1], "r");
    if (!file)
    {

        return 1;
    }


    BYTE bytes[512];
    int x =0 ;
    char num[10];


    FILE* output =NULL;

    while (fread(bytes, 512, 1, file) == 1)
    { 
        // check for file start 
        if (bytes[0]==0xff && bytes[1] ==0xd8 && bytes[2]== 0xff && (bytes[3] & 0xf0) == 0xe0 )
        {   
            if (output)
            {
                fclose(output);
            }
            // create file name
            sprintf(num, "%03i.jpg",x);
            printf("Found file {%i}\n", x);
            output = fopen(num , "w");
            fwrite(&bytes ,512 ,1 ,output);
            x++;
        }
        else if (output)
        {
            fwrite(bytes , 512 , 1 , output);
        }
    }  
    if(output)
    {
        fclose(output);
    }
    return 0;
}

注意使用 fclose(output); 关闭文件描述符,正如 Marek R 所指出的那样

【讨论】:

    【解决方案2】:

    变化

    else
            {
                fwrite(&bytes , 512 , 1 , output);
            }
    

    else if (output)
            {
                fwrite(&bytes , 512 , 1 , output);
            }
    

    生成图片 感谢 Marek R 提到 if 文件已打开的评论

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-01
      • 2020-10-20
      • 1970-01-01
      相关资源
      最近更新 更多