Ввод
Основное средство реализации ввода– это оператор сдвига вправо (>>). Например, в следующей программе из стандартного ввода читается последовательность значений типа int и помещается в вектор:
#include <iostream> #include <vector> int main() { vector<int> ivec; int ival; while ( cin >> ival ) ivec.push_back( ival ); // ... |
|
}
Подвыражение
cin >> ival;
читает целое число из стандартного ввода и копирует его в переменную ival. Результатом является левый операнд – объект класса istream, в данном случае cin. (Как мы увидим, это позволяет сцеплять операторы ввода.)
Выражение
while ( cin >> ival )
читает последовательность значений, пока cin не станет равно false. Значение istream
может быть равно false в двух случаях: достигнут конец файла (т.е. все значения из файла прочитаны успешно) или встретилось неверное значение, скажем 3.14159 (десятичная точка недопустима в целом числе), 1e-1 (буква e
недопустима) или любой строковый литерал. Если вводится неверное значение, объект istream
переводится в состояние ошибки и чтение прекращается. (В разделе 20.7 мы подробнее расскажем о таких состояниях.)
Есть набор предопределенных операторов ввода, принимающих аргументы любого встроенного типа, включая C-строки, а также стандартных библиотечных типов string и complex:
#include <iostream> #include <string> int main() { int item_number; string item_name; double item_price; cout << "Пожалуйста, введите item_number, item_name и price: " << endl; cin >> item_number; cin >> item_name; cin >> item_price; cout << "Введены значения: item# " << item_number << " " << item_name << " @$" << item_price << endl; |
}
Вот пример выполнения этой программы:
Пожалуйста, введите item_number, item_name и price:
10247 widget 19.99
Введены значения: item# 10247 widget @$19.99
Можно ввести каждый элемент на отдельной строке. По умолчанию оператор ввода отбрасывает все разделяющие пустые символы: пробел, символ табуляции, символ перехода на новую строку, символ перевода страницы и символ возврата каретки. (О том, как отменить это поведение, см. в разделе 20.9.)
Пожалуйста, введите item_number, item_name и price:
10247
widget
19.99
Введены значения: item# 10247 widget @$19.99
При чтении ошибка iostream
более вероятна, чем при записи. Если мы вводим такую последовательность:
// ошибка: item_name должно быть вторым
BuzzLightyear 10009 8.99
то инструкция
cin >> item_number;
закончится ошибкой ввода, поскольку BuzzLightyear не принадлежит типу int. При проверке объекта istream
будет возвращено false, поскольку возникло состояние ошибки. Более устойчивая к ошибкам реализация выглядит так:
cin >> item_number; if ( ! cin ) |
Хотя сцепление операторов ввода поддерживается, проверить корректность каждой отдельной операции нельзя, поэтому пользоваться таким приемом следует лишь тогда, когда ошибка невозможна. Наша программа теперь выглядит так:
#include <iostream> #include <string> int main() { int item_number; string item_name; double item_price; cout << "Пожалуйста, введите item_number, item_name и price: " << endl; // хорошо, но легче допустить ошибку cin >> item_number >> item_name >> item_price; cout << "Введены значения: item# " << item_number << " " << item_name << " @$" << item_price << endl; |
Последовательность
ab c
d e
составлена из девяти символов: 'a', 'b', ' '
(пробел), 'c', '\n'
(переход на новую строку), 'd', '\t' (табуляция), 'e' и '\n'. Однако приведенная программа читает лишь пять букв:
#include <iostream> int main() { char ch; // прочитать и вывести каждый символ while ( cin >> ch ) cout << ch; cout << endl; // ... |
И печатает следующее:
abcde
По умолчанию все пустые символы отбрасываются. Если нам нужны и они, например для сохранения формата входного текста или обработки пустых символов (скажем, для подсчета количества символов перехода на новую строку), то можно воспользоваться функцией-членом get()
класса istream
(обычно в паре с ней употребляется функция-член put()
класса ostream; они будут рассмотрены ниже). Например:
#include <iostream> int main() { char ch; // читать все символы, в том числе пробельные while ( cin.get( ch )) cout.put( ch ); // ... |
Другая возможность сделать это – использовать манипулятор noskipws.
Каждая из двух данных последовательностей считается составленной из пяти строк, разделенных пробелами, если для чтения используются операторы ввода с типами const char* или string:
A fine and private place
"A fine and private place"
Наличие кавычек не делает пробелы внутри закавыченной строки ее частью. Просто открывающая кавычка становится начальным символом первого слова, а закрывающая – конечным символом последнего.
Вместо того чтобы читать из стандартного ввода по одному символу, можно воспользоваться потоковым итератором istream_iterator:
#include <algorithm> #include <string> #include <vector> #include <iostream> int main() { istream_iterator< string > in( cin ), eos ; vector< string > text ; // копировать прочитанные из стандартного ввода значения // в вектор text copy( in , eos , back_inserter( text ) ) ; sort( text.begin() , text.end() ) ; // удалить дубликаты vector< string >::iterator it; it = unique( text.begin() , text.end() ) ; text.erase( it , text.end() ) ; // вывести получившийся вектор int line_cnt = 1 ; for ( vector< string >::iterator iter = text.begin() ; iter != text.end() ; ++iter , ++line_cnt ) cout << *iter << ( line_cnt % 9 ? " " : "\n" ) ; cout << endl; |
}
Пусть входом для этой программы будет файл istream_iter.C с исходным текстом. В системе UNIX мы можем перенаправить стандартный ввод на файл следующим образом (istream_iter – имя исполняемого файла программы):
istream_iter < istream_iter.C
(Для других систем необходимо изучить документацию.) В результате программа выводит:
!= " " "\n" #include % ( ) *iter ++iter
++line_cnt , 1 9 : ; << <algorithm> <iostream.h>
<string> <vector> = > >::difference_type >::iterator ? allocator
back_inserter(
cin copy( cout diff_type eos for in in( int
istream_iterator< it iter line_cnt main() sort( string test test.begin()
test.end() test.erase( typedef unique( vector< { }
(Потоковые итераторы ввода/вывода iostream
рассматривались в разделе 12.4.)
Помимо предопределенных операторов ввода, можно определить и собственные перегруженные экземпляры для считывания в пользовательские типы данных. (Подробнее мы расскажем об этом в разделе 20.5.)