Модераторы: bsa
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Когда устанавливается eofbit? 
:(
    Опции темы
neocpp
Дата 9.2.2013, 18:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 10
Регистрация: 21.1.2013

Репутация: нет
Всего: нет



Добрый день. Имеется текстовый файл, в котором просто записано несколько чисел, например: 1 2 3 4

Читаю их таким образом:

Код

int c;
while(!f.eof())
{
    f >> c;
    cout << c << " ";
}


Получаю: 1 2 3 4. Но, стоит заменить тип переменной на: char c; Вывод получается таким, с лишней цифрой: 1 2 3 4 4

Вопрос. Почему в первом случае eofbit установился раньше, сразу после чтения последней цифры? И что происходит во втором случае?
PM MAIL   Вверх
korian
Дата 9.2.2013, 21:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 651
Регистрация: 8.3.2008
Где: Украина, Харьков

Репутация: 2
Всего: 17



а с char'ом разве пробелов не в три раза больше?
Код

1   2   3   4 4
вместо
1 2 3 4


нету компилятора под рукой, проверить...

PM   Вверх
NoviceF
Дата 9.2.2013, 21:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 313
Регистрация: 13.3.2012
Где: Ростов-на-Дону

Репутация: 2
Всего: 2



korian, вот у кого нет компилятора smile

http://liveworkspace.org/code/1bmmjj$2

эффект, описанный автором, присутствует..
PM MAIL   Вверх
korian
Дата 9.2.2013, 22:01 (ссылка) |    (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 651
Регистрация: 8.3.2008
Где: Украина, Харьков

Репутация: 2
Всего: 17



NoviceF, 
спасибо smile знал про liveworkspace.org, но как-то не вспомнил про stringstream.

Для описание возьмем буфер "12 3 4"

В случае с int мы читаем "числа", так сказать, и происходит примерно следующее:
1) прочитали символ '1', запомнили
2) прочитали символ '2', умножили предыдущее значение (цифру 1) на 10, прибавили 2
3) прочитали пробел (закончили читать число)
4) вывели int - 12 и пробел
5) прочитали символ '3', запомнили
6) прочитали пробел (закончили читать число)
7) вывели int - 3 и пробел
8) прочитали символ '4', запомнили
9) попытались прочитать еще символ - eof =  1, (закончили читать число) // <<<<<< это главное как бы
10) вывели int - 4 и пробел
11) вышли из цикла

В случае с char мы читаем "символы", так сказать, и происходит примерно следующее (пробелы пропускаются скорее всего из-за включенного skip_ws или как оно там):
1) прочитали символ '1'
2) вывели символ - '1' и пробел
3) прочитали символ '2'
4) вывели символ - '2' и пробел
5) прочитали символ <пробел> (skip_ws), тупо читаем след символ
6) прочитали символ '3'
7) вывели символ - '3' и пробел
8) прочитали символ <пробел> (skip_ws)
9) прочитали символ '4'
10) вывели символ - '4' и пробел
11) попытались прочитать еще один символ - eof
12) вывели то, что прочитали в прошлый раз
13) вышли из цикла

Кстати, если взять строку "1 2 3 4 " (тут главное пробел в конце), то вывод будет одинаковый


Это сообщение отредактировал(а) korian - 9.2.2013, 22:15
PM   Вверх
volatile
Дата 10.2.2013, 00:00 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 16
Всего: 85



Уважаемые программеры, все гораздо проще.
Запомните одну вещь, поток нужно проверять на конец файла не до ввода, а после.

А еще лучше проверять не на конец файла, а на любую ошибку.
что в коде выразицца след. образом:
Код

char c;
while (f >> c)
{
    cout << c << " ";
}


Код стал немного короче, и много надежней.  smile 

PM MAIL   Вверх
neocpp
Дата 10.2.2013, 08:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 10
Регистрация: 21.1.2013

Репутация: нет
Всего: нет



Цитата

Запомните одну вещь, поток нужно проверять на конец файла не до ввода, а после.


В этом-то и проблема. Я хотел действовать по схеме - сначала считываю значение, и, если установился eofbit, то выхожу из цикла. Так примерно:
Код

while(true)
{
    // пробую считывать
    f >> c;

    // проверяю на eof
    if(f.eof())
        break;

    // вывод числа    
    std::cout << c << " ";
}

Но так получается, что последнее число не выводится. То есть eofbit установился не после неудачного чтения, а сразу после последнего успешного чтения. Поэтому число 4 записалось в c, а потом сразу произошел выход, без вывода c на экран.

Вот еще небольшой код:
Код

#include <iostream>
#include <fstream>

void check(const std::ifstream & f)
{
    std::cout << "eofbit: " << f.eof() << "\n";
    std::cout << "failbit: " << f.fail() << "\n";
}

int main()
{
    std::ifstream f("file.txt");
    
    int c;
    while(f)
    {
        f >> c;
        
        check(f);
        
        std::cout << c << "\n";
    }
 
    return 0;
}

Из него видно, что сначала установился eofbit - после последнего успешного чтения, а уже на следующем шаге failbit, после неудачного чтения.

eofbit: 0
failbit: 0
1
eofbit: 0
failbit: 0
2
eofbit: 0
failbit: 0
3
eofbit: 1
failbit: 0
4
eofbit: 1
failbit: 1
4


А вот в случае char-переменной, eofbit и failbit установились одновременно, уже после неудачного чтения:
eofbit: 0
failbit: 0
1
eofbit: 0
failbit: 0
2
eofbit: 0
failbit: 0
3
eofbit: 0
failbit: 0
4
eofbit: 1
failbit: 1
4


Я не понимаю, почему так. В какой конкретно момент устанавливается eofbit и как это зависит от типа переменной?

volatile, полностью согласен, ваш код надежнее, и обычно я так и делаю. Но вот в чем проблема, if(f) - это проверка на failbit и badbit. Меня в контексте данного вопроса интересует именно eofbit.

_____________________________________________________________________________________________________________
Добавлено @ 09:12
Цитата

8) прочитали символ '4', запомнили
9) попытались прочитать еще символ - eof =  1, (закончили читать число) // <<<<<< это главное как бы

Хм... получается для типа int операция << читает символы, которые являются цифрами и следующий после них разделитель тоже считывает? То есть пробел или признак конца файла считается вместе с последним числом, и устанавливается eofbit. А уже на следующей итерации (если она есть) - попытка читать после конца приводит к fail.

А для char просто читает 1 символ, и "не смотрит" на следующие? То есть, последний символ считали, потом пробуем считать конец файла - получаем сразу eof и fail?

Пока я еще больше запутался, но кажется вы правильно все написали.

Это сообщение отредактировал(а) neocpp - 10.2.2013, 09:12
PM MAIL   Вверх
NoviceF
Дата 10.2.2013, 09:32 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 313
Регистрация: 13.3.2012
Где: Ростов-на-Дону

Репутация: 2
Всего: 2



Цитата(neocpp @  10.2.2013,  09:57 Найти цитируемый пост)
Я не понимаю, почему так. В какой конкретно момент устанавливается eofbit и как это зависит от типа переменной?

Прочитай что написал korian, там этот момент объясняется. В итоге смысл в том, что для char всегда читается 1 символ из потока, а int читает до тех пор, пока не убедится, что число закончилось, то есть для интов, чтение из потока происходит минимум 2 раза за 1 проход цикла, и именно поэтому при чтении int из потока, конец файла обнаруживается быстрее, чем при чтении char.

Добавлено через 7 минут и 37 секунд
Цитата(volatile @  10.2.2013,  01:00 Найти цитируемый пост)
А еще лучше проверять не на конец файла, а на любую ошибку.

Ну в данном контексте конец файла не считается ошибкой и проверку 
Код

while (f >> c)

проходит.

Хотя такой способ проверки, конечно, удобнее.
PM MAIL   Вверх
volatile
Дата 10.2.2013, 12:10 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 16
Всего: 85



Цитата(neocpp @  10.2.2013,  08:57 Найти цитируемый пост)
Я не понимаю, почему так. В какой конкретно момент устанавливается eofbit и как это зависит от типа переменной?

neocpp, вас как я понял интересует внутренняя кухня?
Здесь все уже сказали верно.

При чтении инта программа не знает когда он закончицца. инт может быть таким "1", и таким "10", и таким "100" и т.д.
программа будет читать поток до тех пор, пока не встретицца первый не цифровой символ.

Если сразу за цифрами последует конец файла, то eofbit  и установицца.
Если же после цифр будет идти хотябы один пробел, или перевод строки, то eofbit не установицца.
Из этого вытекает, кстати, что проверять на конец файла, вообще не очень корректно.  smile 

Нужно проверять именно на ошибку, и проверять ее именно после чтения, как я и привел пример.
Такой способ не будет зависеть от оконечных пробелов/переводов строк, в файле.

PM MAIL   Вверх
neocpp
Дата 10.2.2013, 12:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 10
Регистрация: 21.1.2013

Репутация: нет
Всего: нет



Всем спасибо за подробные ответы, теперь все более менее встало на свои места. К сожалению, не получается добавить плюсов к репутации((
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.0600 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.