首页 > 解决方案 > (已解决)有人可以解释为什么 fread() 不起作用吗?

问题描述

经过几个小时的 cs50 恢复练习后,我遇到了分段错误问题。运行调试器后,我发现分段错误的原因是 的故障fread(memory, 512, 1, file),即使在调用该函数后,memory[]数组仍然为空,因此,分段错误。

我尝试使用malloc(512)而不是 unsigned char 数组,但错误仍然存​​在。有人可以解释为什么会发生这种情况以及如何解决吗?

(PS。对不起我的英语不好)

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

int main(int argc, char *argv[])
{
    // making sure the only user input is the name of the file
    if (argc != 2)
    {
        printf("Usage: ./recover image\n");
        return 1;
    }

    // open the file and check if it works
    FILE *file = fopen("card.raw", "r");

    if (file == NULL)
    {
        printf("Could not open card.raw.\n");
        return 2;
    }



    int ending = 1000;
    int count = 0;
    char img = '\0';
    FILE *picture = NULL;
    unsigned char memory[512];
    do
    {
        //creating buffer and reading the file into the buffer
        fread(memory, 512, 1, file);

        //checking if the block is a new jpg file
        if (memory[0] == 0xff && memory[1] == 0xd8 && memory[2] == 0xff && (memory[3] & 0xf0) == 0xe0)
        {

            //if it's the first jpg file
            if (count == 0)
            {
                sprintf(&img, "000.jpg");
                picture = fopen(&img, "w");
                fwrite(&memory, 512, 1, picture);
            }
            //closing previous jpg file and writing into a new one
            else
            {
                fclose(picture);
                img = '\0';
                sprintf(&img, "%03i.jpg", count + 1);
                picture = fopen(&img, "w");
                fwrite(&memory, 512, 1, picture);
            }
        }
        //continue writing into the file
        else
        {
            picture = fopen(&img, "a");
            fwrite(&memory, 512, 1, picture);
        }

        count++;
    }
    while(ending >= 512);

    fclose(file);
    fclose(picture);

    return 0;
}

标签: ccs50

解决方案


如果您使用的是 C 或 C++,那么您应该充分了解所使用的内存模型。例如,声明一个字符局部变量,意味着在堆栈中分配 1 到 4 个字节的内存,具体取决于所使用的内存对齐和体系结构(16 位?32 位?64 位?)。猜猜当你对这样的字符局部变量执行超过 4 个字符的 sprintf 时会发生什么。它将溢出到占据 img 变量之后空间的任何变量。因此,您必须准备一个足够大的缓冲区来保存创建文件名所需的字符。在 C 语言中,如果你犯了错误,有几种可能性:

  • 有时你在犯错后会出现分段错误
  • 有时您没有收到任何错误,但数据已悄然损坏
  • 有时在错误完成后很久就会发生错误

您的代码还有其他问题,Weather Vane 和 Jabberwocky 在上面的评论中已经指出了这一点。我想补充一点,重新打开'img'文件并丢弃以前的文件句柄也不是一件好事(你已经说过继续写?为什么需要重新打开?)。您可能会得到一个悬空的文件句柄或在迭代期间不必要地创建许多文件句柄。C 不会帮你检查这些东西,它假设你真的知道你在做什么。即使混合类型也不会导致编译错误或可识别的运行时错误。它只会做我上面所说的三件事之一。

您可能想使用其他具有更多内存安全功能的现代语言来学习编程,例如 C#、Java 或 Python。


推荐阅读