Форматированный ввод-вывод базовых типов

Для форматированного ввода-вывода используются перегруженные операции >> и <<(правого и левого сдвига), называемые операциями извлечения (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 ваши программы могут управлять шириной вывода чисел.


 



Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: