Оператор вывода <<
Оператор вывода обычно применяется для записи на стандартный вывод cout. Например, программа
#include <iostream> int main() { cout << "сплетница Анна Ливия\n"; |
}
печатает на терминале строку:
сплетница Анна Ливия
Имеются операторы, принимающие аргументы любого встроенного типа данных, включая const char*, а также типов string и complex из стандартной библиотеки. Любое выражение, включая вызов функции, может быть аргументом оператора вывода при условии, что результатом его вычисления будет тип, принимаемый каким-либо вариантом этого оператора. Например, программа
#include <iostream> #include <string.h> int main() { cout << "Длина 'Улисс' равна:\t"; cout << strlen( "Улисс" ); cout << '\n'; cout << "Размер 'Улисс' равен:\t"; cout << sizeof( "Улисс" ); cout << endl; |
}
выводит на терминал следующее:
Длина 'Улисс' равна:7
Размер 'Улисс' равен:8
endl – это манипулятор вывода, который вставляет в выходной поток символ перехода на новую строку, а затем сбрасывает буфер объекта ostream. (С буферизацией мы познакомимся в разделе 20.9.)
Операторы вывода, как правило, удобнее сцеплять в одну инструкцию. Например, предыдущую программу можно записать таким образом:
#include <iostream> #include <string.h> int main() { // операторы вывода можно сцеплять cout << "Длина 'Улисс' равна:\t"; << strlen( "Улисс" ) << '\n'; cout << "Размер 'Улисс' равен:\t" << sizeof( "Улисс" ) << endl; |
}
Сцепление операторов вывода (и ввода тоже) возможно потому, что результатом выражения
cout << "некоторая строка";
служит левый операнд оператора вывода, т.е. сам объект cout. Затем этот же объект передается следующему оператору и далее по цепочке (мы говорим, что оператор << левоассоциативен).
Имеется также предопределенный оператор вывода для указательных типов, который печатает адрес объекта. По умолчанию адреса отображаются в шестнадцатеричном виде. Например, программа
#include <iostream> int main() { int i = 1024; int *pi = &i; cout << "i: " << i << "\t&i:\t" << &i << '\n'; cout << "*pi: " << *pi << "\tpi:\t" << pi << endl << "\t\t&pi:\t" << &pi << endl; |
выводит на терминал следующее:
i: 1024 &i: 0x7fff0b4
*pi: 1024 pi: 0x7fff0b4
&pi: 0x7fff0b0
Позже мы покажем, как напечатать адреса в десятичном виде.
Следующая программа ведет себя странно. Мы хотим напечатать адрес, хранящийся в переменной pstr:
#include <iostream> const char *str = "vermeer"; int main() { const char *pstr = str; cout << "Адрес pstr равен: " << pstr << endl; |
Но после компиляции и запуска программа неожиданно выдает такую строку:
Адрес pstr равен: vermeer
Проблема в том, что тип const char*
интерпретируется как C-строка. Чтобы все же напечатать адрес, хранящийся в pstr, необходимо подавить обработку типа const char* по умолчанию. Для этого мы сначала убираем спецификатор const, а затем приводим pstr к типу void*:
<< static_cast<void*>(const_cast<char*>(pstr))
Теперь программа
выводит ожидаемый результат:
Адрес pstr равен: 0x116e8
А вот еще одна загадка. Нужно напечатать большее из двух чисел:
#include <iostream> inline void max_out( int val1, int val2 ) { cout << ( val1 > val2 ) ? val1 : val2; } int main() { int ix = 10, jx = 20; cout << "Большее из " << ix << ", " << jx << " равно "; max_out( ix, jx ); cout << endl; |
}
Однако программа выдает неправильный результат:
Большее из 10, 20 равно 0
Проблема в том, что оператор вывода имеет более высокий приоритет, чем оператор условного выражения, поэтому печатается результат сравнения val1 и val2. Иными словами, выражение
cout << ( val1 > val2 ) ? val1 : val2;
вычисляется как
(cout << ( val1 > val2 )) ? val1 : val2;
Поскольку val1 не больше val2, то результатом сравнения будет false, обозначаемый нулем. Чтобы изменить приоритет операций, весь оператор условного выражения следует заключить в скобки:
cout << ( val1 > val2 ? val1 : val2 );
Теперь результат получается правильный:
Большее из 10, 20 равно 20
Такого рода ошибку было бы проще найти, если бы значения литералов true и false
типа bool
печатались как строки, а не как 1 и 0. Тогда мы увидели бы строку:
Большее из 10, 20 равно false
и все стало бы ясно. По умолчанию литерал false
печатается как 0, а true – как 1. Это можно изменить, воспользовавшись манипулятором boolalpha(), что и сделано в следующей программе:
int main() { cout << "печать значений типа bool по умолчанию: " << true << " " << false << "\nи в виде строк: " << boolalpha() << true << " " << false << endl; |
Вот результат:
печать значений типа bool по умолчанию: 1 0
и в виде строк: true false
Для вывода массива, а также вектора или отображения, необходимо обойти все элементы и напечатать каждый из них:
#include <iostream> #include <vector> #include <string> string pooh_pals[] = { "Тигра", "Пятачок", "Иа-Иа", "Кролик" }; int main() { vector<string> ppals( pooh_pals, pooh_pals+4 ); vector<string>::iterator iter = ppals.begin(); vector<string>::iterator iter_end = ppals.end(); cout << "Это друзья Пуха: "; for ( ; iter != iter_end; iter++ ) cout << *iter << " "; cout << endl; |
}
Вместо того чтобы явно обходить все элементы контейнера, выводя каждый по очереди, можно воспользоваться потоковым итератором ostream_iterator. Так выглядит эквивалентная программа, где используется эта техника (подробное обсуждение итератора ostream_iterator см. в разделе 12.4):
#include <iostream> #include <algorithm> #include <vector> #include <string> string pooh_pals[] = { "Тигра", "Пятачок", "Иа-Иа", "Кролик" }; int main() { vector<string> ppals( pooh_pals, pooh_pals+4 ); vector<string>::iterator iter = ppals.begin(); vector<string>::iterator iter_end = ppals.end(); cout << "Это друзья Пуха: "; // копируем каждый элемент в cout ... ostream_iterator< string > output( cout, " " ); copy( iter, iter_end, output ); cout << endl; |
Программа печатает такую строку:
Ýòî äðóçüÿ Ïóõà: Òèãðà Ïÿòà÷îê Èà-Èà Êðîëèê
Упражнение 20.1
Даны следующие определения объектов:
string sa[4] = { "пух", "тигра", "пятачок", "иа-иа" }; vector< string > svec( sa, sa+4 ); string robin( "кристофер робин" ); const char *pc = robin.c_str(); int ival = 1024; char blank = ' '; double dval = 3.14159; |
(a) Направьте значение каждого объекта в стандартный вывод.
(b) Напечатайте значение адреса pc.
(c) Напечатайте наименьшее из двух значений ival и dval, пользуясь оператором условного выражения:
ival < dval ? ival : dval