Проблемы, возникающие при вводе строк
Успешно выполнив все описанные ранее операции с объектом cin, вы будете неприятно удивлены, если попытаетесь ввести в строке полное имя. Дело в том, что cin рассматривает пробел как заданный по умолчанию разделитель строк. После того как в строке обнаруживается пробел, ввод строки завершается добавлением концевого нулевого символа. Эта проблема показана в листинге 16.2.
Листинг 16.2. Попытка ввода бодев одного сша с помощьм cin
1: //Листинг 16.2. Проблемы с вводом строки с помощью cin
2:
3: #include <iostream.h>
4:
5: int main()
6: {
7: char YourName[50];
8: cout << "Your first name: ";
9: cin >> YourName;
10: cout << "Here it is: " << YourName << endl;
11: cout << "Your entire name: ";
12: cin >> YourName;
13: cout << "Here it is: " << YourName << endl;
14: return 0;
15: }
Результат:
Your first name: Jesse
Here it is: Jesse
Your entire name: Jesse Liberty
Here it is: Jesse
Анализ: Строкой 7 для хранения вводимой пользователем строки создается массив символов. В строке 8 пользователю предлагается ввести имя, и, как видно из вывода, это имя сохраняется правильно.
В строке 11 пользователю предлагается ввести не только имя, но и фамилию. Ввод осуществляется только до тех пор, пока cin не обнаружит пробел между именем и фамилией. После этого ввод строки прекращается и оставшаяся информация теряется. Это не совсем то, что было нужно.
Чтобы понять, почему cin работает именно так, проанализируйте листинг 16.3, в котором показан пример ввода строки значений.
Листинг 16.3. Ввод строки значений
1: //Листинг 16.3. Ввод строки значений с помощью cin
2:
3: #include <iostream.h>
4:
5: int main()
6: {
7: int myInt;
8: long myLong;
9: double myDouble;
10: float myFloat;
11: unsigned int myUnsigned;
12: char myWord[50];
13:
14: cout << "int: ";
15: cin >> myInt;
16: cout << "Long: ";
17: cin >> myLong;
18: cout << "Double: ";
19: cin >> myDouble;
20: cout << "Float: ";
21: cin >> myFloat;
22: cout << "Word: ";
23: cin >> myWord;
24: cout << "Unsigned: ";
25: cin >> myUnsigned;
26:
27: cout << "\n\nInt:\t" << myInt << endl;
28: cout << "Long:\t" << myLong << endl;
29: cout << "Double:\t" << myDouble << endl;
30: cout << "Float:\t" << myFloat << endl;
31: cout << "Word: \t" << myWord << endl;
32: cout << "Unsigned:\t" << myUnsigned << endl;
33:
34: cout << "\n\nInt, Long, Double, Float, Word, Unsigned: ";
35: cin >> myInt >> myLong >> myDouble;
36: cin >> myFloat >> myWord >> myUnsigned;
37: cout << "\n\nInt:\t" << myInt << endl;
38: cout << "Long:\t" << myLong << endl;
39: cout << "Double:\t" << myDouble << endl;
40: cout << "Float:\t" << myFloat << endl;
41: cout << "Word: \t" << myWord << endl;
42: cout << "Unsigned:\t" << myUnsigned << endl;
43:
44:
45: return 0;
46: }
Результат:
Int: 2
Long: 30303
Double: 393939397834
Float: 3.33
Word: Hello
Unsigned: 85
Int: 2
Long: 30303
Double: 3.93939e+11
Float: 3.33
Word: Hello
Unsigned: 85
Int, Long. Double, Float, Word, Unsigned: 3 304938 393847473 6.66 bye -2
Int: 3
Long: 304938
Double: 3.93847e+08
Float: 6.66
Word: bye
Unsigned: 4294967294
Вновь в программе объявляются переменные разных типов и массив символов. Пользователю предлагается последовательно ввести данные разных типов, чтобы убедиться что программа поддерживает ввод данных любого типа.
Анализ: В строке 34 пользователю предлагается ввести все данные сразу в определенном порядке, после чего каждое введенное значение присваивается соответствующей переменной. Благодаря тому что cin рассматривает пробелы между словами как разделители, становится возможной инициализация всех переменных. В противном случае программа пыталась бы ввести всю строку в одну переменную, что было бы ошибкой.
Обратите внимание на строку 42, в которой выводится без знаковое целое число. Пользователь ввел значение -2. Поскольку программа была проинструктирована, что вводится без знаковое целое число, то вместо знакового -2 будет введено без знаковое двоичное представление этого числа. Поэтому при выводе с помощью cout на экране отображается значение 4294967294, являющееся двоичным представлением числа -2.
Позже вы узнаете, как вводить в буфер строки, содержащие несколько слов, разделенных пробелами. Сейчас же рассмотрим подробнее использование cin для ввода данных сразу в несколько переменных, как в строках 35-36.
Оператор >> возвращает ссылку на объект istream
Оператор >> возвращает ссылку на объект istream. Но поскольку cin сам является объектом istream, результат выполнения одной операции ввода может быть началом следующей операции ввода, как показано ниже:
Int Var0ne, varTwo, varThree;
cout << "Enter three numbers: "
cin >> Var0ne >> varTwo >> varThree;
В строке cin >> VarOne >> varTwo >> varThree; сначала выполняется первый ввод cin >> VarOne, в результате чего возвращается объект istream, позволяющий выполнить присвоение второго значения переменной varTwo. Это равносильно следующей записи:
((cin >> VarOne) >> varTwo) >> varThree;
Аналогичный подход используется с объектом cout, но речь об этом пойдет дальше.
Другие методы объекта cin
В дополнение к перегружаемому оператору >> объект cin имеет множество других встроенных методов. Они используются в тех случаях, когда необходим более совершенный контроль над вводом данных.
Ввод одного символа
Вариант operator>>, принимающий ссылку на символ, может использоваться для считывания одного символа со стандартного устройства ввода. Для этого используется функция-член get(). При этом можно применять get() без параметров или использовать вариант этой же функции, принимающей в качестве параметра ссылку на символ.