§5 Библиотека ввода/вывода. Манипуляторы. Флаги форматирования

Потоки

В языке C++ нет встроенной поддержки ввода/вывода, вместо этого используется библиотека функций IOStream. Эта библиотека содержит различные классы, определяющие потоки ввода/вывода. Класс, наряду с объектом, является ключевым понятием объектно-ориентированного программирования. Объект находится в таком же отношении к своему классу, в каком переменная находится по отношению к своему типу. Старшим классом в иерархии является класс ios. Он содержит функции ввода/вывода общие для всех остальных, производных, классов, а также указатель на класс streambuf, значением которого является адрес буфера памяти.
Буфер – это блок памяти, используемый в качестве временного хранилища данных. Буферизация позволяет считывать информацию с устройства большими блоками с размещением в буфере, а затем, самой программе, считывать и записывать информацию в буфер посимвольно.
3
Поток (stream) – это абстракция, отражающая перемещение данных от источника к приемнику. Реализация потоков в языке C++ выполнена таким образом, что потоки для различных источников и приемников выглядят единообразно.

  • Ввод интерпретируется как чтение данных в поток (с клавиатуры).
  • Эти потоки определяет класс istream (input stream).

  • Вывод интерпретируется как запись данных из потока (на дисплей).
  • Эти потоки определяет класс ostream (output stream).

Наследником классов istream и ostream является класс iostream, следовательно им наследуются и объекты чтения и объекты записи. Для потоков ввода/вывода в библиотеке IOStream определены глобальные объекты чтения и записи:

  • объект cin читает данные со стандартного устройства ввода (клавиатура);
  • объект cout записывает данные на стандартное устройство вывода (монитор).

Для того, чтобы потоковые объекты стали доступными в программе необходимо использовать директиву компилятора include с именем заголовочного файла, заключенного в угловые скобки <>:
#include <iostream>
Имена объектов принадлежат пространству имен стандартной библиотеки. Для более лаконичного обращения к глобальным объектам необходимо сделать объявление с помощью следующей инструкции using:
using namespace std;

Потоковые операции

  • Для вывода данных используется операция вывода или операция вставкиoperator<<
  • Для ввода данных используется операция ввода или операция извлечения - operator>>
  • В программе и на схеме это выглядит следующим образом:

    cin >> var_A;
    

    1

    cout << "Ничего я не боюсь, если рядом - С++!" << endl;
    

    2

Здесь var_A - это переменная, именованная область памяти компьютера.
Особенностью использования этих операций в том, что они позволяют добавлять в поток данные - "цепочкой" (как в примере, выше, добавляется манипулятор endl), по очередности, так как операции << и >> обладают ассоциативностью слева-направо.
Пример, как это можно реализовать, в программе:

Программа 5.1

//============================================================================
// Name        : lesson-5-1.cpp
//============================================================================

#include <iostream>
using namespace std;

int main() {
    int a, b, c;
    cin >> a >> b >> c;
    cout << "Первое число "
         << a
         << "\nВторое число "
         << b
         << "\nТретье число "
         << c
         << "\na + b + c = "
         << a + b + c
         << "\na * b * c = "
         << a * b * c
         << endl;
    return 0;
}
2 3 4
Первое число 2
Второе число 3
Третье число 4
a + b + c = 9
a * b * c = 24

В случае, если инструкция потока, оформленная в виде сцепления нескольких операций >> или <<, окажется слишком длинной, то инструкцию потока можно представить в виде столбца. Такой подход делает программный код более читабельным.

Функции неформатированного ввода/вывода

Классы istream и ostream включают ряд методов, которые в совокупности называются функциями неформатированного ввода/вывода. Некоторые из них представлены в таблице ниже. Эти функции названы так потому, что они производят считывание или запись символьных данных без каких-либо преобразований, не пропуская при этом пробельные символы.

istream ostream
get() - извлекает символ put() - записывает символ
peek() - читает символ без извлечения
unget() - возврат извлеченного ранее символа в поток
putback() - вставка символа в поток
getline() - извлекает символы, пока не будет найден заданный символ
ignore() - удаляет из потока определенное количество символов пока не будет встречен символ разделитель, который также отбрасывается
read() - извлекает из потока блоки символов в целевой массив write() - вставляет блоки символов в поток
gcount() - количество извлеченных из потока символов. Все выше перечисленные функции будут воздействовать на gcount, включая >> (операцию извлечения)

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

ch = cin.peek();
cin.read(s, 100);
cin.ignore(255, '\n');
cout.put(line);
cout.write(str1, 50);

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

В программе 5.1 в потоке вывода используется манипулятор endl. Этот манипулятор вставляет в буфер вывода символ новой строки и выгружает содержимое буфера на стандартное устройство.
Манипуляторы - вспомогательные функции управляющие форматированием потоков ввода/вывода. Помимо endl, еще несколько манипуляторов доступны в заголовке iostream:

  • scientific  Экспоненциальная форма вывода вещественных чисел
  • fixed       Фиксированная форма вывода вещественных чисел
  • dec         Перевод в десятичную систему счисления
  • oct         Перевод в восьмеричную систему счисления
  • hex         Перевод в шестнадцатеричную систему счисления
  • ends        Вставка символа конца строки
  • showbase    Выводить индикатор основания систем счисления
  • left        Выравнивать по левому краю поля
  • boolalpha   Вывод логических величин в тестовом виде
  • uppercase   Выводить в числах прописные буквы
  • showpos     Выводить знак + для положительных чисел
Программа 5.2

//============================================================================
// Name        : lesson-5-2.cpp
//============================================================================

#include <iostream>
using namespace std;

int main() {
	int a = 15;
	cout << "a_10 = " << a << endl;
	cout << oct << "a__8 = " << a << endl;
	cout << hex << "a_16 = " << a << endl;
	return 0;
}
a_10 = 15
a__8 = 17
a_16 = f

Следующие манипуляторы имеют параметры:

  • setw()         Устанавливает ширину поля вывода
  • setfill()      Устанавливает символ заполнения (по умолчанию, пробел)
  • setprecision() Число выводимых знаков дробной части

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

Программа 5.3

//============================================================================
// Name        : lesson-5-3.cpp
//============================================================================
#include <iostream>
#include <iomanip>
using namespace std;

int main() {
    int a = 10;
    float b = 10.0 / 2.3;
    cout << a << endl;
    cout << setw(12) << a << endl;
    cout << scientific << b << endl;
    cout << "b = " << fixed << b << endl;
    cout << setw(12) << setprecision(2) << b << endl;
    cout << setw(12) << setfill('.') << b << endl;
    return 0;
}
10
          10
4.347826e+00
b = 4.347826
        4.35
........4.35

В программах рассмотрены примеры, когда манипуляторы используются в потоках вывода. Однако манипуляторы можно применять и в потоках ввода. Пример использования манипулятора setw для контроля количества вводимых символов:
Программа 5.4

//============================================================================
// Name        : lesson-5-4.cpp
//============================================================================
#include <iostream>
#include <iomanip>
using namespace std;

int main() {
	const int buf = 10;
	char c[buf];
	// будет прочитано 9 символов + '\0'
	cin >> setw(buf) >> c;
	cout << c << endl;
	return 0;
}
qwertyuiopasdfghjkl
qwertyuio

Функции и флаги форматирования

Для управления вводом/выводом, помимо манипуляторов, доступны флаги форматирования (как аргументы) и форматирующие функции. Эти функции вызываются как методы базового класса (ios) dot-нотацией. Например: cout.width(10).
Некоторые функции класса ios:

  • fill(ch)      Устанавливает символ заполнения
  • precision(p)  Устанавливает точность
  • width(w)      Устанавливает ширину поля
  • setf(flags)   Устанавливает флаг форматирования
  • unsetf(flags) Сбрасывает указанный флаг форматирования

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

cout.setf(ios::flag);
cout.setf(ios::flag1 | ios::flag2 | ios::flag3);

Для выключения:

cout.unsetf(ios::flag)

Здесь flag, flag1, flag2... подключаемые или отключаемые флаги. Имена флагов, в большинстве своем, совпадают с именами манипуляторов. В программе можно одновременно использовать и манипуляторы, и флаги форматирования и функции-члены.
Функция setf может иметь два аргумента. В таком случае, первый аргумент - устанавливаемый флаг, а второй - маска для сброса действующего флага:

  • basefield   для dec, oct и hex
  • adjustfield для left, right и internal
  • floatfield  для scientific и fixed

Например: cout.setf(ios::scientific, ios::floatfield);

Программа 5.5

//============================================================================
// Name        : lesson-5-5.cpp
//============================================================================
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;

int main() {
    cout.setf(ios::fixed | ios::showpos);
    cout.fill('.');
    cout.precision(3);
    for (int i = 4; i < 20; i++) {
    	cout << i * sqrt(7);
    	cout.width(15);
    	cout << i * sqrt(5) << endl;
    }
    return 0;
}
+10.583.........+8.944
+13.229........+11.180
+15.875........+13.416
+18.520........+15.652
+21.166........+17.889
+23.812........+20.125
+26.458........+22.361
+29.103........+24.597
+31.749........+26.833
+34.395........+29.069
+37.041........+31.305
+39.686........+33.541
+42.332........+35.777
+44.978........+38.013
+47.624........+40.249
+50.269........+42.485

С полным списком манипуляторов и флагов форматирования вы можете познакомиться в методичке (Табл. 12 и 13).

Домашняя работа
  1. Составить программу выводящую на дисплей следующий рисунок:
         *
         *
         *
        * *
       *   *
      *  *  *
      * * * *
      *  *  *
      *     *
      *     *
      *     *
     **  *  **
    * *  *  * *
    * *  *  * *
    ***  *  ***
      *******
         *
        * *
        ***
    

    Непечатаемые символы (табуляция , пробел) использовать нельзя!

  2. Составьте программу печатающую таблицу зависимости значения величины гипотенузы от значений данных катетов по теореме Пифагора в следующем формате:
    -------------------------
    | N | A  | B   | C      |
    -------------------------
    | 1 | 10 |  15 | 18.028 |
    | 2 | 20 |  30 | 36.056 |
    | 3 | 30 |  45 | 54.083 |
    | 4 | 40 |  60 | 72.111 |
    | 5 | 50 |  75 | 90.139 |
    | 6 | 60 |  90 | 108.17 |
    | 7 | 70 | 105 | 126.19 |
    | 8 | 80 | 120 | 144.22 |
    | 9 | 90 | 135 | 162.25 |
    -------------------------
    

    Для больших значений N используйте цикл!

  3. Составьте таблицу соответствия чисел в различных системах счисления: десятичной, восьмеричной и шестнадцатеричной.
Учебник

§55

Литература
  1. Лафоре Р. Объектно-ориентированное программирование в C++ (4-е изд.). Питер: 2004
  2. Прата, Стивен. Язык программирования C++. Лекции и упражнения, 6-е изд.: Пер. с англ. — М.: ООО «И.Д. Вильяме», 2012
  3. Липпман Б. Стенли, Жози Лажойе, Барбара Э. Му. Язык программирования С++. Базовый курс. Изд. 5-е. М: ООО "И. Д. Вильямс", 2014
  4. Павловская Т. А. C/C++. Программирование на языке высокого уровня. - СПб.: Питер, 2003.


Print Friendly, PDF & Email

Добавить комментарий