Форум программистов, компьютерный форум CyberForum.ru

Нюансы условий достижения EOF в ifstream - C++

Восстановить пароль Регистрация
 
SaShka K
3 / 3 / 0
Регистрация: 16.01.2014
Сообщений: 55
24.02.2014, 18:33     Нюансы условий достижения EOF в ifstream #1
Есть файл in.txt из 2х строк следующего содержания:
abcde
12345


Есть код:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <fstream>
int main() {
   std::ifstream fileIn("in.txt", std::ios::in);
 
   char* chPtr = new(char[10]);
   char ch;
   
   printf("fileIn.get() == EOF?: %d \n", (fileIn.get() == EOF));    // вывод 0
   std::cout << "fileIn.eof() = " << fileIn.eof() <<  "\n"; // вывод 0 
 
   fileIn.getline(chPtr, 3);
   std::cout << "chPtr-" << chPtr << "\n";  // вывод "bc"  (см.прим.1.)
   fileIn.get(ch);
   std::cout << "ch-" << ch << "\n";   // (см.прим.2.)
 
   printf("fileIn.get() == EOF?: %d \n", (fileIn.get() == EOF));    // вывод 1  (см.прим.3) 
   std::cout << "fileIn.eof() = " << fileIn.eof() << "\n";  // вывод 0  (см.прим.4)
   while (!fileIn.eof()) {
      fileIn >> ch; // (см. 5.)
      std::cout << ch << ", ";
   }
   fileIn.close();
   delete[] chPtr;  
}
Примечания:
(1.) 1й символ 'a' съел get() чуть выше; считалось 2 следующих символа из потока, а 3й считываемый, так понимаю, getline() автоматом пишет '\0'.

(2.) И тут собственно вопрос - выводит символ (2 вертикальные белые черты, правая из которых с промежутком посередине; расстояние между чертами == толщине каждой из них и == высоте промежутка в правой) этот символ выводится всегда, когда, например, пытаюсь прочесть в char неинициализированный участок строки.
Но в файле ведь ещё осталась часть первой строки и полностью вторая... Не понятно.

(3.) Оказыавется, мы вдруг оказались в конце файла. НО почему??

(4.) Тут продолжает быть 0, т.к. (насколько понимаю) попытки чтения за пределами конца файла ещё не было. Мы просто оказались прямо перед чертой конца файла (т.е. после последнего символа файла, но пока не заступив за его границу).

(5.) Этот цикл в текущей ситуации оказывается вечным. И проблема не в нём, т.к., переставив его в начало описанного кода, получаю нормально (ожидаемо) отрабатывающий цикл. Судя по его поведению тут, предполагаю, что каким-то образом, указатель в файле перепрыгнул в конец файла и теперь ни чтение не производится, т.к., видимо (это моё предположение) срабатывает какое-то ограничение, что одиночный char не может быть считан, если курсор стоит перед чертой конца файла, и поэтому (т.к. чтение не происходит) и курсор не перемещается далее, т.е. eof() не наступает.
Это мой второй вопрос - мне не понятно поведение.
Я прочёл, что по достижении конца файла устанавливается флаг и больше ничего прочесть из потока невозможно. Но, если добавить внуть цикла команду
C++
1
fileIn.clear();
, которая должна снимать этот флаг и делать возможным дальнейшее чтение, то выводимое значение ch просто меняется с символа с кодом (-52) на последний символ файла '5'. Из этого предполагаю, что по достижении EOF, выставляется флаг достижения конца файла, но курсор остаётся в положении на последнем символе файла (т.е. в том же положении, в которое перешёл после чтения предпоследнего символа). Правильно ли я полагаю?
Лучшие ответы (1)
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
24.02.2014, 18:33     Нюансы условий достижения EOF в ifstream
Посмотрите здесь:

Объект ifstream!!! C++
C++ Объект ifstream!!!
C++ ifstream
C++ \n \0 EOF
Объясните пожалуйста. Нюансы программы с рекурсией C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
retmas
Жарю без масла
803 / 685 / 143
Регистрация: 13.01.2012
Сообщений: 1,580
24.02.2014, 19:27     Нюансы условий достижения EOF в ifstream #2
Сообщение было отмечено автором темы, экспертом или модератором как ответ
в строке 12 у вас будет считано функцией getline 2 символа. при этом \n считан не будет. поэтому поток fileIn перейдет в состояние fail. отсюда и проблемы ничиная с п. 2
SaShka K
3 / 3 / 0
Регистрация: 16.01.2014
Сообщений: 55
24.02.2014, 19:35  [ТС]     Нюансы условий достижения EOF в ifstream #3
к retmas
Спасибо. Подскажите пож., почему происходит так, как Вы написали. Или ткните пож. меня носом, где почитать, почему так.
retmas
Жарю без масла
803 / 685 / 143
Регистрация: 13.01.2012
Сообщений: 1,580
24.02.2014, 19:38     Нюансы условий достижения EOF в ifstream #4
Цитата Сообщение от SaShka K Посмотреть сообщение
где почитать, почему так
в любом толковом описании функции getline

Добавлено через 59 секунд
std::istream::getline
SaShka K
3 / 3 / 0
Регистрация: 16.01.2014
Сообщений: 55
25.02.2014, 16:29  [ТС]     Нюансы условий достижения EOF в ifstream #5
осталось без ответа 2 второстепенных, но всё же интересных мне вопроса, чёткого ответа на которые я найти в сети не могу:
Рассматриваю их на примере поведения этого же кода, т.к. вскрытая благодаря retmas ошибка проектирования не мешает говорить о них:

1) Почему при установке флага `failbit` входного файлового потока проверка на `get()==EOF` даёт `true`, хотя фактически конец файла не был достигнут?
Это просто побочный эффект этого флага, или причина глубже?

2) (писал об этом в примечании № 5. в изначальной постановке. Тут излагаю лаконичнее): Если в написанном в постановке вопроса коде в цикле добавляю выражение с функцией `clear()`, снимающей флаги ошибок потока, то проверка функции eof() всё равно не срабатывает и цикл остаётся вечным:
C++
1
2
3
4
5
6
   ...
   while (!fileIn.eof()) {
      fileIn >> ch; // (см. 5.)
      std::cout << ch << ", ";
      fileIn.clear();
   }
На выводе получаю бесконечно выводимую пятёрку (последний символ в файле). Хотя ожидал, что прочтётся '5', тут возможно установится флаг eofbit, но тут же clear() его снимет и в следующей итерации уже произойдёт попытка чтения за границей файла, что при следующей проверке условия цикла вызовет срабатывание `eof()`. Но получается не так.

Я правильно предполагаю причину этого: получается ситуация, что происходит всё как я описал, НО после чтения '5' включается флаг `eofbit`, но курсор не двигается и так и остаётся на последнем символе файла (т.к. программа поняла, что достигнут конец файла, курсор не двигает дальше). Соответственно, когда снимаю флаг, возвращаюсь в точно ту же ситуацию, которая была в начале предыдущей итерации.
Так? Или я что-то неверно истолковываю?
retmas
Жарю без масла
803 / 685 / 143
Регистрация: 13.01.2012
Сообщений: 1,580
25.02.2014, 17:07     Нюансы условий достижения EOF в ifstream #6
1)
Цитата Сообщение от SaShka K Посмотреть сообщение
Почему при установке флага `failbit` входного файлового потока проверка на `get()==EOF` даёт `true`
а что она еще может выдать?
2)
Цитата Сообщение от SaShka K Посмотреть сообщение
проверка функции eof() всё равно не срабатывает и цикл остаётся вечным
своим clear() вы сбрасываете eofbit.
SaShka K
3 / 3 / 0
Регистрация: 16.01.2014
Сообщений: 55
26.02.2014, 13:48  [ТС]     Нюансы условий достижения EOF в ifstream #7
Цитата Сообщение от retmas Посмотреть сообщение
а что она еще может выдать?
Ну я ожидал, что, коль get() читает следующий символ из потока, а EOF это конец файла (т.е. что-то вроде некой служебной информации, считываемой только при достижении этого самого конца файла), то `get()==EOF` должно по идее давать `true` собственно при следующем чтении после чтения последнего символа файла. Как-то так..

Добавлено через 13 часов 9 минут
Цитата Сообщение от retmas Посмотреть сообщение
своим clear() вы сбрасываете eofbit.
Простите, конечно глупость написал. :$ Видимо заучился. Спасибо, что терпите )
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
26.02.2014, 14:33     Нюансы условий достижения EOF в ifstream #8
Посоветую, вот так не организовывать чтение из файла:
C++
1
2
3
4
while (!fileIn.eof()) {
      fileIn >> ch; // (см. 5.)
      std::cout << ch << ", ";
   }
Если в конце последней строки будет '\n', то будет повторый вывод последнего символа. fileIn >> прочтёт последний символ (до '\n'), вывод через cout, eof ещё не установлен, поэтому ещё одно чтение, но так как считается EOF, то значение в ch останется старым, и оно будет выведено второй раз.
Поэтому лучше так делать:
C++
1
2
3
while (fileIn >> ch) {
std::cout << ch << ", ";
}
Такая конструкция будет правильно работать вне зависимости от того, есть ли в конце последней строки '\n'.
SaShka K
3 / 3 / 0
Регистрация: 16.01.2014
Сообщений: 55
26.02.2014, 14:51  [ТС]     Нюансы условий достижения EOF в ifstream #9
Цитата Сообщение от alsav22 Посмотреть сообщение
Если в конце последней строки будет '\n', то будет повторный вывод последнего символа.
Насколько я понял, повторный вывод последнего символа в таком цикле будет всегда (независимо от того, какой именно этот символ будет - не обязательно '\n')
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
26.02.2014, 15:05     Нюансы условий достижения EOF в ifstream
Еще ссылки по теме:

C++ Ifstream и eof в нем
DirectShow запись видео до достижения размера C++
Теовер на си или порядок действий для достижения результата C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
26.02.2014, 15:05     Нюансы условий достижения EOF в ifstream #10
В данном случае, да. Но если, например, чтение идёт в int, и есть такая трока: 1 2 3 4, то повторный вывод будет если только в конце есть '\n'.
Yandex
Объявления
26.02.2014, 15:05     Нюансы условий достижения EOF в ifstream
Ответ Создать тему
Опции темы

Текущее время: 03:50. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru