Программирование >>  Инициализация объектов класса, структура 

1 ... 351 352 353 [ 354 ] 355 356 357 ... 395


[ 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, то чтение прошло бы успешно и поток остался бы в нормальном состоянии.

Чтобы выяснить, в каком состоянии находится поток, достаточно проверить его значение



1 ... 351 352 353 [ 354 ] 355 356 357 ... 395

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика