|
Программирование >> Инициализация объектов класса, структура
[ 0 ] Программа не вывела ни одного символа, видимо, полагая, что файл пуст. Проблема в том, что файл открыт для дозаписи и потому позиционирован на конец. При выполнении инструкции inCut.get( ch ) ; мы читаем конец файла, цикл while завершается и выводится значение 0. Хотя mi допустили серьезную ошибку, исправить ее совсем несложно, поскольку причина понятна. Надо лишь перед чтением переустановить файл на начало. Это делается с помощью обращения: inCut.seekg( 0 ); Запустим программу заново. На этот раз она печатает: Call me Ishmael. Some years ago, never mind [ 45 ] Как видим, выводится лишь первая строка текста и счетчик для нее, а оставшиеся шесть строк проигнорированы. Ну что ж, исправление ошибок - неотъемлемая часть профессии программиста. А проблема опять в том, что файл открыт в режиме дозаписи. Как только мы в первый раз вывели cnt, файл оказался позиционирован на конец. При следующем обращении к get() читается конец файла, и цикл while снова завершается преждевременно. Нам необходимо встать на ту позицию в файле, где мы были перед выводом cnt. Для запомнить текущую позицию ios base::pos type mark = inCut.tellg(); inCut << cnt << sp; этого понадобятся еще две инструкции: inCut.seekg( mark ); восстановить позицию После повторной компиляции программа выводит на экран ожидаемый результат. Но посмотрев на выходной файл, мы обнаружим, что она все еще не вполне правильна: окончательное значение счетчика есть на экране, но не в файле. Оператор вывода, следующий за циклом while, не был выполнен. Дело в том, что inCut находится в состоянии конец файла , в котором операции ввода и вывода не выполняются. Для решения проблема: необходимо сбросить это состояние с помощью функции-члена clear() : inCut.clear(); обнулить флаги состояния Окончательный вариант программы выглядит так: #include <iostream> #include <fstream> int main() { fstream inOut( copy.out , ios base::inios base::app ); int cnt=0; char ch; inOut.seekg(0); while ( inOut.get( ch )) { cout.put( ch ); cnt++; if ( ch == \n ) запомнить текущую позицию ios base::pos type mark = inOut.tellg(); ios base::pos type mark inOut << cnt << ; inOut.seekg( mark ); восстановить позицию inOut.clear(); inOut << cnt << endl; cout << [ << cnt << ]\n ; return 0; Вот теперь - наконец-то! - все правильно. При реализации этой программы было необходимо явно сформулировать поведение, которое mi собирались поддержать. А каждое наше исправление было реакцией на выявившуюся ошибку вместо анализа проблемы в целом. Упражнение 20.12 Пользуясь операторами вывода для класса Date, которые вы определили в упражнении 20.7, или для класса CheckoutRecord из упражнения 20.8 (см. раздел 20.4), напишите программу, позволяющую создать файл и писать в него. Упражнение 20.13 Напишите программу для открытия и чтения файла, созданного в упражнении 20.12. Выведите содержимое файла на стандартный вывод. Упражнение 20.14 Напишите программу для открытия файла, созданного в упражнении 20.12, для чтения и дозаписи. Выведите экземпляр класса Date или CheckoutRecord: (a) в начало файла (b) после второго из существующих объектов (c) в конец файла if ( !cin ) на истину: операция чтения не прошла встретился конец файла while ( cin >> word ) Для чтения заранее неизвестного количества элементов мы обычно пишем цикл while: операция чтения завершилась успешно . Условие в цикле while будет равно false, если достигнут конец файла или произошла ошибка при чтении. В большинстве случаев такой проверки потокового объекта достаточно. Однако при реализации оператора ввода для класса WordCount из раздела 20.5 нам понадобился более точн1й анализ состояния. У любого потока есть набор флагов, с помощью которых можно следить за состоянием потока. Имеются чет1ре предикатные функции-члена: if ( inCut.eof() ) eof() возвращает true, если достигнут конец файла: отлично: все прочитано ... bad() возвращает true при попытке выполнения некорректной операции, например при установке позиции за концом файла. Обычно это свидетельствует о том, что ноток находится в состоянии ошибки; fail() возвращает true, если операция завершилась неудачно, например не удалось открыть файл или передан некорректный формат ввода: 20.7. Состояния потока Пользователей библиотеки iostreami, разумеется, интересует, находится ли ноток в int ival; ошибочном состоянии. Например, если мы пишем cin >> ival; и вводим слово Borges , то cin переводится в состояние ошибки после неудачной попытки присвоить строковый литерал целому числу. Если бы mi ввели число 1024, то чтение прошло бы успешно и поток остался бы в нормальном состоянии. Чтобы выяснить, в каком состоянии находится поток, достаточно проверить его значение
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |