Флаги и форматирующие методы




ВВЕДЕНИЕ

Стандартную библиотеку С++ можно разделить на две части. К первой части относятся функции, макросы, типы и константы, унаследованные из библиотеки С; ко второй – классы и другие средства С++.

Классы стандартной библиотеки можно разделить на следующие группы.

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

Строковый класс – предназначены для работы с символьными переменными.

Контейнерные классы – реализуют структуры для хранения данных (списки, векторы, множества).

Итераторы – предназначены для унифицированного доступа к элементам классов.

Математические классы – поддерживают обработку массивов с плавающей точкой и работу с комплексными числами.

Диагностические классы – обеспечивают динамическую идентификацию типов и объектно-ориентированную обработку ошибок.

Остальные классы обеспечивают динамическое распределение памяти и ряд других функций.

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

 


Потоковые классы

 

Поток – это абстрактное понятие, относящееся к любому переносу данных от источника к приемнику.

Чтение данных из потока извлечением, вывод в поток – помещением или включением. Поток определяется как последовательность байтов и не зависит от конкретного устройства, с которым производится обмен. Обмен с потоком для увеличения скорости передачи данных производится, как правило, через специальную область данных – буфер.

По направлению обмена потоки можно разделить на входные (данные вводятся в память) и двунаправленные (допускающие как извлечение, так и включение).

По виду устройств, с которыми работает поток, можно выделить стандартные, файловые и строковые потоки.

Стандартные потоки предназначены для передачи данных от клавиатуры и на экран.

Файловые потоки – для обмена информацией с файлами на внешних устройствах.

Строковые потоки – для работы с массивами символов.

Для поддержки потоков библиотека С++ содержит иерархию классов, построенную на основе двух базовых классов – ios и sterambuf. Класс ios содержит общие для ввода и вывода поля и методы, класс steambuf обеспечивает буферизацию потоков и их взаимодействие с физическими устройствами.

Далее перечисляются часто используемые классы потоков:

ios – базовый класс потоков;

istream – класс входных потоков;

ostream – класс выходных потоков;

iostream – класс двунаправленных потоков;

istringstream – класс входных строковых потоков;

ostringstream – класс выходных строковых потоков;

stringstream – класс двунаправленных потоков;

ifstream – класс входных файловых потоков;

ofstream – класс выходных файловых потоков;

fstream – класс двунаправленных файловых потоков.

Описание классов находится в заголовочных файлах:

<ios> – базовый класс ввода/вывода;

<iosfwd> – предварительные объявления средств ввода/вывода;

<istream> – шаблон потока ввода;

<ostream> – шаблон потока вывода;

<iostream> – стандартные объекты и операции с потоками ввода/вывода;

<fstream> – потоки ввода/вывода в файлы;

<sstream> – потоки ввода/вывода в строки;

<streambuf> – буферизация потоков ввода/вывода;

<iomanip>–манипуляторы (см. далее).

Стандартные потоки

 

Заголовочный файл <iostream> помимо описания классов для ввода/вывода содержит четыре предопределенных объекта (табл.1).

 

Таблица 1

Предопределенные объекты

 

Объект Класс Описание
     
cin istream Связывается с клавиатурой (стандартным буферизованным вводом)
cout ostream Связывается с экраном (стандартным буферизованным выводом)

Окончание табл.1

     
cerr ostream Связывается с экраном (стандартным небуферизованным выводом), куда направляются сообщения об ошибках
clog ostream Связывается с экраном (стандартным буферизованным выводом), куда направляются сообщения об ошибках

 

 

В классах istream и ostream операции извлечения из потока >> и помещения в поток << определены путем перегрузки операций сдвига.

Числовые значения можно вводить в десятичной или шестнадцатеричной системе счисления (с префиксом 0x) со знаком или без знака. Вещественные числа представляются в форме с фиксированной точкой или плавающей точкой (с порядком).

При вводе строки извлечение происходит до ближайшего пробела (вместо него в строку записывается 0-символ).

Значения указателей вводятся в шестнадцатеричной системе счисления.

Форматирование данных

 

Форматирование в потоковых классах выполняется тремя способами: с помощью флагов, манипуляторов и форматирующих методов.

Флаги и форматирующие методы

Флаги – это отдельные биты, объединенные в поле x_flags типа long класса ios.

 

Таблица 2

Некоторые флаги форматирования

 

Флаг Умолчание Описание
     
skipws + При извлечении пробельные символы игнорируются
left - Выравнивание по левому краю поля
right + Выравнивание по правому краю поля
internal - Знак числа выводится по левому краю, число – по правому
dec + Десятичная система счисления
oct - Восьмеричная система счисления
hex - Шестнадцатеричная система счисления
showbase - Выводится основание системы счисления (0x – шестнадцатеричная, 0 – восьмеричная)
showpoint - При выводе числа печатается точка и дробная часть числа
uppercase - Использование при выводе верхнего регистра
scientific - Печать вещественных чисел в экспоненциальной форме
fixed - Печать вещественных чисел в форме с фиксированной точкой

 

Для управления флагами в классе ios есть методы flags, setf и unsetf.

long ios:: flags (long); – возвращает текущие флаги потока;

long ios:: flags (long); – присваивает флагам значение параметра;

long ios:: setf (long, long); – присваивает флагам, биты которых установлены в первом параметре, значение соответствующих битов второго параметра;

long ios:: setf (long, long); – устанавливает флаги, биты которых установлены в параметре;

long ios:: unsetf (long, long); – сбрасывает флаги, биты которых установлены в параметре;

Все функции возвращают прежние флаги потока.

Кроме флагов для форматирования используются поля класса ios:

int x_width – минимальная ширина поля;

int x_precision – количество цифр в дробной части числа;

int x_fill – символ заполнения поля вывода.

Для управления этими полями используются методы width, precision и fill:

int ios:: width () – возвращает значение ширины поля вывода;

int ios:: width () – устанавливает значение ширины поля вывода;

int ios:: precision () – возвращает значение точности представления дробной части;

int ios:: precision (int) – устанавливает значение точности представления дробной части;

char fill () – возвращает текущий символ заполнения;

char fill (char) – устанавливает значение текущего символа заполнения (по умолчанию – пробел).

Перед установкой некоторых флагов требуется сбросить флаги, которые не могут быть установлены одновременно с ними. Для этого удобно использовать вторым параметром метода setf статические константы класса ios:

adjustfield (left | right | internal)

basefield (dec | oct | hex)

floatfield (scientific | fixed)

Пример

# include <iostream.h>

int main () {

long a = 100, b = 077;

cout.width (7); cout.unsetf (ios:: dec);

cout.setf (ios:: hex | ios:: showbase | ios::uppercase);

cout << a;

cout.width (7);

cout << b << endl;

double d = 0.12, c = 1.3e-4;

cout.setf(ios:: left);

cout << d << endl;

cout << c;

return 0;

}

 

Результат работы программы:

0X3T8 0X3F

0.12

0.00013

Манипуляторы

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

Простые манипуляторы

dec – устанавливает флаг десятичной системы;

oct – устанавливает флаг восьмеричной системы;

hex – устанавливает флаг шестнадцатеричной системы;

ws – устанавливает при вводе извлечение пробельных символов;

endl – при выводе включает в поток символ новой строки и выгружает буфер;

ends – при выводе включает в поток нулевой символ;

flush – при выводе выгружает буфер.

Изменение системы счисления действует до следующего явного изменения.

Пример

cout << 13 << hex << ‘ ‘ << 13 << oct << ‘ ‘ << 13 << endl;

На экране:

13 d 15

Параметризованные манипуляторы

Параметризованные манипуляторы – это манипуляторы, имеющие аргумент. Для их использования необходимо подключать заголовочный файл <iomanip>.

setbase (int n) – задает основание системы счисления (n = 8, 10, 16 или 0). 0 – основание по умолчанию (десятичное, кроме случаев, когда вводятся восьмеричные или шестнадцатеричные числа);

resetiosflags (long) – сбрасывает флаги состояния потока, биты которых установлены в параметре;

setfill (int) – устанавливает символ-заполнитель с кодом, равным значению параметра;

setprecision (int) – устанавливает максимальное количество цифр в дробной части чисел;

setw (int) – устанавливает максимальную ширину поля вывода;

setiosflags (long) – устанавливает флаги состояния потока, биты которых в параметре равны 1.

 

Пример

double d (1.234);

cout << setfill (‘.’) << setprecision (4)

<< setiosflags (ios:: showpoint | ios:: fixed);

cout << setw (12) << d << endl;

На экране:

……1.2340

 

Методы обмена с потоком

 

В потоковых классах наряду с операциями извлечения >> и включения << определены методы для неформатированного чтения и записи в поток (при этом преобразования данных не выполняются).

 

Функция Назначение
   
Класс istream
gcount () Возвращает количество символов, считанных с помощью последней функции неформатированного ввода
get () Возвращает код извлеченного из потока символа или EOF
get (buf, num, lim = ‘\n’) Считывает num-1 символов (или пока не встретится символ lim) и копирует их в строку buf. Вместо символа lim в строку записывается признак конца строки (‘\0’). Символ lim остается в потоке. Возвращает ссылку на текущий поток
getline (buf, num, lim = ‘\n’) Аналогична get (), но копирует в buf и символ lim    

Продолжение таблицы

   
ignore (num = 1, lim = EOF) Считывает и пропускает символы до тех пор, пока не будет прочитано num символов (по умолчанию 1) или не встретится разделитель lim. Возвращает ссылку на текущий поток
peek () Возвращает следующий символ без удаления его из потока или EOF, если достигнут конец файла
putback (c) Помещает в поток символ с, который становится текущим при извлечении из потока
read (buf, num) Считывает num символов (или все символы до конца файла, если их меньше num) в символьный массив buf и возвращает ссылку на текущий поток
readsome (buf, num) Считывает num символов в символьный массив buf и возвращает количество считанных символов
seekg (pos) Устанавливает текущую позицию чтения в значение pos
seekg (offs, org) Перемещает текущую позицию чтения на offs байтов, считая от одной из трех позиций, определяемых параметром org: ios:: beg (от начала), ios:: cur (от текущей позиции) и ios:: end (от конца файла)
tellg () Возвращает текущую позицию чтения потока
Класс ostream
flush () Записывает содержимое потока вывода на физическое устройство
рut (с) Выводит в поток символ с и возвращает ссылку на поток

Окончание таблицы

   
seekg (pos) Устанавливает текущую позицию записи в значение pos
seek (ofs, org) Перемещает текущую позицию записи на offs байтов, считая от одной из трех позиций (см. выше)
tellg () Возвращает текущую позицию записи потока
write (buf, num) Записывает в поток num символов из массива buf и возвращает ссылку на поток

Пример 1. Программа считывает строки из входного потока в символьный массив.

# include <iostream.h>

int main () {

const int N = 20, Len = 100;

char str [Len] [N]

int i = 0;

while (cin.getline (str [i], Len, ‘\n’) & & i < N) {

i ++;}

return 0;

}

Пример 2. Программа формирует файл test, в который вводится три строки (файловые потоки см. далее).

# include <iostream.h>

# include <fstream.h>

# include <string.h>

int main () {

// Запись в файл

ofstream out (“test”);

if (!out) {

cout << “Нельзя открыть файл для записи” << endl;

return 1;

}

char *str [ ] = {“the first line”, “the second line”, “the third line”};

for (int i = 0; i<3, ++ i) {

out.write (str [i], strlen (str [i]));

out.put (‘\n’);

}

out.close ();

// Чтение из файла

ifstream in (“test”);

if (! in) {

cout << “Нельзя открыть файл для чтения” << endl;

return 1;

}

char check_str [3] [30];

for (int i = 0; i < 3; ++ i) {

in.get (check_str [i], 30);

in.get (); }

for (int i = 0; i < 3; ++ i) cout << check_str [i] << endl;

in.close ();

return 0;

}

Пример 3. Программа с функциями peek () и putback ().

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

# include <iostream.h>

# include <fstream.h>

# include <stdlib>

int main () {

char ch;

// Подготовка файла

ofstream out (“test”);

cout << “Нельзя открыть файл test для записи” << endl;

return1;

}

char str [80], *p;

out << 123 << “Это выполняется тест” << 23;

out << “Всем привет” << 99 << “Пока” << endl;

out.close ();

// Чтение файла

ifstream in (“test”);

if (!in) {

cout << “Нельзя открыть файл test для чтения” << endl;

return 1;

}

do {

p = str;

ch = in.peek (); // определяем тип следующего значения

if (isdigit(ch)) {

while (isalpha (*p = in.get ())) p ++; // считываем целые

in.putback (*p); // возврат символа в поток

*р = “\0”; // заканчиваем строку нулем

cout << “Число:” << atoi (str);

}

else if (isalpha (ch)) { //считываем строку

while (isalpha (*p = in.get ())) p ++;

in.putback (*p); // возврат символа в поток

*p = ‘\0’; // заканчиваем строку нулем

cout << “Строка:” << str;

}

else in.get (); // пропуск

cout << endl;

} while (!in.eof ());

in.close ();

return 0;

}

Результат работы программы:

Число: 123

Строка: Это

Строка: выполняется

Строка: тест

Число: 23

Строка: Всем

Строка: привет

Число: 99

Строка: Пока

Ошибки потоков

В базовом классе ios определено поле state, которое представляет собой состояние потока в виде совокупности битов:

enum io_state {

googbit = 0x00, // Нет ошибок

eofbit = 0x01, // Достигнут конец файла

failbit = 0x02, // Ошибка форматирования или преобразования

badbit = 0x04, // Серьезная ошибка, после которой пользоваться потоком

// нельзя

hardbit = 0x08 // Неисправность оборудования

};

Состоянием потока можно управлять с помощью следующих методов и операций:

int rdstate () – возвращает текущее состояние потока;

int eof () – возвращает ненулевое значение, если установлен флаг eofbit;

int fail () – возвращает ненулевое значение, если установлен один из флагов failbit, badbit или hardbit;

int good () – возвращает ненулевое значение, если сброшены все флаги ошибок;

void clear (int = 0) – параметр принимается в качестве состояния ошибки, при отсутствии параметра состояние ошибки устанавливается 0;

operator void *() – возвращает нулевой указатель, если установлен хотя бы один бит ошибки;

operator! () – возвращает ненулевой указатель, если установлен хотя бы один бит ошибки.

Пример. Наиболее часто используемые операции с флагами состояния потока:

// Проверить, установлен ли флаг flag

if (steam_obj.rdstate () & ios:: flag)

// Сбросить флаг flag

stream_obj.clear (rdstate () & ~ios:: flag)

// Установить флаг flag

stream_obj.clear (rdstate () | ios:: flag)

// Установить флаг flag и сбросить все остальные

stream_obj.clear (ios:: flag)

// Сбросить все флаги

stream_obj.clear ()

 

Операция void *() неявно вызывается всякий раз, когда поток сравнивается с нулем. Это поволяет записывть циклы вида:

while (stream_obj) {

// Все в порядке, можно производить ввод/вывод

}

Файловые потоки

 

Стадартная библиотека содержит три класса для работы с файлами:

ifstream – класс входных файловых потоков;

ofstream – класс выходных файловых потоков;

fstream – класс двунаправленных файловых потоков.

Эти классы являются производными от классов istream, ostream и iostream соответственно.

Использование файлов в программе предполагает следующие операции:

- создание потока;

- открытие потока;

- обмен (ввод/вывод);

- уничтожение потока;

- закрытие файла.

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

Конструкторы без параметров создают объект соответствующего класса, не связывая его с файлом:

ifstream ();

ofstream ();

fstream ();

Конструкторы с параметрами создают объект соответствующего класса, открывают файл с указанным именем и связывают файл с объектом:

ifstream (const char * name, int mode = ios:: in);

ofstream (const char * name, int mode = ios:: out | ios:: trunc);

fstream (const char * name, int mode = ios:: in | ios:: out);

здесь второй параметр – это режим открытия файла.

 

 

Открыть файл в программе можно с использованием либо конструкторов, либо метода open, имеющего такие же параметры, как и в соответствующем конструкторе.

Пример 1

ifstream inpf (“input.txt”); // используем конструктор

if (! inpf) {

cout << “Невозможно открыть файл для чтения”;

return 1;

}

Пример 2

ofstream f;

f.open (“output.txt”, ios:: out); //используем метод open

if (!f) {

cout << “Невозможно открыть файл для записи”;

return 1;

}

Чтение и запись выполняются либо с помощью операций чтения и извлечения, аналогичных потоковым классам, либо с помощью методов классов.

Пример. Вывод на экран содержимого файла.

# include <fstream.h>

int main () {

char text [81], buf [81];

cout << “Введите имя файла”;

cin >> text;

ifstream f (text);

if (!f) {

cout << “Ошибка открытия файла”;

return 1;

}

while (!f.eof ()) {

f.getline (buf,81);

cout << buf << endl;

}

return 0;

}

Для закрытия потока определен метод close (), но поскольку он неявно выполняется деструктором, явный вызов необходим только тогда, когда требуется закрыть поток раньше конца его области видимости.

Задание

Перепишите вашу программу – телефонный справочник с использованием файловых потоков и форматированного ввода-вывода.

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

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

istringstream – входные строковые потоки;

ostringstream – выходные строковые потоки;

stringstream – двунаправленные строковые потоки.

Эти классы определены в заголовочном файле <sstream> и являются производными от классов istream, ostream и iostream соответственно.

Участки памяти, с которыми выполняются операции чтения и извлечения, по стандарту определяются как строки С++ (класс string). Строковый класс будет рассмотрен далее. Строковые потоки создаются и связываются с этими участками памяти с помощью конструкторов:

explicit istringstream (int mode = ios:: in);

explicit istringstream (const string & name, int mode = ios:: in);

explicit ostringstream (int mode = ios:: out);

explicit ostringstream (const string & name, int mode = ios:: out);

explicit stringstream (int mode = ios:: in | ios:: out);

explicit stringstream (const string & name, int mode = ios:: in | ios:: out);

Здесь слово explicit указывает на то, что эти конструкторы вызываются только явным образом.

В строковых потоках описан метод str, возвращаюший копию строки или устанавливающий ее значение:

string str () const;

void str (const string & S);

Пример. Строковый поток используется для формирования сообщения, включающего текущее время и передаваемый в качестве параметра номер:

# include <sstream>

# include <string>

# include <iostream>

# include <ctime>

using namespace std;

string message (int i) {

ostringstream os;

time_t t;

time (&t); // Функция возвращает текущие дату и время в виде time_t

os << “time: “ << ctime (&t) <<”number: ” << i << endl;

return os.str (); // Функция ctime () превращает время

// в строку

}

int main () {

cout << message (22);

return 0;

}


 

Строки

 

С++ не содержит стандартного типа данных “строка”. Вместо этого он поддерживает массивы символов, завершающиеся нуль-символом. Библиотека содержит функции для работы с такими массивами, унаследованные от С и описанные в заголовочном файле <string.h>.

Тип данных (класс) string стандартной библиотеки лишен недостатков, присущих массивам символов. Основные действия со строками выполняются в нем с помощью операций и методов, а длина строки изменяется динамически. Для использования класса необходимо подключать к программе заголовочный файл <string>.



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2016-08-20 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: