Организация ввода и вывода данных

Вывод данных

Потоки. Поток вывода

Поток (stream) — это абстракция, отражающая перемещение данных от источника к приемнику. В большинстве программ требуется получать данные из-вне (например, с клавиатуы), а также отправлять результаты вычислений на стандартное устройство (монитор).
2
Такое движение данных называется стандартным потоком ввода/вывода. Разумеется, среда C++ реализует потоки не сама по себе, а в непосредственном взаимодействии с операционной системой. Реализация потоков в языке C++ выполнена таким образом, что потоки для различных источников и приемников выглядят единообразно.
Для того, чтобы имелась возможность осуществлять ввод и вывод данных в программе необходимо включить в программу библиотеку ввода/вывода. В стандартной библиотеке C++ (STD) библиотека ввода/вывода представлена двумя основными классами: istream и ostream, классы ввода и вывода соответственно. Поскольку в одной программе чаще всего есть и ввод и вывод, существует объединенный класс iostream, который наследует от родительских классов istream и ostream все функции, обеспечивающие работу потоков.
Для начала работы с потоками необходимо включить (в начале программы) заголовочный файл iostream следующей директивой:

#include <iostream>

Далее мы должны объявить использование пространства имен STD, поскольку библиотека ввода/вывода не входит в ядро языка C++, а принадлежит стандартной библиотеке. Это придаст нашей программе более лаконичный характер:

using namespace std;

Инструкция потока вывода начинается соответствующим объявлением cout (читается “си-аут”). cout является объектом класса iostream. Данные отправляют (или добавляются) в поток с помощью операции вставки (вывода) <<. Например:
Программа 8.2.1

#include <iostream>
using namespace std;
int main() {
    cout << "Ничего я не боюсь, если рядом C++!\n";
    cout << "5 + 10 = " << 15 << endl;
    return 0;
}

Строка инструкции потока может быть очень длинной, поэтому, для хорошего восприятия программного кода, эту строку можно (и даже нужно!) оформлять в виде столбца:

cout << "2 x 1 = " << 2 << "\n"
     << "2 x 2 = " << 4 << "\n"
     << "2 x 3 = " << 6 << "\n"
     << "2 x 4 = " << 8 << "\n"
     << "2 x 5 = " << 10 << "\n"
     << "2 x 6 = " << 12 << "\n"
     << "2 x 7 = " << 14 << "\n"
     << "2 x 8 = " << 16 << "\n"
     << "2 x 9 = " << 18 << "\n"
     << "2 x 10 = " << 20 << endl;

Синтаксически вывод на языке C++ действительно напоминает поток. Поток завершает специальная функция (манипулятор) – endl. Эта функция выполняет двоякую роль. Во-первых, она завершает строку (добавляет символ признака конца строки) с переводом на новую. Во-вторых, она освобождает буфер вывода и закрывает поток.

Примечание. Хотя endl и производит переход на новую строку, внутри потока использовать его не рекомендуется (но не запрещено). Для того, чтобы осуществить переход на новую строку лучше использовать специальную управляющую последовательность "\n" (как во фрагменте программы выше) осуществляющую вставку символа перехода на новую строку.

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

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

Заканчивается инструкция потока вывода точкой с запятой.

Форматированный вывод

Очень часто выводу требуется придать некоторый упорядоченный вид. Такой вывод данных называется форматированным выводом. Язык С++ имеет средства форматирования вывода данных. Форматированный вывод обеспечивают специальные функции – манипуляторы. Манипуляторы вставляются (добавляются) в поток, также как и прочие данные – с помощью операции вставки. Список основных манипуляторов вы можете увидеть в методичке (Таблица 15).
Следующий манипулятор с которым мы с вами познакомимся – это setw(). Манипулятор setw – это функция, имеющая аргумент – количество знакомест на вывод объекта вывода. Манипуляторы имеющие параметры собраны в особом классе библиотеки ввода/вывода – iomanip. Необходимо включить этот заголовок в начале программы. Если на вывод символа предать в качестве аргумента функции setw значение 10, то символ сместится вправо на 10 позиций (девять символьных позиций будут содержать пробелы). Объясняется это тем, что выравнивание, по умолчанию, осуществляется вправо.

Примечание. Манипулятор setfill() (заголовок iomanip) устанавливает вместо пробела символ заполнитель, например, точку setfill('.'). Манипулятор left будет выравнивать по левой границе.

В следующей задаче нам нужно вывести на экран треугольник, образованный символами звездочка по образцу:

*
**
***
** **
**  **
**   **
**    **
**     **
**      **
**       **
**        **
*************
**************

При этом, символ пробела использовать запрещено. Решим эту задачу следующим образом:
Программа 8.2.2

//====================================================//
// Форматированный вывод с помощью манипулятора setw  //
//====================================================//
#include <iostream>
#include <iomanip>
using namespace std;

int main() {
	cout << "*\n"
	     << "**\n"
	     << "***\n"
	     << "**" << setw(3) << "**\n"
	     << "**" << setw(4) << "**\n"
	     << "**" << setw(5) << "**\n"
	     << "**" << setw(6) << "**\n"
	     << "**" << setw(7) << "**\n"
	     << "**" << setw(8) << "**\n"
	     << "**" << setw(9) << "**\n"
	     << "*************\n"
	     << "**************"
	     << endl;
}
Примечание. Манипуляторы – не единственный способ форматирования. Существуют также флаги форматирования и некоторые другие функции, о которых мы будем говорить в позднее.

Ввод данных

Для ввода данных используется поток ввода. Поток ввода начинается с определения потокового объекта ввода – cin (читается “си-ин”). По аналогии с потоком вывода, поток ввода использует операцию извлечения >> (или ввода) для чтения данных в поток со стандартного устройства (клавиатуры).
Переменные, входящие в поток должны быть определены в программе раньше.

int var_A;
cin >> var_A;

1
Можно вводить значения нескольких переменных за раз. Значения переменных определенных ранее будут заменены на новые. Пример ввода нескольких переменных:

int a = 10, b, c;
cin >> a >> b >> c;

В окне терминала ввод переменных осуществляется либо записью данных в строку с разделителем пробел и последующим нажатием клавиши Enter, либо нажатием клавиши Enter после каждого, набранного с клавиатуры, значения данных.
В потоке cin можно вводить значения переменных разного типа. В этом случае нужно следить за тем, чтобы вводимые значения переменных соответствовали требованиям предъявляемым к литералам данных типов.

Арифметические типы данных

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

Целый тип

Этот тип данных представлен типами: short, int, long long. По умолчанию используется тип int. Каждый из этих типов представлен в двух версиях: знаковой и беззнаковой. Знаковые типы (signed) могут принимать как положительные, так и отрицательные значения. Беззнаковые (unsigned) – только положительные значения и 0. Диапазон допустимых значений называется шириной типа. Ширина определяется количеством байт выделяемых для хранения значения данного типа. Ширина типа int – 4 байта. Это – знаковый тип, следовательно его диапазон изменяемых значений:

Size                   MIN                   MAX
 4                 -2147483648            2147483647
Действительный тип

Действительные (вещественные) типы призваны работать с любыми числами. Действительные типы или типы с плавающей точкой представлены типами одинарной, двойной и расширенной точности: float, double и long double. По умолчанию используется тип double.
Вещественное число представлено в памяти в виде двух частей: мантиссы и порядка. Мантисса – это число >= 1, но < 2, поэтому старшая цифра мантиссы, равная 1, никогда не хранится. Например, для хранения числа типа float выделяется 32 бита, из них: 1 разряд выделяется для хранения знака мантиссы, 8 разрядов для хранения порядка числа и 23 разряда для хранения мантиссы. Ширина типа double – 8 байт. Диапазон значений этого типа:

Size                      MIN                       MAX
  8    2.225073858507201e-308    1.797693134862316e+308

Обратите внимание, что размеры мантиссы действительных типов значительно меньше порядка (для double – 15). Следовательно, при выполнении арифметических операций с этими типами будет накапливаться неточность в вычислениях.

Создание дружественного интерфейса

Данные не должны вводиться “вслепую”, т. е. для ввода тех или иных данных необходимо приглашение. Такие приглашения называются диалогами с пользователем или дружественными интерфейсами. Для создания диалогов потоки ввода/вывода используются совместно. Приведем пример. Создадим программу приветствия, опрашивающую пользователя и выводящую полученную информацию.
Программа 8.2.3

//====================================================//
// Организация диалога с пользователем                //
//====================================================//
#include <iostream>
#include <string>
using namespace std;

int main() {
	int Y;
	string S;
	cout << "Как тебя зовут?\n";
	cin >> S;
	cout << "Сколько тебе лет?\n";
	cin >> Y;
	cout << "Здравствуй, " << S
	     << "! Тебе всего " << Y
	     << " лет." << endl;
	return 0;
}

Обратите внимание, что поток вывода, например, в стр. 11 не завершается endl. Дело в том, что последующий поток ввода автоматически завершает предыдущий поток с установкой признака завершения строки.
Приведем пример программы в которой не используются диалоги. Эта программа вычисляет длину и площадь окружности.
Программа 8.2.4.1

#include <iostream>
using namespace std;

int main() {
	const double pi = 3.1415926535;
	double r;
	cin >> r;
	double l = 2 * pi * r;
	double s = pi * r * r;
	cout << l << endl;
	cout << s << endl;
	return 0;
}

Вот как выглядит консольный ввод и вывод этой программы:

5
31.4159
78.5398

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

#include <iostream>
using namespace std;

int main() {
	const double pi = 3.1415926535;
	double r;
	cout << "r = ";
	cin >> r;
	cout << "l = "   << 2 * pi * r
		 << "\ns = " << pi * r * r
		 << endl;
	return 0;
}

В программе 8.2.4.1 нет большой необходимости использовать переменные l и s, поэтому в программе ниже вычисления перенесены в поток вывода. Это не только возможно, но и нужно сделать, если программу требуется оформить в более компактной форме. Теперь ввод и вывод с помощью диалогов выглядит так:

r = 5
l = 31.4159
s = 78.5398

Вопросы и задания

  1. Составить программу, которая выводит в консольном окне ваше имя, образованное символом “*”. Символ пробела использовать запрещено!
Print Friendly, PDF & Email

Comments are closed.