(Решено) Может кто-нибудь объяснить, почему не работает fread ()? - PullRequest
1 голос
/ 07 мая 2020

После пары часов работы над упражнением восстановления cs50 я наткнулся на проблему с ошибкой сегментирования. После запуска отладчика я обнаружил, что причиной ошибки сегментации является неисправность fread(memory, 512, 1, file), даже после вызова функции массив memory[] остается пустым, поэтому возникает ошибка сегментации.

i ' Мы пробовали работать с malloc(512) вместо массива беззнаковых символов, но ошибка не исчезла. Может кто-нибудь объяснить, почему это происходит и как это решить?

(PS. Извините за мой плохой engli sh)

#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;
}

1 Ответ

0 голосов
/ 07 мая 2020

, если вы используете C или C ++, вы должны полностью знать используемую модель памяти. Например, объявление символьной локальной переменной означает выделение от 1 до 4 байтов памяти в стеке, в зависимости от выравнивания памяти и используемой архитектуры (16-битный? 32-битный? 64-битный?). И угадайте, что происходит, когда вы выполняете sprintf более чем из 4 символов в такой локальной переменной символа. Он будет переполнен любой переменной, занимающей пространство после переменной img. Таким образом, вы должны подготовить достаточно большой буфер для хранения символов, необходимых для создания имени файла. В C, если вы допустили ошибку, есть несколько возможностей:

  • иногда возникает ошибка сегментации после того, как вы допустили ошибку
  • иногда вы не получали никакой ошибки, но данные тихо повреждены
  • иногда ошибка возникает спустя долгое время после того, как ошибка была сделана

Есть и другие проблемы с вашим кодом, на которые указали Weather Vane и Jabberwocky в комментариях выше . Я хотел бы добавить, что повторное открытие файла img и сброс предыдущего дескриптора файла тоже нехорошо (вы уже сказали, продолжать писать? Зачем нужно открывать заново?). Вы можете получить висящий дескриптор файла или без необходимости создать множество дескрипторов файла во время итерации. C не поможет вам проверить такие вещи, он предполагает, что вы действительно знаете, что делаете. Даже смешивание типов не вызовет ошибки компиляции или идентифицируемой ошибки времени выполнения. Он просто выполнит одну из трех вещей, о которых я сказал выше. .

...