CS50 - Восстановление - Работа с Card.raw PSET3

Итак, я новичок, борющийся (на самом деле тонущий) с C, пытаясь пройти через CS50. Я работаю над упражнением «Восстановить», пытаясь восстановить jpeg из файла card.raw. Через Google я узнал, что, набрав xxd -l 2400 card.raw (символ «L») в терминале, я могу отобразить в терминале байты 0-2384 включительно, которые имеют следующий формат:

0000000: 0000 0000 0000 0000 0000 0000 0000 0000 ................

0000950: 0fe0 c11b e555 8f20 33cc fbfe 559e 8eee .....U. 3...У...

Q1: Я хочу отобразить первые 32 байта (все 0) с помощью printf (чтобы проверить, что читается). Моя программа компилируется, но ничего не отображает. (Конечно, как только у меня это заработает, я изменю его, чтобы отображать больше байтов, так как я знаю, где начинается первый jpeg при просмотре данных в терминале).

Простые ответы приветствуются (если бы я был более опытным, я бы не публиковал такие простые вопросы). Спасибо,

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

int main()
{

    // hardcode opening of card.raw in read binary mode
    FILE *infile = fopen("card.raw", "rb");

    if (infile == NULL)
    {
        fprintf(stderr, "Could not open infile"); 
        return 2;
    } 

    // declare a variable to hold data to be read from infile file, note that a size for it must be specified
    char text[32];

    /* go to the beginning of the card.raw file to start reading */
    fseek(infile, 0, SEEK_SET);

    // text is the variable that will hold what is read, declared above
    // how many to read, how many to read at a time, where to read from
    fread(text, 32, 1, infile);
    printf("%s\n", text);
}

person Mike    schedule 16.02.2019    source источник
comment
Основные вопросы приветствуются, но, пожалуйста, размещайте только один вопрос в каждом.   -  person bishop    schedule 16.02.2019
comment
В шестнадцатеричном дампе число слева — это смещение в данных, а данные представлены шестнадцатеричными данными в середине и представлением этих шестнадцатеричных значений в формате ascii справа. Hexdump текстовый файл, и вы увидите, как это работает.   -  person Retired Ninja    schedule 16.02.2019
comment
Возможный дубликат Невозможно распечатать шестнадцатеричные байты в C   -  person Retired Ninja    schedule 16.02.2019
comment
Вы также можете посмотреть здесь вопросы и ответы, посвященные CS50. cs50.stackexchange.com   -  person Retired Ninja    schedule 16.02.2019


Ответы (2)


Есть пара существенных проблем. Сначала это объявление char text[32];. Напомним, что char имеет очень конкретное значение, оно вычисляется целыми числами от 0 до 255; он "подписан". Это идеально подходит для чтения текста ascii. Вспомните/просмотрите файл bmp.h из resize, чтобы узнать, как следует объявлять данные для чтения данных, которые не являются текстом ascii, например данные изображения.

-- редактировать -- Двоичные данные должны быть "беззнакового" типа данных. В bmp.h автор использовал uint8_t здесь typedef uint8_t BYTE; (что требует #include stdint.h>). Вы можете использовать
unsigned char text[32]

Во-вторых, это printf("%s\n", text);. text объявляется массивом символов. Но помните то, что делает строку строкой? Это завершающий нулевой байт, технически 0. Поэтому, когда вы просите printf напечатать text в виде строки, он напечатает все до первого нулевого байта (0). Который, как вы можете видеть из вашего шестнадцатеричного дампа, является первым байтом в файле.

--edit-- Поскольку вы не можете использовать строковый формат в printf, вы можете печатать вывод по одному символу за раз, как марио или цезарь. Однако, поскольку он беззнаковый, строка формата будет %u вместо %c. Вы можете увидеть его в шестнадцатеричном формате со строкой формата %04x (x — спецификатор для шестнадцатеричного).

person DinoCoderSaurus    schedule 17.02.2019
comment
Спасибо, но ваши намеки все еще выше моей головы. Я знаю, что первые 32 байта равны 0, и просто не знаю, как отобразить их в C или python из файла Card.raw. Я просмотрел файл bmp.h, но не совсем понял разницу между Byte, Dword, Long, Word, на которую, как мне кажется, вы мне указываете. (Меня действительно не волнуют первые 32 байта, я просто хочу напечатать что-то на экране, чтобы видеть, что я обращаюсь к нужным данным). - person Mike; 18.02.2019
comment
Я добавил более конкретную информацию в ответ. Я надеюсь, что это приведет вас на правильный путь. - person DinoCoderSaurus; 18.02.2019

Благодаря DinoCoderSAurus, с вашей (и некоторой другой помощью) я смог выяснить следующее:

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

int main()
{

    // hardcode opening of a file with fopen, in read binary mode
    FILE *infile = fopen("card.raw", "rb");
    // error check, did file open?
    if (infile == NULL)
    {
        fprintf(stderr, "Could not open infile"); 
        return 2;
    }

    // because card.raw contains binary/hex data, must use unsigned char to hold data, 32 bytes chosen at random
    unsigned char dataval[32];

    //    dataval is the variable that will hold what is read, declared above
    //          how many to read, how many to read at a time, where to read from
    fread(dataval, 1, 32, infile);

    //Print bytes (from dataval) one at a time
    for (int i = 0; i < 32; i++)
    {
        printf("%02X ", (int)dataval[i]);
    }
    printf("\n");

    return 0;
}
person Mike    schedule 18.02.2019