Опубликован: 26.06.2003 | Доступ: свободный | Студентов: 36634 / 5382 | Оценка: 4.07 / 3.80 | Длительность: 15:14:00
ISBN: 978-5-9556-0017-8
Лекция 17:

Ввод-вывод

< Лекция 16 || Лекция 17: 123 || Лекция 18 >

Манипуляторы и форматирование ввода-вывода

Часто бывает необходимо вывести строку или число в определенном формате. Для этого используются так называемые манипуляторы.

Манипуляторы – это объекты особых типов, которые управляют тем, как ostream или istream обрабатывают последующие аргументы. Некоторые манипуляторы могут также выводить или вводить специальные символы.

С одним манипулятором мы уже сталкивались, это endl. Он вызывает вывод символа новой строки. Другие манипуляторы позволяют задавать формат вывода чисел:

endl при выводе перейти на новую строку;
ends вывести нулевой байт (признак конца строки символов);
flush немедленно вывести и опустошить все промежуточные буферы;
dec выводить числа в десятичной системе (действует по умолчанию);
oct выводить числа в восьмеричной системе;
hex выводить числа в шестнадцатиричной системе счисления;
setw (int n) установить ширину поля вывода в n символов ( n – целое число);
setfill(int n) установить символ-заполнитель; этим символом выводимое значение будет дополняться до необходимой ширины;
setprecision(int n) установить количество цифр после запятой при выводе вещественных чисел;
setbase(int n) установить систему счисления для вывода чисел; n может принимать значения 0, 2, 8, 10, 16, причем 0 означает систему счисления по умолчанию, т.е. 10.

Использовать манипуляторы просто – их надо вывести в выходной поток. Предположим, мы хотим вывести одно и то же число в разных системах счисления:

int  x  =  53;
cout << "Десятичный вид:        " << dec  
     <<  x  <<  endl
     << "Восьмиричный вид:      " << oct  
     <<  x  <<  endl
     << "Шестнадцатиричный вид: " << hex  
     <<  x  <<  endl

Аналогично используются манипуляторы с параметрами. Вывод числа с разным количеством цифр после запятой:

double x;
// вывести число в поле общей шириной 
// 6 символов (3 цифры до запятой, 
// десятичная точка и 2 цифры после запятой)
cout  <<  setw(6)  <<  setprecision(2) << fixed <<  x  <<  endl;

Те же манипуляторы (за исключением endl и ends ) могут использоваться и при вводе. В этом случае они описывают представление вводимых чисел. Кроме того, имеется манипулятор, работающий только при вводе, это ws. Данный манипулятор переключает вводимый поток в такой режим, при котором все пробелы (включая табуляцию, переводы строки, переводы каретки и переводы страницы) будут вводиться. По умолчанию эти символы воспринимаются как разделители между атрибутами ввода.

int x;
// ввести шестнадцатиричное число
cin  >>  hex  >>  x;

Строковые потоки

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

Например, в приведенном в предыдущей главе классе Exception для исключительной ситуации можно добавить сообщение. Если мы хотим составить сообщение из нескольких частей, то может возникнуть необходимость форматирования этого сообщения:

// произошла ошибка
strstream  ss;
ss  << "Ошибка ввода-вывода, регистр: " 
    <<  oct  <<  reg1;
ss  << "Системная ошибка номер: " << dec  
    <<  errno  <<  ends;
String  msg(ss.str());
ss.rdbuf()->freeze(0);
Exception ex(Exception::INTERNAL_ERROR, msg);
throw  ex;

Сначала создается объект типа strstream с именем ss. Затем в созданный строковый поток выводятся сформатированные нужным образом данные. Отметим, что в конце мы вывели манипулятор   ends, который добавил необходимый для символьной строки байтов нулевой байт. Метод str() класса strstream предоставляет доступ к сформатированной строке (тип его возвращаемого значения – char* ). Следующая строка освобождает память, занимаемую строковым потоком (подробнее об этом рассказано ниже). Последние две строки создают объект типа Exception с типом ошибки INTERNAL_ERROR и сформированным сообщением и вызывают исключительную ситуацию.

Важное свойство класса strstream состоит в том, что он автоматически выделяет нужное количество памяти для хранения строк. В следующем примере функция split_numbers выделяет числа из строки, состоящей из нескольких чисел, разделенных пробелом, и печатает их по одному на строке.

#include  <strstream.h>
void
split_numbers(const  char* s)
{
    strstream  iostr;
    iostr  <<  s  <<  ends;
    int  x;
    while  (iostr  >>  x) 
    cout  <<  x<<  endl;
}
int
main()
{
    split_numbers("123  34  56  932");
    return 1;
}

Замечание. В среде Visual C++ файл заголовков называется strstream.h.

Как видно из этого примера, независимо от того, какова на самом деле длина входной строки, объект iostr автоматически выделяет память, и при выходе из функции split_numbers, когда объект уничтожается, память будет освобождена.

Однако из данного правила есть одно исключение. Если программа обращается непосредственно к хранимой в объекте строке с помощью метода str (), то объект перестает контролировать эту память, а это означает, что при уничтожении объекта память не будет освобождена. Для того чтобы память все-таки была освобождена, необходимо вызвать метод rdbuf()->freeze(0) (см. предыдущий пример).

< Лекция 16 || Лекция 17: 123 || Лекция 18 >
Елена Шумова
Елена Шумова

Здравствуйте! Я у Вас прошла курс Язык программировая Си++.

Заказала сертификат. Хочу изменить способ оплаты. Как это сделать?

Маргарита Башкатова
Маргарита Башкатова
Анатолий Федоров
Анатолий Федоров
Россия, Москва, Московский государственный университет им. М. В. Ломоносова, 1989
Рустам Новиков
Рустам Новиков
Эстония, Таллин