Для форматированного ввода-вывода используются перегруженные операции >> и <<(правого и левого сдвига), называемые операциями извлечения (extraction) и вставки (insertion), соответственно. Перегрузка проведена в файле iostream.h так, чтобы облегчить форматированный ввод-вывод значений переменных базовых типов. Операции вставки и извлечения распознают тип правого операнда и в соответствии с установленными правилами форматирования в потоке преобразуют значение этого операнда (листинг 5.4).
Листинг 5.4. Пример форматированного ввода-вывода базовых типов
#include "stdafx.h"
#include <iostream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{ char c = 't';
char s[7] = "string";
int i = 26;
double df = 12.3456789;
ostream *pcout = &cout;
cout << c <<'\n'<<s<<'\n'<<i<<'\n'<<df<<'\n'<<pcout<<'\n';
return 0;
}
Программа показывает свойства форматирования при работе со стандартными потоками cin и cout. В результате ее выполнения на экран будут ны следующие 5 строк:
t
String
26
12.34567
АС8
Последняя строка вывода может отличаться, поскольку шестнадцатеричный адрес размещения области памяти для потока cout может быть другим.
|
|
Для базовых типов и символьных массивов по умолчанию установлены следующие стандартные правила форматирования:
è символы и строки символов выводятся в привычном виде;
è числа выводятся в десятичной системе счисления;
è знак у положительных чисел не выводится;
è у целых чисел выводятся только значащие цифры (незначащие старшие нули отбрасываются);
è вещественные числа выводятся с сохранением до 6 значащих указанием положения десятичной точки, если дробная часть не нулевая; при отбрасывании младших значащих цифр производится округление
Можно управлять форматом ввода-вывода с помощью флагов форматирования потока, которые объявлены в классе ios. Для установки флагов форматирования используются символические константы, ряд из которых приведен в табл. 5.4.
Таблица 5.4. Константы флагов форматирования
Константа | Способ форматирования |
dec | Использовать десятичное представление |
fixed | Для вещественных чисел использовать представление с фиксированной точкой |
hex | Использовать шестнадцатеричное представление |
internal | Помещать символ-заполнитель (по умолчанию пробел) после знака числа или символа-признака основания системы счисления |
left | Прижимать к левому краю при выводе |
oct | Использовать восьмеричное представление |
scientific | Для вещественных чисел использовать "научное" представление: мантисса и порядок, разделенные символом е или Е |
scipws | Пропускать пробельные символы при вводе |
stdio | Освобождать стандартные потоки stdout, stderr языка С после каждого вывода в поток |
unitbuf | Освобождать буферы (выводить содержимое) всех потоков после каждого включения (вывода) в поток |
Флаги форматирования хранятся в защищенном члене класса ios — переменной x_flags типа long. Устанавливать флаги форматирования можно с помощью функции flags () — члена класса ios. Эта функция объявлена вариантах:
|
|
long flags ();
long flags(long new_fmtflags);
Новая совокупность флагов new_fmtfiags может быть получена с помощью операции | (побитного ИЛИ) и констант, приведенных в табл. 5.4. Функции возвращают прежний набор флагов.
Листинг 5.5. Пример использования флагов форматирования
long oldfmtflags = cout.flags();
// задание новых флагов
cout.flags(ios::scientific|ios::hex);
cout <<'\n' <<1.2 << "; (dec) 110 = (hex) " << 110;
// восстановление флагов
cout.flags(oldfmtflags);
cout <<'\n' <<1.2 << "; (dec) 110 = (hex) " << 110;
В примере 5.5 выполняется сохранение флагов, установленных по умолчанию, и установка флагов для вывода вещественных чисел в научном формате (целых чисел в шестнадцатеричной системе счисления. Пояснения приведены в комментариях.
В результате выполнения этого фрагмента на экран будут выведены строки:
1.200000е+00; (dec) 110 = (hex) 6e
1.2; (dec) 110 = (hex) 110???
Сохранять значения флагов, установленных по умолчанию, необязательно Для восстановления начальных установок можно воспользоваться вызовом
Flags (0).
С помощью функции setf () можно устанавливать отдельные флаги без пользования переменной флагов форматирования.
Не все флаги форматирования можно установить одновременно. Информацию о взаимосвязи флагов дают константы, используемые при образовании маски для функции setf (). В классе ios объявлено три таких константы:]
è basefield — поле флагов dec, oct, hex;
è adjustfield—поле флагов lef t, right, internal;
è floatfield —поле флагов scientific и fixed.
è
Эти константы следует использовать в том случае, когда перед установкой флага требуется сбросить все альтернативные флаги.
С помощью функции unsetf () сбрасываются все флаги, которые помечены в параметре. Функция возвращает предыдущее значение переменной x_f lags
Однако не все флаги действуют на входные и на выходные потоки Учет свойств флагов может облегчить ввод некоторых специфических значений.
При выводе данных в виде таблиц часто требуется определять фиксированные размеры строки или символьного представления числа. В этом случае говорят о поле вывода или о числе символов, которые должны быть выведены. Если поле вывода больше числа символов в выводимой строке или числе, то незанятые места заполняются определенными символами. В качестве символа-заполнителя по умолчанию устанавливается пробел. Флаги left, right, internal задают правило размещения числа или строки в этом поле.
Для вещественных чисел часто требуется управлять и точностью представления выводимых чисел.
Значения ширины поля вывода, точности представления и символа заполнителя хранятся в следующих защищенных переменных класса ios:
int x_width; // задает минимальную ширину поля вывода
int x_precision; // определяет максимальное количество значащих цифр вещественного числа
int x_fill; // задает символ-заполнитель поля вывода до минимальной ширины,
Доступ к переменным форматирования обеспечивают функции-члены того же класса, имеющие следующие заголовки:
char fill(); // возвращает используемый символ-заполнитель
// устанавливает новый символ-заполнитель и возвращает прежний символ^
char fill(char cf);
// возвращает значение переменной x_precision
int precision();
// устанавливает новое значение и возвращает прежнее значение int precision(int p);
int width(); // возвращает используемый размер поля вывода
// устанавливает ширину поля вывода и возвращает прежнее значение int width (int w);
< Примечание >
|
|
Новое значение ширины поля вывода действует только на очередную операцию вывода, после которой восстанавливается прежнее значение величины x_width = 0.
Листинг 5.6. Пример управления параметрами форматирования
cout.flags(0);
cout.width(12);
cout.precision(8);
cout.fill('%');
cout.setf(ios::showpoint|ios::showpos|ios::left);
cout<<'\n'<<17.77777<< " = " << 1.77777e1 << " > " << 17<<'\n';
cout.setf(ios::internal);
cout.precision(6);
cout.width(12);
cout.fill('*');
cout<<17.77777<< "!= " << 1.77777e1 << " > " << 17<<'\n';
...
В результате выполнения указанного фрагмента программы (листинг 5.6) на экране появятся строки:
%%%%%%%%%%%+17.777770 = +17.777700 > +17
****+17.7778!= +17.7777 > +17
В приведенных примерах можно выделить два стиля работы с потоками:
l функциональный, когда для управления состоянием потока используются вызовы вида
имя_потока.функция();
l операциональный, который наглядно отражает порядок обмена данными, в виде
имя_потока «выводимое_1_значение «...«n_значение;
имя_потока >> вводимое 1 значение»...» n_значение;
Второй из них представляется более наглядным и более привлекательным. В качестве средства для широкого применения этого стиля используются манипуляторы.
МАНИПУЛЯТОРЫ
Манипуляторами называют специальные функции, позволяющие изменять состояние потока и использующиеся совместно с операциями извлечения и вставки в одном операторе ввода или вывода данных. Отличие манипуляторов от обычных функций состоит в том, что их имена можно использовать в качестве правого операнда при выполнении форматированного обмена с помощью операций << и >>. В качестве самого левого операнда выражения с манипуляторами и операторами обмена всегда используется имя потока.
Например, используя манипуляторы hex, oct и endl, можно написать следующий оператор:
cout <<"(dec) 1023 = (hex) " «hex «1023 «" = (oct) " «1023 << endl;
В результате выполнения на экране появится строка:
(dec) 1023 = (hex) 3ff = (oct) 1777
Стандартные манипуляторы ввода-вывода делятся на две группы: манипуляторы с параметрами и манипуляторы без параметров. Манипуляторы с параметрами объявлены в файле iomanip.h, а без параметров— в iostream.h. В табл. 5.5 приведены стандартные манипуляторы без параметров.
|
|
Таблица 5.5. Манипуляторы без параметров
Манипулятор | Действие в потоке |
dec | Преобразование в десятичное представление |
hex | Преобразование в шестнадцатеричное представление |
oct | Преобразование в восьмеричное представление |
endl | Вставка символа новой строки и выгрузка буфера |
ends | Вставка в поток нулевого признака конца |
flush | Выгрузка буфера выходного потока |
ws | Извлечение и игнорирование пробельных символов |
showbase | Вставка признака системы счисления |
noshowbase | Изъятие признака системы счисления |
skipws | Пропуск пробельных символов при вводе |
noskipws | Отмена пропуска пробельных символов при вводе |
uppercase | Использование символов верхнего регистра при выводе чисел |
nouppercase | Отмена использования символов верхнего регистра при выводе чисел |
internal | Вставка заполнителей между знаком и модулем выводимого числа |
left | Вставка заполнителей после значения в поле вывода |
right | Вставка заполнителей перед значением в поле вывода |
fixed | Использование для вещественных чисел формата dddd. dd |
scientific | Использование для вещественных чисел формата l.ddddd e dd |
boolalpha | Вывод данных типа bool в символическом виде |
noboolalpha | Вывод данных типа bool как целых чисел |
Манипуляторы без параметров управляют флагами форматирования потока и буфером потока.
Манипулятор endl удобно использовать для немедленной выдачи сообщений программы.
Например:
cout «"\nModeling is going." «endl;
Вывод с таким использованием манипулятора endl избавляет от необходимости ожидания заполнения буфера до момента окончания процесса моделирования.
Чтобы избежать подобных ситуаций при выводе сообщения об ошибках, целесообразно направлять в небуферизованный поток сеrr. При этом именем потока отмечается место обработки ошибок в программе (листинг 5.7).
Листинг 5.7. Пример вывода сообщений об ошибках в поток сеrr
if (SizeFile > MaxSizeFile)
{
сеrr «"\nSize of file is very large.";
// операторы обработки ошибки
}
Если при выводе не требуется начинать новую строку и нужно обеспечить немедленное освобождение буфера, то следует использовать манипулятор flush.
Например,
clog «"\nWork is finishing." «flush;
Для управления точностью, шириной поля вывода и другими параметрами форматирования используются манипуляторы с параметрами, приведены в табл. 5.6.
Таблица 5.6. Манипуляторы с параметрами
Манипулятор с параметром | Действие в потоке |
resetiosflags (long f flags) | Сброс флагов форматирования |
setiosflags (long f flags) | Установка флагов форматирования |
setbase (int b) | Установка системы счисления с заданным основанием |
setfill (int cf) | Установка символа-заполнителя |
setpresision (int p) | Установка точности вывода вещественных чисел |
setw (int w) | Установка ширины поля для очередной операции вывода |
Отметим, что манипуляторы обеспечивают все возможности методов ios для управления форматированием.
Листинг 5.8. Использование манипуляторов с параметрами
#include "stdafx.h"
#include <iostream>
#include <iomanip>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
double darray[]={6.7891, -0.0089, 5.6789};
char col__name [ ] = "Rounded values:";
cout «setw(sizeof (col_name)) «col_name«endl;
cout «setprecision(3) «setiosflags(ios::fixed | ios::showpoint);
cout «setfill('x') «setiosflags (ios::showpos | ios::left);
for (int i=0;i<sizeof(darray)/sizeof(darray[0]);i++)
cout «setw(sizeof (col_name)) «darray [i]«endl;
return 0;
}
В результате выполнения программы (листинг 5.8) на экран будут выведены строки с заголовком столбцов и округленными значениями элементов массива:
Rounded values:
+6.7891хххххххххх
-0.0089хххххххххх
+5.6789ххххххххх
< Примечание >
При использовании специальных символов, перечисленных в табл. 4.1, следует располагать их внутри одинарных кавычек, если вы используете данные символы сами по себе, например '\n', или внутри двойных кавычек, если вы используете их внутри строки, например "Привem\nMup!".
Следующая программа SPECIAL.CPP использует специальные символы сигнала (\а) и табуляции (\t) для выдачи звука на встроенный динамик компьютера и затем выводит слова Звонок Звонок Звонок, разделенные табуляцией:
Резюме
В этой лекции обсуждались вопросы использования cout для отображения вывода на экран. Все программы, которые вы создадите в процессе изучения оставшейся части книги, будут использовать cout для отображения вывода. Сейчас мы должны запомнить следующие основные концепции:
1. Выходной поток cout позволяет нам выводить символы и числа.
2. Используя специальные символы внутри выходного потока, наша программа может указать новую строку, табуляцию и другие специальные возможности.
3. Для продвижения курсора в начало следующей строки программы могут создать новую строку, используя символ \n или модификатор endl.
4. Модификаторы dec, oct и hex позволяют программам выводить значения в десятичном, восьмеричном и шестнадцатеричном виде.
5. Используя выходной поток cerr, программы могут записать сообщения в стандартное устройство ошибок операционной системы.
6. С помощью модификатора setw ваши программы могут управлять шириной вывода чисел.