§ 8.2. Операции. Выражение. Инструкция. Ввод и вывод данных. Форматированный вывод

Школьный курс python
Содержание

Выражение. Операнды. Операция. Инструкция

Выражение

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

0
-12.4
(x + 5) / 2
cout << ++num
c == 2 && (c < 5 || d > sqrt(3 * a))

Выражения с присваиванием (операция “=“) очень похоже на математическое выражение. Но это не одно и тоже! Например, выражение:

a = a + 1

в математике не имеет смысла, так как сопоставляется левая и правая часть уравнения, а оно решения не имеет. Но выражение на языке программирования осмысленно и корректно, так как изображает вычислительный процесс и изменение состояния памяти. Слева от “=” – так называемое lvalue-значение и оно связано с адресом в памяти, а справа – выражение, которое вычисляет значение операнда операции присваивания и оно не ссылается на область в памяти. Выражение:

a + 1 = a

приведет к ошибке.

Операнды

Операнд (англ. – operand) ― это аргумент операции. В выражении один или несколько операндов связаны (по аналогии с математическим способом записи) операциями. В простейшем случае операнд может быть литералом, константой или переменной. В более общем случае – это выражение (в котором тоже свои операнды). В одно выражение могут входить операнды разных числовых типов. Преобразования типов мы рассмотрим позднее.
9

Операции

Операции (англ. – operator) – выполняют определенные действия над операндами. Полный список операций смотрите в методичке (Таблица 4). В соответствии с количеством операндов операции делятся на унарные (один операнд), бинарные (два операнда) и, единственную, тернарную (в которой три операнда). Операция вызова функции может содержать неограниченное количество операндов. Фактически, операция — это та же функция, но записываемая особым образом. В C++ имеется возможность определять операции для произвольных типов как функции (методы) — чтобы можно было работать с ними точно так же, как и с фундаментальными типами. Эта возможность называется «перегрузка операций». Операции имеют приоритет и ассоциативность.
Приоритет (англ. – precedence) определяет старшинство операции. Несколько операций могут иметь равный приоритет. В этом случае включается порядок вычисления – ассоциативность (англ. – associativity). Ассоциативность может быть либо слева-направо, либо справа-налево. Приоритет и ассоциативность определяют направление вычислительного процесса. Например:

2 + 4 * 6 / 3 
// результат 10, а не 12!
10 - 5 - 2
// результат 3, а не 7!

Первое выражение будет равносильно: (2 + ((4 * 6) / 3))
Второе выражение будет равносильно: ((10 - 5) - 2)
Для изменения порядка вычисления используются круглые скобки ().

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

Инструкция (англ. – statement) – представляет собой законченное предложение на языке C++. Инструкция указывает компьютеру выполнить некоторые действия. Чаще всего используется инструкция выражение (expression statement). Такая инструкция всегда завершается точкой с запятой;, даже если она находится в конце блока (см. ниже). Инструкции делятся на неисполняемые (например, для описания данных) и исполняемые (например, присваивание, ввод, вывод). Иногда, требуется использовать пустую инструкцию, состоящую из одиночной ";". Такая ситуация возникает, например, в циклах, когда все выражения заключены в заголовке цикла.

int a;
a = a + 1;
a++;

Вывод данных

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

#include <iostream>

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

using namespace std;

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

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

Потоки поддерживают не только вывод констант, но и вычисления:

cout << "5 + 10 = ";
cout << 5 + 10 << endl;

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

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;

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

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

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

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

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

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

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

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

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

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

Программа 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;
}
Примечание. Манипуляторы - не единственный способ форматирования. Существуют также флаги форматирования и некоторые другие функции, о которых мы будем говорить позднее.

К сожалению, среди манипуляторов нет функции центрирования вывода. Здесь нужно применить хитрость. Вычисляем длину самой длинной строки в символах и делим значение пополам. Отсюда будем определять величину смещения для каждой строки.
Задача 2. Составьте программу выводящую на экран звездочки в форме треугольника по образцу:

      *      
     ***     
    *****    
   *******   
  *********  
 *********** 
*************
Программа 8.2.3
#include <iostream>
#include <iomanip>
using namespace std;

int main() {
	int N = 13 / 2 + 1; // центр самой длинной строки
	cout << setw(++N) << "*\n" // увеличиваем N на 1
		 << setw(++N) << "***\n"
		 << setw(++N) << "*****\n"
		 << setw(++N) << "*******\n"
		 << setw(++N) << "*********\n"
		 << setw(++N) << "***********\n"
		 << "*************" << endl;
	return 0;
}

Для вычисления значения смещения нам потребуется целочисленная переменная N, использование которой мы объявили в 6 строке. Операция ++N называется операцией префиксного инкремента. Она увеличивает значение аргумента на единицу. Вычисления будут производиться слева направо, поэтому значение N будет возрастать на единицу по мере продвижения к концу потока.

Форматированный вывод в C++ выглядит довольно громоздко и неуклюже. В стандарт C++20 вошли новые возможности форматированного вывода (аналогичные языку python), но в компиляторах эти возможности не реализованы в полной мере.

Ввод данных

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

int var_A;
cin >> var_A;

1
Можно вводить значения нескольких переменных за раз. Если переменная уже имела какое-то значение (например, как в коде ниже, переменная a инициализируется значением 10), то это значение будет заменено на новое. Пример ввода нескольких переменных:

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

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

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

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

Целый тип

Этот тип данных представлен типами: 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). Следовательно, при выполнении арифметических операций с этими типами будет накапливаться неточность в вычислениях.
Подробнее об этих и других типах мы будем говорить на последующих уроках.

Организация диалога (создание дружественного интерфейса)

Работа программы всегда должна быть интуитивно понятна пользователю этой программы. Т. е. пользователь должен знать, какие действия по вводу данных он должен выполнять в данный момент (или же получать внятный вывод в конце работы программы). Такое устройство программы называется “дружественным интерфейсом”. Это обеспечивается выводом подсказок (текста сопровождения) на экран во время её работы.
Задача 3. Создадим программу, которая опрашивает пользователя, а затем выводит введенные ранее данные на экран.

Программа 8.2.4
//====================================================//
// Организация диалога с пользователем                //
//====================================================//
#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;
}

Ввод/вывод программы в окне Konsole

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

Программа 8.2.5.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.5.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.5.1 нет большой необходимости использовать переменные l и s, поэтому в программе ниже вычисления перенесены в поток вывода. Это не только возможно, но и нужно сделать, если программу требуется оформить в более компактной форме. Теперь ввод и вывод с помощью диалогов выглядит так:

r = 5
l = 31.4159
s = 78.5398

Если в течение работы программы величины какого-либо типа не изменяются, то используются не переменные, а константы. Объявление переменных и констант отличается тем, что перед спецификатором типа константы дополнительно указывается квалификатор const.

Приложение

Примеры решения задач
Вопросы
Темы сообщений
Задания А
  1. Составить программу, которая выводит в консольном окне ваше имя, образованное символом “*”. Символ пробела использовать запрещено!
Задания Б
Задания С
Ссылки
1 Звезда2 Звезды3 Звезды4 Звезды5 Звезд (1 оценок, среднее: 5,00 из 5)
Загрузка...

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.


Обсуждение закрыто.