Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > C++ Builder
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 02.06.2012, 11:52   #1
kleric
Пользователь
 
Регистрация: 27.07.2009
Сообщений: 22
Злость fread и бинарное чтение файла

Всем добрый день.
Прошу помощи у знатоков в решении проблемы))

При считывании файла в бинарном режиме(содержимое файла жирным):
50 49 43 40 50 23 00 4A 50 47 00 00 FF D8 FF E0 00 10

fread считывает как то непонятно(или я не правильно делаю)
Вместо:

PIC
@P#


выводит

PIC@P#
@P#


почему в TFrame.id "записалось" содержимое след. 3 байт?
витчер среды ХЕ2 отображает нормально

но почему при выводе и использовании я зачем то получаю и ещё следующие 3 байта?

Код:
#include <tchar.h>
#include <iostream.h>

struct TFrame
{
	unsigned char id[3];
	unsigned char size[3];
};

int _tmain(int argc, _TCHAR* argv[])
{
    FILE *fp = NULL;

    // открываем
    if ( (fp = _wfopen(L"test.dat", L"rb") ) == NULL )
    {
        return 1;
    }

    // читаем
    TFrame fr;
    fread( &fr, 6, 1, fp );

    fclose(fp);

    printf("%s\n%s", fr.id, fr.size);

    return 0;
}
kleric вне форума Ответить с цитированием
Старый 02.06.2012, 12:22   #2
Гром
Старожил
 
Аватар для Гром
 
Регистрация: 21.03.2009
Сообщений: 2,193
По умолчанию

Потому что printf выводит строку вплоть до первого терминирующего символа ('\0'). Или считывайте отдельно каждое поле, не забывая добавлять в конец каждого массива (строки) этот ноль, либо выводите не printf-ом, а с помощью цикла for строго необходимое количество символов.
Простые и красивые программы - коды программ + учебник C++
Создание игры - взгляд изнутри - сайт проекта
Тема на форуме, посвященная ему же
Гром вне форума Ответить с цитированием
Старый 02.06.2012, 13:27   #3
kleric
Пользователь
 
Регистрация: 27.07.2009
Сообщений: 22
По умолчанию

Цитата:
Сообщение от Гром Посмотреть сообщение
Потому что printf выводит строку вплоть до первого терминирующего символа ('\0'). Или считывайте отдельно каждое поле, не забывая добавлять в конец каждого массива (строки) этот ноль, либо выводите не printf-ом, а с помощью цикла for строго необходимое количество символов.
спасибо за ответ, но объясните мне, пожалуйста,такое поведение ватчера ХЕ2
kleric вне форума Ответить с цитированием
Старый 02.06.2012, 14:03   #4
kleric
Пользователь
 
Регистрация: 27.07.2009
Сообщений: 22
По умолчанию

Цитата:
Сообщение от Гром Посмотреть сообщение
Потому что printf выводит строку вплоть до первого терминирующего символа ('\0'). Или считывайте отдельно каждое поле, не забывая добавлять в конец каждого массива (строки) этот ноль, либо выводите не printf-ом, а с помощью цикла for строго необходимое количество символов.
сделал как вы сказали
Код:
// читаем
    TFrame fr;

    unsigned char a[4];
    fread( a, 3, 1, fp );
    a[3] = '\0';

    unsigned char b[4];
    fread( b, 3, 1, fp );
    b[3] = '\0';

    fclose(fp);

    memcpy(fr.id, a, 3);
    memcpy(fr.size, b, 3);

    cout << fr.id << endl << fr.size << endl;
всёравно выводит

PIC@P#
@P#
kleric вне форума Ответить с цитированием
Старый 02.06.2012, 14:26   #5
veniside
Старожил
 
Регистрация: 03.01.2011
Сообщений: 2,508
По умолчанию

Код:
memcpy(fr.id, a, 3);
смысл было в a[3] заносить \0, если потом его не копировать ) да и копировать его некуда, собственно. Так что по-сути ничего не изменилось, о чём и говорит результат.
"Когда приходит положенное время, человек перестаёт играть в пинбол. Только и всего."
veniside вне форума Ответить с цитированием
Старый 02.06.2012, 14:30   #6
kleric
Пользователь
 
Регистрация: 27.07.2009
Сообщений: 22
По умолчанию

Цитата:
Сообщение от veniside Посмотреть сообщение
Код:
memcpy(fr.id, a, 3);
смысл было в a[3] заносить \0, если потом его не копировать ) да и копировать его некуда, собственно. Так что по-сути ничего не изменилось, о чём и говорит результат.
хорошо, снова переделал
Код:
    // читаем
    TFrame fr;

    byte a[4] = {0};

    for ( int i = 0; i < 3; ++i )
    {
        fread( &a[i], 1, 1, fp );
    }

    byte b[4] = {0};
    for ( int i = 0; i < 3; ++i )
    {
        fread( &b[i], 1, 1, fp );
    }

    fclose(fp);

    strcpy(fr.id, a);
    strcpy(fr.size, b);

    cout << fr.id << endl << fr.size << endl;
но объясните откуда ватчер берёт значение PIC@P# для id??
kleric вне форума Ответить с цитированием
Старый 02.06.2012, 14:34   #7
veniside
Старожил
 
Регистрация: 03.01.2011
Сообщений: 2,508
По умолчанию

видимо, он рассматиривает id как null-terminated строку. А так как никакого null у вас в конце строки нет, то он и шпарит дальше, пока не найдёт \0.
"Когда приходит положенное время, человек перестаёт играть в пинбол. Только и всего."
veniside вне форума Ответить с цитированием
Старый 02.06.2012, 14:55   #8
kleric
Пользователь
 
Регистрация: 27.07.2009
Сообщений: 22
По умолчанию

Цитата:
Сообщение от veniside Посмотреть сообщение
видимо, он рассматиривает id как null-terminated строку. А так как никакого null у вас в конце строки нет, то он и шпарит дальше, пока не найдёт \0.
и опять переделал через fstream
Код:
    fstream fp("test.dat",ios::binary|ios::in);
    // читаем
    TFrame fr;

    fp.read( fr.id, 3 );
    fp.read( fr.size, 3 );

    fp.close();

    cout << fr.id << endl << fr.size << endl;
вывод более ужасен
PIC@P#↑@x*↑
@P#↑@x*↑

НО почему strlen(fr.id) = 11
а sizeof(fr.id) = 3 (как и положено) ?
kleric вне форума Ответить с цитированием
Старый 02.06.2012, 16:40   #9
veniside
Старожил
 
Регистрация: 03.01.2011
Сообщений: 2,508
По умолчанию

Цитата:
почему strlen(fr.id) = 11
вроде уже 3 раза сказали. Строки заканчиваются \0. Так принято. \0 в конце id у вас отсутствует. Бывает. Вот strlen() и сканирует всю память, которая встретится после id (а там встречается 3 байта от size и дальше мусор). Вот этот мусор вы и наблюдаете на экране. Случано на 11-том байте оказался \0. Повезло. А могло ещё пару килобайт мусора быть. И это всё считалось бы строкой.

Вы уже решите одно из двух:

1) описываем структуру так, как байты лежат в файле. Это позволяет читать из файла всю структуру напрямую, но не позволяет рассматривать поля структуры как строки.

ЛИБО

2) описываем поля структры как строки. Это не позволяет прочесть из файла всю структуру за раз, по позволяет работать с полями как со строками.

Код:
struct TFrame
{
	unsigned char id[4];  // не забываем прописать \0 в id[3]
	unsigned char size[4]; // не забываем прописать \0 в size[3]
};
Вы же упорно пытаетесь смешать эти два подхода.
"Когда приходит положенное время, человек перестаёт играть в пинбол. Только и всего."
veniside вне форума Ответить с цитированием
Старый 02.06.2012, 17:25   #10
kleric
Пользователь
 
Регистрация: 27.07.2009
Сообщений: 22
По умолчанию

спасибо за объяснение
читает и выводит отлично
Код:
    char buf[4];
    fp.read( buf, 3 );
    buf[3] = '\0';

    cout << buf << endl;

    char buf2[4];
    fp.read( buf2, 3 );
    buf2[3] = '\0';

    cout << buf2 << endl;
PIC
@P#


НО

помогите теперь упаковать это в структуру
при таком подходе:
Код:
    strcpy( (char*)&fr.id, buf );
    strcpy( (char*)&fr.size, buf2 );

    cout << fr.id << endl;
выводит PIC@P#
откуда это взялось? ))
как правильно составить структуру в этом случае?
kleric вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
fread GriFFoN PHP 1 22.10.2011 22:55
Использование fread без блокирующего режима TRIZER PHP 4 20.06.2011 14:02
Чтение из файла virtuhay266 Помощь студентам 0 27.11.2010 23:27
бинарное чтение файла.. Gerry Помощь студентам 3 03.11.2009 11:59
Чтение из файла Need_Help Паскаль, Turbo Pascal, PascalABC.NET 5 19.05.2007 05:37