Урок #2

Базовые типы данных, константы, литералы и арифметические операторы

Типы данных

На прошлом уроке мы изучили тип int, диапазон которого от -2 147 483 648 до 2 147 483 647. Но что делать, если типа данных не хватает? Например, надо вычислить результат сложения двух чисел с 15-ю разрядами. Эти числа не поместятся в базовый тип int. Для этого существует более большой (более длинный) тип long long, диапазон которого уже от -9 223 372 036 854 775 808 до 9 223 372 036 854 775 807. Но что делать, если число превышает это огромное значение всего лишь на одну тысячу! Не волнуйтесь, Вам не придется много чего писать, можно написать перед нашим типом данных слово unsigned, что означает «беззнаковый». Тогда диапазон значений сразу стает от 0 до удвоенного количества верхней границы типа без слова unsigned.

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

-1981284352
-8446744073709551616
10000000000000000000
Для продолжения нажмите любую клавишу…

Как мы видим, в первых двух случаях значения как бы «перескочили» через максимально возможный элемент и перешли к минимально возможному. Это можно сравнить с числовой линией, на которой расположены все возможные числа из диапазона типа. Давайте представим, что существует стандартный тип supershort (такой тип мы обязательно потом научимся создавать), диапазон которого от -10 до 9. Распределим все значения от -10 до 9 на числовой линии, а потом соединим концы отрезка нашего диапазона. Получится, что следующие число после 9 – это -10, а не 10, ведь числа 10 у нас нету в диапазоне. Если брать числа 11, 12 и 13, мы получим числа -9, -8 и -7 соответственно. Именно по этому принципу построены все стандартные типы данных в C++.

Так же в этом примере я использовал несколько интересных вещей. Давайте взглянем на имена переменных. Перед именем каждой переменной стоят буквы i, ll и ull. Легко догадаться, что это сокращение от имен типов этих переменных. Это делается для того, что бы указать какой тип у переменной. Это используют очень редко. Но в некоторых случаях это необходимо. Я написал эти сокращения только ради примера и больше не буду их употреблять в кодах программ. Использовать сокращения или нет – это полностью Ваше решение.

Так же вам, скорее всего, приглянулась конструкция i_first = ll_second = ull_third. Удивительно, но все переменные присвоят значение выражения или переменной, которая стоит справа после последнего оператора присвоения. Но почему эта команда работает именно так? Ответ кроется в ее реализации. Дело в том, что все операции присвоения выполняются справа налево.

Действительные типы данных

Помимо целочисленных типов в C++ есть так же и действительные, то есть дробные. Всего действительных типов данных два: float и double. double имеет в два раза больше диапазон значений, чем float, поэтому чаще всего используют именно его. Так же есть еще одно представление дробного числа — long float, что является некой копией double и ничем не отличается от него. Давайте рассмотрим программу, которая выводит произведение введенных двух чисел.

1.17
26.123
30.5639
Для продолжения нажмите любую клавишу…

Забавный факт: если число типа double или float будет равно числу очень приближенным к единице, то это число при выводе станет единицей. Если же приравнять это число любому целочисленному типу, то оно станет равно 0. Попробуйте запустить эту программу:

1 0
Для продолжения нажмите любую клавишу…

Константы и литералы

Бывают программы, в которых необходимо использовать какое-то число несколько раз и не может, как в реальном мире, так и в программе измениться. Это число пи, всяческие физические константы, число дней в январе и иные подобные числа. То есть константа – это ячейка памяти, где записано какое-то значение, которое не может изменяться в программе. Объявление константы довольно простое.

31 30
Для продолжения нажмите любую клавишу…

Как мы видим, достаточно написать в объявление константы слово const. Не имеет значения где будет стоять это слово. После типа константы, или перед – компилятору все равно, но я рекомендую писать именно const int, потому что так будет легче найти константы в программе.

К стати, так же как и константам, обычным переменным можно присваивать начальные значения сразу в объявлении переменной. Например, конструкция int a = 1 ошибочной не является.

Литералы – это любые символы либо строки не в переменной. Мы их использовали в программе что бы ставить пробелы между числами при выводе в консоль. " " – это символьный литерал. Обычно символы берутся в одинарные кавычки ' ', а строки, то есть последовательность символов – в двойные " ". Но почему, когда мы ставили пробел, то использовали двойные кавычки? Это делается для того, чтобы не запутаться в строках, когда мы захотим добавить какие-то слова перед или после него. Допустим, мы хотим красиво оформить программу, которую мы только что писали, сделав в выводе в консоль название месяцев.

In January are 31 days. In April are 30 days.
Для продолжения нажмите любую клавишу…

Здесь литералами служили "In January are ", " days. In April are", " days.".

Арифметические операторы

На прошлом уроке мы изучали сложение, умножение и вычитание двух чисел. Эти операции являются бинарными, то есть используются только с двумя переменными, или значениями. Теперь надо частично рассмотреть деление. Все что мы сейчас можем найти – это целую часть от деления одного числа на второе. Оператор деления / «отрубляет» дробную часть от ответа. Давайте рассмотрим результат выполнения этой программы:

2
Для продолжения нажмите любую клавишу…

В ответе должно было получится 3, ведь 2.5 округляется в большую сторону, но программа выведет 2, потому что, как я уже писал, дробная часть в буквальном смысле исчезает. Попробуйте сами поделить числа 7 и 3, 100 и 7.

С числами типа float и double все намного легче: они имеют привычный для нас вид, то есть состоят из целой и дробной части. Это значит, что, записав результат деления числа 5 на 2 в переменную действительного типа, мы получим вполне приличный ответ — 2.5. Если же решение имеет довольно низкую степень, порядка 10^(-5), то ответ будет выводиться в таком виде: 1e-05, что означает “1 в степени -5”.

Но что же делать, если мы не хотим, что бы пропадала информация о делении числа 5 на 2. Для этого надо как-то вычислить остаток при делении. Конечно, можно было его вычислить и так: r (то есть остаток) = 5 – (5 / 2) * 2. Но это достаточно большое выражение, поэтому для облегчения работы с языком, был придуман оператор остатка %. Он так же является бинарным.

5 = 2 * 2 + 1 Для продолжения нажмите любую клавишу…

Унарные операторы

Кроме бинарных (+, -, *, / и %) существуют так же унарные, которые требуют наличие только одной переменной. Это инкремент, другими словами – увеличение числа на единицу, и декремент, или уменьшение числа не единицу. Оператор инкремента ++ и декремента -- являются визитной карточкой языка C++. Даже в названии это используется.

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

1 2 2 3
Для продолжения нажмите любую клавишу…

Из результата видно, что во время первого увеличения переменной на один, когда оператор инкремента стоял перед переменной, то сначала значение инкремента увеличилось на один, а после этого только вывелся результат. Во втором же случае все наоборот.

Выражение и подробнее о присвоении

Узнав о почти всех арифметических и унарных операторах, нам следует узнать, что такое выражение. Выражение – последовательность констант, литералов, функций, которые возвращают значение, обычных переменных и всевозможных арифметических операторов. Выражение должно возвращать значение. Например, выражение 2 + 3 возвращает 5, а 2 * 2 + 2 возвращает 6. Отлично, мы разобрались с определением выражения и выяснили, что оно возвращает значение. Но куда именно? На самом деле мест, где могут располагаться выражения, довольно много. Но сейчас мы начнем с самого простого. Мы уже знаем, что делает оператор присвоения. Он «сует то, что справа в то, что слева». Это в действительности так и есть. Но данное определение не очень грамотное, поэтому перефразируем его с использованием нового слова – выражение. Оператор присвоения вычисляет значение выражения и записывает его значение в переменную. Странно, но этот оператор тоже возвращает значение. То есть можно писать так (как было замечено ранее): a = b = 5. Данная конструкция будет выполняться справа на лево. Сначала в переменную b запишется значение выражения, то есть 5, а затем переменная a приобретет значение b, что так же равно 5.

Возможные вопросы по теме:

«А можно писать ++num++?» — нельзя, это приведет к ошибке, так же как и num++++. Поэтому лучше писать num = num + 2, или num += 2. Эта конструкция += прибавляет к переменной num значение выражения справа от нее. В нашем случае, это 2. Так же можно делать такие операции:

Выражение Эквивалент
num += 2 num = num + 2
num -= 2 num = num — 2
num *= 2 num = num * 2
num /= 2 num = num / 2
num %= 2 num = num % 2

«Чувак, мне надоело каждый раз писать std::! Как от этого избавиться?» — все очень просто. У нас пока было очень мало вызовов функций из пространства имен std, поэтому мы писали перед каждой функцией имя пространства имен. Для того что бы подключить сразу все функции из пространства имен std, нам надо сразу после подключения библиотек написать using namespace std.

Добавляйте свои вопросы в комментарии. Лучшие попадут в статью 🙂


Урок #1 Урок #3