Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C++ для начинающих (Стенли Липпман) 3-е хххх.pdf
Скачиваний:
99
Добавлен:
30.05.2015
Размер:
6 Мб
Скачать
☆

С++ для начинающих

1024

#include <sstream>

string program_name( "our_program" ); string version( 0.01 );

// ...

string mumble( int *array, int size )

{

if ( ! array ) { ostringstream out_message;

out_message << "ошибка: "

<<program_name << "--" << version

<<": " << __FILE__ << ": " << __LINE__

<<" -- указатель равен 0; "

<<" а должен адресовать массив.\n";

//возвращаем строку, в которой находится сообщение return out_message.str();

}

// ...

}

(В разделе 20.8 мы познакомимся со строковым вводом/выводом более подробно.)

Потоки ввода/вывода поддерживают два предопределенных типа: char и wchar_t. В этой главе мы расскажем только о чтении и записи в потоки данных типа char. Помимо них, в библиотеке iostream имеется набор классов и объектов для работы с типом wchar_t. Они отличаются от соответствующих классов, использующих тип char, наличием префикса ‘w’. Так, объект стандартного ввода называется wcin, стандартного вывода – wcout, стандартного вывода для ошибок – wcerr. Но набор заголовочных файлов для char и wchar_t один и тот же.

Классы для ввода/вывода данных типа wchar_t называются wostream, wistream, wiostream, для файлового ввода/вывода – wofstream, wifstream, wfstream, а для строкового – wostringstream, wistringstream, wstringstream.

20.1. Оператор вывода <<

Оператор вывода обычно применяется для записи на стандартный вывод cout.

#include <iostream>

int main()

{

cout << "сплетница Анна Ливия\n";

Например, программа

}

печатает на терминале строку:

сплетница Анна Ливия

С++ для начинающих

1025

Имеются операторы, принимающие аргументы любого встроенного типа данных,

включая 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 << "некоторая строка";

С++ для начинающих

1026

служит левый операнд оператора вывода, т.е. сам объект 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

Позже мы покажем, как напечатать адреса в десятичном виде.

Следующая программа ведет себя странно. Мы хотим напечатать адрес, хранящийся в

#include <iostream>

const char *str = "vermeer"; int main()

{

const char *pstr = str; cout << "Адрес pstr равен: "

<< pstr << endl;

переменной pstr:

}

Но после компиляции и запуска программа неожиданно выдает такую строку:

Адрес pstr равен: vermeer

Проблема в том, что тип const char* интерпретируется как C-строка. Чтобы все же напечатать адрес, хранящийся в pstr, необходимо подавить обработку типа const

С++ для начинающих

1027

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 );

Теперь результат получается правильный:

С++ для начинающих

1028

Большее из 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;

и напечатать каждый из них:

С++ для начинающих

1029

}

Вместо того чтобы явно обходить все элементы контейнера, выводя каждый по очереди, можно воспользоваться потоковым итератором ostream_iterator. Так выглядит эквивалентная программа, где используется эта техника (подробное обсуждение

#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;

итератора ostream_iterator см. в разделе 12.4):

}

Программа печатает такую строку:

Это друзья Пуха: Тигра Пятачок Иа-Иа Кролик

Упражнение 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;

Даны следующие определения объектов: complex purei( 0, 7 );

(a)Направьте значение каждого объекта в стандартный вывод.

(b)Напечатайте значение адреса pc.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]