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

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
SaShka K
3 / 3 / 0
Регистрация: 16.01.2014
Сообщений: 55
#1

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

24.02.2014, 18:33. Просмотров 785. Ответов 9
Метки нет (Все метки)

Есть файл 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, выставляется флаг достижения конца файла, но курсор остаётся в положении на последнем символе файла (т.е. в том же положении, в которое перешёл после чтения предпоследнего символа). Правильно ли я полагаю?
0
Лучшие ответы (1)
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
24.02.2014, 18:33
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Нюансы условий достижения EOF в ifstream (C++):

Ifstream и eof в нем - C++
Имеется код: int main() { setlocale(LC_ALL, &quot;rus&quot;); // корректное отображение Кириллицы char abc; ofstream fout(&quot;ofstream...

Нюансы обучения: желание учесть все нюансы - корректность кода или overengineering? - C++
Здравствуйте программисты! Ответьте пожалуйста на такой вопрос(объясните) Вот я учу С++ и решаю задачи по учебникам, и постоянно...

Различия ifstream::get() и ifstream::get(ch) - C++
Доброго времени суток. Была тут тема, в которой я не разобрался до конца. Код ниже проверяет баланс скобок в текстовом файле #include...

DirectShow запись видео до достижения размера - C++
Всем привет. Есть граф записи DirecShow(видео пишется все норм). По достижении файлом размера (например 100Мб) необходимо продолжать...

Составить условие достижения последнего элемента массива - C++
помогите придумать условие ,как правильно это записать в if(&quot;если массив достиг последнего элемента&quot;)

\n \0 EOF - C++
Добрый вечер, возник такой вопрос: зачем мы заменяем символ конца строки на нуль символ в данном коде (удаление символов содержащихся в s2...

9
retmas
Жарю без масла
863 / 745 / 168
Регистрация: 13.01.2012
Сообщений: 1,702
24.02.2014, 19:27 #2
Лучший ответ Сообщение было отмечено автором темы, экспертом или модератором как ответ
в строке 12 у вас будет считано функцией getline 2 символа. при этом \n считан не будет. поэтому поток fileIn перейдет в состояние fail. отсюда и проблемы ничиная с п. 2
1
SaShka K
3 / 3 / 0
Регистрация: 16.01.2014
Сообщений: 55
24.02.2014, 19:35  [ТС] #3
к retmas
Спасибо. Подскажите пож., почему происходит так, как Вы написали. Или ткните пож. меня носом, где почитать, почему так.
0
retmas
Жарю без масла
863 / 745 / 168
Регистрация: 13.01.2012
Сообщений: 1,702
24.02.2014, 19:38 #4
Цитата Сообщение от SaShka K Посмотреть сообщение
где почитать, почему так
в любом толковом описании функции getline

Добавлено через 59 секунд
std::istream::getline
1
SaShka K
3 / 3 / 0
Регистрация: 16.01.2014
Сообщений: 55
25.02.2014, 16:29  [ТС] #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`, но курсор не двигается и так и остаётся на последнем символе файла (т.к. программа поняла, что достигнут конец файла, курсор не двигает дальше). Соответственно, когда снимаю флаг, возвращаюсь в точно ту же ситуацию, которая была в начале предыдущей итерации.
Так? Или я что-то неверно истолковываю?
0
retmas
Жарю без масла
863 / 745 / 168
Регистрация: 13.01.2012
Сообщений: 1,702
25.02.2014, 17:07 #6
1)
Цитата Сообщение от SaShka K Посмотреть сообщение
Почему при установке флага `failbit` входного файлового потока проверка на `get()==EOF` даёт `true`
а что она еще может выдать?
2)
Цитата Сообщение от SaShka K Посмотреть сообщение
проверка функции eof() всё равно не срабатывает и цикл остаётся вечным
своим clear() вы сбрасываете eofbit.
1
SaShka K
3 / 3 / 0
Регистрация: 16.01.2014
Сообщений: 55
26.02.2014, 13:48  [ТС] #7
Цитата Сообщение от retmas Посмотреть сообщение
а что она еще может выдать?
Ну я ожидал, что, коль get() читает следующий символ из потока, а EOF это конец файла (т.е. что-то вроде некой служебной информации, считываемой только при достижении этого самого конца файла), то `get()==EOF` должно по идее давать `true` собственно при следующем чтении после чтения последнего символа файла. Как-то так..

Добавлено через 13 часов 9 минут
Цитата Сообщение от retmas Посмотреть сообщение
своим clear() вы сбрасываете eofbit.
Простите, конечно глупость написал. :$ Видимо заучился. Спасибо, что терпите )
0
alsav22
5425 / 4820 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
26.02.2014, 14:33 #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'.
1
SaShka K
3 / 3 / 0
Регистрация: 16.01.2014
Сообщений: 55
26.02.2014, 14:51  [ТС] #9
Цитата Сообщение от alsav22 Посмотреть сообщение
Если в конце последней строки будет '\n', то будет повторный вывод последнего символа.
Насколько я понял, повторный вывод последнего символа в таком цикле будет всегда (независимо от того, какой именно этот символ будет - не обязательно '\n')
0
alsav22
5425 / 4820 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
26.02.2014, 15:05 #10
В данном случае, да. Но если, например, чтение идёт в int, и есть такая трока: 1 2 3 4, то повторный вывод будет если только в конце есть '\n'.
1
26.02.2014, 15:05
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
26.02.2014, 15:05
Привет! Вот еще темы с ответами:

Теовер на си или порядок действий для достижения результата - C++
Из урны в которой 10 белых, 8 черных и 6 красных шаров извлекается по 1 шару с возвращением пока не получили последовательность из 5 белых...

ifstream - C++
Привет всем такая проблема ввода Student* s;// студенты s = new Student; ifstream fin(&quot;Student.txt&quot;); for(int i(0); i &lt; l;...

Не работает while (!***.eof() ! - C++
Здравствуйте, задание такое: Вводить с клавиатуры данные и записывать их в файл в виде Имя группа оценка Иванов ...

Int Eof - C++
Вот проблема есть массив int a заполнять его целыми числами последовательность завершается признаком конца ввода


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

Или воспользуйтесь поиском по форуму:
10
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru