- •1.4. Оператор присваивания
- •1.5. Системы счисления
- •1.6. Арифметические операции
- •1.8. Директивы препроцессора
- •1.9. Функции ввода/вывода printf() и scanf()
- •2.2.1. Оператор цикла while
- •2.2.2. Оператор цикла for
- •.2.3. Оператор цикла do while
- •2.3. Функции
- •2.4. Область видимости переменных
- •3.1. Массивы
- •3.2. Работа со строками
- •3.3. Обработка элементов массива
- •3.4. Структуры
- •3.5. Битовые поля
- •3.7. Перечисляемые типы
- •3.8. Типы, определяемые пользователем
- •4.1. Указатели
- •4.2. Функции malloc() и free(). Ссылки
- •4.3. Стек
- •4.4. Связные списки
- •4.5. Бинарные деревья
- •5.1. Работа с текстовыми файлами
- •5.2. Работа с бинарными файлами
- •5.3. Пример программирования. Простой словарь
- •Глава 6. Основы объектно-ориентированного программирования
- •6.2. Наследование
- •6.3. Дружественные классы и функции
- •6.4. Виртуальные функции
- •6.5. Перегрузка операторов
- •Создание простой программы
- •Компиляция вашей программы
- •Создание второй программы
- •Изучение синтаксических ошибок
- •International syntax.Cpp:
- •Работа в среде типа windows
- •Что вам необходимо знать
1.6. Арифметические операции
В языке С++ довольно просто реализуются элементарные математические операции: сложения, вычитания, умножения и деления. Допустим, что в программе заданы две переменные
int a, b;
с начальными значениями
a=4; b=8;
тогда операции сложения, вычитания, умножения и деления будут выглядеть следующим образом:
int c; c = a+b; //сложение двух переменных с = a-b; //вычитание c = a*b; //умножение c = a/b; //деление
Представленные операции можно выполнять не только с переменными, но и с конкретными числами, например
c = 10+5; c = 8*4; float d; d = 7/2;
Результатом первых двух арифметических операций будут числа 15 и 32 соответственно, но при выполнении операции деления в переменную d будет записано число 3, а не 3,5. Это связано с тем, что число 7 в языке С++ будет интерпретироваться как целочисленная величина, которая не может содержать дробной части. Поэтому полученная дробная часть 0,5 будет отброшена. Для реализации корректного деления одного числа на другое следует использовать такую запись:
d = 7.0/2;
или
d = (float )7/2;
В первом случае вещественное число делится на два и результат (вещественный) присваивается вещественной переменной d. Во втором варианте выполняется приведение типов: целое число 7 приводится к вещественному типу float, а затем делится на 2. Второй вариант удобен, когда выполняется деление одной целочисленной переменной на другую:
int a,b; a = 7; b = 2; d = a/b;
В результате значение d будет равно 3, но если записать
d = (float )a/b;
то получим значение 3,5. Здесь следует также отметить, что если переменная d является целочисленной, то результат деления всегда будет записан с отброшенной дробной частью. Аналогичные правила справедливы для всех арифметических операций.
В заключении рассмотрения работы с арифметическими операциями отметим, что приоритет операций умножения и деления выше приоритета операций сложения и вычитания. Это означает, что сначала выполняются операции умножения и деления и только затем операции сложения и вычитания. Следующий пример демонстрирует приоритет арифметических операций:
double n=2, SCALE = 1.2; double arg = 25.0 + 60.0*n/SCALE;
В приведенном примере сначала будет выполнена операция умножения, затем деления и, наконец, сложения. То есть порядок вычисления соответствует математическим правилам. Для того чтобы изменить порядок вычисления (поменять приоритеты) используются круглые скобки как показано ниже
double arg = (25.0 + 60.0)*n/SCALE;
Здесь сначала выполняется операция сложения и только затем операции умножения и деления.
Кроме рассмотренных арифметических операций в С++ имеется полезная операция деления по модулю. Ее результатом является остаток от деления одного целого числа на другое. Так выражение
int a = 13 % 5;
означает, что число 13 делится по модулю 5. Учитывая, что число 5 дважды входит в число 13, то остаток получается равный 3. Эту операцию можно реализовать и на основе стандартных арифметических операций следующим образом:
int a = 13 – 13/5*5;
Следует отметить, что операция целочисленного деления % может быть реализована только для целых чисел и целочисленных переменных и не применима к другим типам данных.
Для простоты программирования в языке С++ реализованы компактные операторы инкремента и декремента, т.е. увеличения и уменьшения значения переменной на 1 соответственно. Данные операторы могут быть записаны в виде
i++; // операция инкремента ++i; // операция инкремента i--; // операция декремента --i; // операция декремента
Разницу между первой и второй формами записи данных операторов можно продемонстрировать на следующем примере:
int i=10,j=10; int a = i++; //значение a = 10; i = 11; int b = ++j; //значение b = 11; j = 11;
Из полученных результатов видно, что если оператор инкремента стоит после имени переменной, то сначала выполняется операция присваивания и только затем операция инкремента. Во втором случае наоборот, операция инкремента реализуется до присвоения результата другой переменной. Поэтому значение a = 10, а значение b = 11. В первом случае говорят о постпрефиксной форме, а во втором – о префиксной. Подобный приоритет операции инкремента остается справедливым и при использовании арифметических операций, например
int a1=4, a2=4; double b = 2.4*++a1; //результат b = 12.0 double c = 2.4*a2++; //результат c = 9.6
Из приведенного примера видно, что операция инкремента (декремента) обладает более высоким приоритетом, чем операция умножения (соответственно и деления). Для того чтобы изменить приоритеты используются круглые скобки.
Операция декремента действует аналогично операции инкремента с той лишь разницей, что она уменьшает значение переменной на 1.
1.7. Поразрядные операции языка С++
Поразрядные операции состоят из четырех основных операций: отрицание, логическое И, логическое ИЛИ и исключающее ИЛИ. Рассмотрим данные операции по порядку.
При выполнении операции поразрядного отрицания все биты, равные 1, устанавливаются равными 0, а все биты равные нулю, устанавливаются равными 1. Для выполнения данной операции в языке С++ используется символ ‘~’ как показано в следующем примере:
unsigned char var = 153; //двоичная запись 10011001 unsigned char not = ~var; //результат 01100110 (число 102)
В результате переменная not будет содержать число 102. В ходе выполнения операции поразрядного И результирующий бит будет равен 1, если оба бита в соответствующих операндах равны 1, т.е.
10010011 & 00111101 даст результат 00010001.
Для выполнения операции логического И используется символ & следующим образом:
unsigned char var = 153; //двоичная запись 10011001 unsigned char mask = 0x11; // число 00010001 (число 17) unsigned char res = var & mask; // результат 00010001
или
var &= mask; // то же самое, что и var = var & mask;
В ходе выполнения двоичной операции ИЛИ результирующий бит устанавливается равным 1, если хотя бы один бит соответствующих операндов равен 1. В противном случае, результирующее значение равно 0. Для выполнения данной логической операции используется символ ‘|’ как показано ниже:
unsigned char var = 153; //двоичная запись 10011001 unsigned char mask = 0x11; // число 00010001 unsigned char res = var | mask; // результат 10011001
Также допускается применение такой записи
var |= mask; // то же самое, что и var = var | mask;
Наконец, при операции исключающее ИЛИ результирующий бит устанавливается равным 0, если оба бита соответствующих операндов равны 1, и 1 в противном случае. Для выполнения данной операции в языке С++ используется символ ‘^’:
unsigned char var = 153; //двоичная запись 10011001 unsigned char mask = 0x11; // число 00010001 unsigned char res = var ^ mask; // результат 10001000
или
var ^= mask; // то же самое, что и var = var ^ mask;
Рассмотрим примеры использования логических операций, которые часто применяются на практике. Самой распространенной по использованию является операция логического И. Данная операция обычно используется совместно с так называемыми масками. Под маской понимают битовый шаблон, который служит для выделения тех или иных битов числа, к которому она применяется. Например, если требуется определить, является ли нулевой бит числа установленным в 1 или нет, то для этого задается маска 00000001, которая соответствует числу 1 и выполняется операция поразрядного И:
unsigned char flags = 3; // 00000011 unsigned char mask = 1; // 00000001 if((flag & mask) == 1) printf(“Нулевой бит включен”); else printf(“Нулевой бит выключен”);
Здесь переменная flags, представленная одним байтом, содержит восемь флаговых битов. Для того чтобы узнать установлен или нет нулевой флаговый бит задается маска со значением 1 и выполняется операция логического И. В результате все биты переменной flags будут равны нулю за исключением нулевого, если он изначально имел значение 1. Таким образом, маска является шаблоном, который как бы накладывается на битовое представление числа, из которого выделяются биты, соответствующие единичным значениям маски. Рассмотренный пример показывает, как одна байтовая переменная flags может содержать восемь флаговых значений и тем самым экономить память ЭВМ.
Следующим примером использования логических операция является возможность включать нужные биты в переменной, оставляя другие без изменений. Для этого используется логическая операция ИЛИ. Допустим, в переменной flags необходимо установить второй бит равным 1. Для этого задается маска в виде переменной mask = 2 (00000010) и реализуется операция логического ИЛИ:
unsigned char flags = 0; // 00000000 unsigned char mask = 2; // 00000010 flags |= mask;
Этот код гарантирует, что второй бит переменной flags будет равен 1 без изменений значений других битов.
Для отключения определенных битов целесообразно использовать две логические операции: логическое И и логическое НЕ. Допустим, требуется отключить второй бит переменной flags. Тогда предыдущий пример запишется следующим образом:
unsigned char flags = 0; // 00000000 unsigned char mask = 2; // 00000010 flags = flags & ~mask;
или
flags &= ~mask;
Работа этих двух операций заключается в следующем. Приоритет операции НЕ выше приоритета операции И, поэтому переменная mask в двоичной записи будет иметь вид 11111101. Применяя операцию логического умножения переменной flags с полученным числом ~mask все биты останутся неизменными, кроме второго, значение которого будет равно нулю.
Наконец, операция исключающее ИЛИ позволяет переключать заданные биты переменных. Идея переключения битов основывается на свойствах операции исключающего ИЛИ: 1^1 = 0, 1^0 = 1, 0^0 = 0 и 0^1 = 1. Анализ данных свойств показывает, что если значение бита маски будет равно 1, то соответствующий бит переменной, к которой она применяется, будет переключен, а если значение бита маски равно 0, то значение бита переменной останется неизменным. Следующий пример демонстрирует работу переключения битов переменной flags.
unsigned char flags = 0; //00000000 unsigned char mask = 2; //00000010 flags ^= mask; //00000010 flags ^= mask; //00000000
Кроме логических операций в языке С++ существуют операции поразрядного смещения битов переменной. Операция смещения битов влево определяется знаком << и смещает биты значения левого операнда на шаг, определенный правым операндом, например, в результате выполнения команды
10001010 << 2;
получится результат 00101000. Здесь каждый бит перемещается влево на две позиции, а появляющиеся новые биты устанавливаются нулевыми. Рассмотрим особенности действия данной операции на следующем примере:
int var = 1; var = var <<1; //00000010 – значение 2 var <<= 1; //00000100 – значение 4
Можно заметить, что смещение битов переменной на одну позицию влево приводит к операции умножения числа на 2. В общем случае, если выполнить сдвиг битов на n шагов, то получим результат равный умножению переменной 2 в степени n на . Данная операция умножения на число 2 в степени n является более быстрой, чем обычное умножения, рассматриваемое ранее.
Аналогично, при операции смещения вправо >> происходит сдвиг битов переменной на шаг, указанный в правом операнде. Например, сдвиг
00101011 >> 2;
приведет к результату 00001010. Здесь, также как и при сдвиге влево, новые появляющиеся биты устанавливаются равными нулю. В результате выполнения последовательностей операций
int var = 128; //1000000 var = var >> 1; //0100000 – значение 64 var >>= 1; //0010000 – значение 32
значение переменной var каждый раз делится на 2. Поэтому сдвиг var >>= n можно использовать для выполнения операции деления значения переменной на величину 2 в степени n.
