Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Дополнительные операторы ввода/вывода



Иногда необходимо прочитать из входного потока последовательность не интерпретируемых байтов, а типов данных, таких, как char, int, string и т.д. Функция-член get() класса istream читает по одному байту, а функция getline() читает строку, завершающуюся либо символом перехода на новую строку, либо каким-то иным символом, определяемым пользователем. У функции-члена get() есть три формы:

· get(char& ch) читает из входного потока один символ (в том числе и пустой) и помещает его в ch. Она возвращает объект iostream, для которого была вызвана. Например, следующая программа собирает статистику о входном потоке, а затем копирует входной поток в выходной:

#include < iostream>

 

int main()

{

char ch;

int tab_cnt = 0, nl_cnt = 0, space_cnt = 0,

   period_cnt = 0, comma_cnt = 0;

while ( cin.get(ch)) {

      switch( ch ) {

         case ' ': space_cnt++; break;

         case '\t': tab_cnt++; break;

         case '\n': nl_cnt++; break;

         case '.': period_cnt++; break;

         case ', ': comma_cnt++; break;

    }

    cout.put(ch);

}

 

cout < < " \nнаша статистика: \n\t"

   < < " пробелов: " < < space_cnt < < '\t'

   < < " символов новой строки: " < < nl_cnt < < '\t'

   < < " табуляций: " < < tab_cnt < < " \n\t"

   < < " точек: " < < period_cnt < < '\t'

   < < " запятых: " < < comma_cnt < < endl;

}

Функция-член put() класса ostream дает альтернативный метод вывода символа в выходной поток: put() принимает аргумент типа char и возвращает объект класса ostream, для которого была вызвана.

После компиляции и запуска программа печатает следующий результат:

 

Alice Emma has long flowing red hair. Her Daddy says

when the wind blows through her hair, it looks almost alive,

like a fiery bird in flight. A beautiful fiery bird, he tells her,

magical but untamed. " Daddy, shush, there is no such creature, "

she tells him, at the same time wanting him to tell her more.

Shyly, she asks, " I mean, Daddy, is there? "

 

наша статистика:

  пробелов: 59 символов новой строки: 6 табуляций: 0

  точек: 4     запятых: 12

 

· вторая форма get() также читает из входного потока по одному символу, но возвращает не поток istream, а значение прочитанного символа. Тип возвращаемого значения равен int, а не char, поскольку необходимо возвращать еще и признак конца файла, который обычно равен -1, чтобы отличаться от кодов реальных символов. Для проверки на конец файла мы сравниваем полученное значение с константой EOF, определенной в заголовочном файле iostream. Переменная, в которой сохраняется значение, возвращенное get(), должна быть объявлена как int, чтобы в ней можно было представить не только код любого символа, но и EOF:

#include < iostream>

 

int main()

{

   int ch;

 

   // альтернатива:

// while ( ch = cin.get() & & ch! = EOF )

   while (( ch = cin.get())! = EOF )

         cout.put( ch );

 

   return 0;

}

При использовании любой из этих форм get() для чтения данной последовательности нужно семь итераций:

 

a b c

d

 

Читаются следующие символы: ('a', пробел, 'b', пробел, 'c', символ новой строки, 'd'). На восьмой итерации читается EOF. Оператор ввода (> > ) по умолчанию пропускает пустые символы, поэтому на ту же последовательность потребуется четыре итерации, на которых возвращаются символы: 'a', 'b', 'c', 'd'. А вот следующая форма get() может прочесть всю последовательность всего за две итерации;

· сигнатура третьей формы get() такова:

get(char *sink, streamsize size, char delimiter='\n')

sink – это массив, в который помещаются символы. size – это максимальное число символов, читаемых из потока istream. delimiter – это символ-ограничитель, при обнаружении которого чтение прекращается. Сам ограничитель не читается, а оставляется в потоке и будет прочитан следующим. Программисты часто забывают удалить его из потока перед вторым обращением к get(). Чтобы избежать этой ошибки, в показанной ниже программе мы воспользовались функцией-членом ignore() класса istream. По умолчанию ограничителем является символ новой строки.

Символы читаются из потока, пока одно из следующих условий не окажется истинным. Как только это случится, в очередную позицию массива помещается двоичный нуль.

· прочитано size-1 символов;

· встретился конец файла;

· встретился символ-ограничитель (еще раз напомним, что он остается в потоке и будет считан следующим).

Эта форма get() возвращает объект istream, для которого была вызвана (функция-член gcount() позволяет узнать количество прочитанных символов). Вот простой пример ее применения:

#include < iostream>

 

int main()

{

   const int max_line = 1024;

   char line[ max_line ];

 

   while ( cin.get( line, max_line ))

   {

    // читается не больше max_line - 1 символов,

    // чтобы оставить место для нуля

    int get_count = cin.gcount();

    cout < < " фактически прочитано символов: "

    < < get_count < < endl;

 

    // что-то сделать со строкой

 

    // если встретился символ новой строки,

    // удалить его, прежде чем приступать к чтению следующей

    if ( get_count < max_line-1 )

         cin.ignore();

   }

}

Если на вход этой программы подать текст о юной Алисе Эмме, то результат будет выглядеть так:

 

фактически прочитано символов: 52

фактически прочитано символов: 60

фактически прочитано символов: 66

фактически прочитано символов: 63

фактически прочитано символов: 61

фактически прочитано символов: 43

 

Чтобы еще раз протестировать поведение программы, мы создали строку, содержащую больше max_line символов, и поместили ее в начало текста. Получили:

 

фактически прочитано символов: 1023

фактически прочитано символов: 528

фактически прочитано символов: 52

фактически прочитано символов: 60

фактически прочитано символов: 66

фактически прочитано символов: 63

фактически прочитано символов: 61

фактически прочитано символов: 43

 

По умолчанию ignore() читает и удаляет один символ из потока, для которого вызвана, но можно и явно задать ограничитель и количество пропускаемых символов. В общем виде ее сигнатура такова:

ignore( streamsize length = 1, int delim = traits:: eof )

ignore() читает и отбрасывает length символов из потока или все символы до ограничителя включительно или до конца файла и возвращает объект istream, для которого вызвана.

Мы рекомендуем пользоваться функцией getline(), а не get(), поскольку она автоматически удаляет ограничитель из потока. Сигнатура getline() такая же, как у get() с тремя аргументами (и возвращает она тоже объект istream, для которого вызвана):

getline(char *sink, streamsize size, char delimiter='\n')

Поскольку и getline(), и get() с тремя аргументами могут читать size символов или меньше, то часто нужно “спросить” у объекта istream, сколько символов было фактически прочитано. Это позволяет сделать функция-член gcount(): она возвращает число символов, прочитанных при последнем обращении к get() или getline().

Функция-член write() класса ostream дает альтернативный метод вывода массива символов. Вместо того чтобы выводить символы до завершающего нуля, она выводит указанное число символов, включая и внутренние нули, если таковые имеются. Вот ее сигнатура:

write( const char *sink, streamsize length )

Здесь length определяет, сколько символов выводить. write() возвращает объект класса ostream, для которого она вызвана.

Парной для функции write() из класса ostream является функция read() из класса istream с такой сигнатурой:

read( char* addr, streamsize size )

read() читает size соседних байт из входного потока и помещает их, начиная с адреса addr. Функция gcount() возвращает число байт, прочитанных при последнем обращении к read(). В свою очередь read() возвращает объект класса istream, для которого она вызвана. Вот пример использования getline(), gcount() и write():

#include < iostream>

 

int main()

{

   const int lineSize = 1024;

   int lcnt = 0; // сколько строк прочитано

   int max = -1; // длина самой длинной строки

 

   char inBuf[ lineSize ];

 

   // читается до конца строки, но не более 1024 символов

   while (cin.getline( inBuf, lineSize ))

   {

    // сколько символов фактически прочитано

    int readin = cin.gcount();

 

    // статистика: счетчик строк, самая длинная строка

    ++lcnt;

    if ( readin > max )

         max = readin;

 

    cout < < " Строка #" < < lcnt

    < < " \tПрочитано символов: " < < readin < < endl;

 

    cout.write( inBuf, readin).put('\n').put('\n');

   }

 

   cout < < " Всего прочитано строк: " < < lcnt < < endl;

   cout < < " Самая длинная строка: " < < max < < endl;

}

Когда на вход было подано несколько фраз из романа Германа Мелвилла “Моби Дик”, программа напечатала следующее:

 

Строка #1 Прочитано символов: 45

Call me Ishmael. Some years ago, never mind

 

Строка #2 Прочитано символов: 46

how long precisely, having little or no money

 

Строка #3 Прочитано символов: 48

in my purse, and nothing particular to interest

 

Строка #4 Прочитано символов: 51

me on shore, I thought I would sail about a little

 

Строка #5 Прочитано символов: 47

and see the watery part of the world. It is a

 

Строка #6 Прочитано символов: 43

way I have of driving off the spleen, and

 

Строка #7 Прочитано символов: 28

regulating the circulation.

 

Всего прочитано строк: 7

Самая длинная строка: 51

 

Функция-член getline() класса istream поддерживает только ввод в массив символов. Однако в стандартной библиотеке есть обычная функция getline(), которая помещает символы в объект класса string:

getline( istream & is, string str, char delimiter );

Эта функция читает не более str:: max_size()-1 символов. Если входная последовательность длиннее, то операция завершается неудачно и объект переводится в ошибочное состояние. В противном случае ввод прекращается, когда прочитан ограничитель (он удаляется из потока, но в строку не помещается) либо достигнут конец файла.

Вот еще три необходимые нам функции-члена класса istream:

// возвращает символ в поток

putback( char class );

 

// устанавливает " указатель на следующий символ потока istream на один символ назад

unget();

 

// возвращает следующий символ (или EOF),

// но не извлекает его из потока

peek();

Следующий фрагмент иллюстрирует использование некоторых из них:

char ch, next, lookahead;

 

while ( cin.get( ch ))

{

switch (ch) {

case '/':

// это комментарий? посмотрим с помощью peek()

// если да, пропустить остаток строки

next = cin.peek();

if ( next == '/' )

    cin.ignore( lineSize, '\n' );

break;

case '> ':

// проверка на лексему > > =

next = cin.peek();

if ( next == '> ' ) {

    lookahead = cin.get();

    next = cin.peek();

    if ( next! = '=' )

       cin.putback( lookahead );

    }

    //...

}

Упражнение 20.4

Прочитайте из стандартного ввода следующую последовательность символов, включая все пустые, и скопируйте каждый символ на стандартный вывод (эхо-копирование):

 

a  b c

d e

f

 

Упражнение 20.5

Прочитайте фразу “riverrun, from bend of bay to swerve of shore” сначала как последовательность из девяти строк, а затем как одну строку.

Упражнение 20.6

С помощью функций getline() и gcount() прочитайте последовательность строк из стандартного ввода и найдите самую длинную (не забудьте, что строку, прочитанную за несколько обращений к getline(), нужно считать одной).


Поделиться:



Последнее изменение этой страницы: 2019-04-09; Просмотров: 317; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.065 с.)
Главная | Случайная страница | Обратная связь