IV Flashcards
Как распространить инструкцию на несколько строк?
- Если по каким-то причинам необходимо распространить инструкцию на несколько строк, достаточно добавить последним символом сим вол обратной косой черты ():
cout << “Hello \
World” << endl; // Разделение строки на две вполне допустимо
- Еще один способ разместить приведенную выше инструкцию в двух строках — это использовать два строковых литерала вместо одного:
cout << “Hello “
“World” << endl; // Два строковых литерала подряд вполне допустимы
- Встретив такой код, компилятор обратит внимание на два соседних строковых литерала и сам объединит их.
- Разделение инструкций на несколько строк может быть полезным, если у вас есть длинные текстовые элементы или сложные инструкции, состоящие из множества переменных, которые делают инструкцию намного длиннее, чем может вместить большинство экранов.
Оператор это
Операторы (operator) в C++ представляют собой инструменты, предоставляемые языком для работы с данными, их преобразования, обработки и принятия решений на их основе.
Оператор присваивания (=)
Оператор присваивания (assignment operator) вполне интуитивно понятен:
int daysInYear = 365;
Приведенное выше выражение использует оператор присваивания для инициализации целочисленной переменной значением 365. Оператор присваивания заменяет значение, содержащееся в операнде слева от оператора присваивания (называемого l-значением (l-value)), значением операнда справа (называемого г-значением (r-value)).
Понятие I- и г-значений
- Зачастую l-значения называют областями памяти.
- С другой стороны, r-значения могут быть самим содержимым области памяти.
- Все l-значения могут быть r-значениями, но не все r-значения могут быть l-значениями. Чтобы понять это лучше, рассмотрим следующий пример, который не имеет никакого смысла, а потому не будет компилироваться:
365 = daysInYear;
Оператор деления по модулю
Оператор деления по модулю (%) возвращает остаток от деления и применим только к целочисленным значениям.
- int numl = 22;*
- int num2 = 5;*
- int divideNums = numl / num2; / / 4*
- int moduloNums = numl % num2; / / 2*
Операторы инкремента (++) и декремента (- -)
- Синтаксис их использования следующий:
- int num1 = 101 ;*
- int num2 = numl++; // Постфиксный оператор инкремента*
- int num2 = ++num1; // Префиксный оператор инкремента*
- int num2 = num1–; // Постфиксный оператор декремента*
- int num2= – num1; // Префиксный оператор декремента*
Пример кода демонстрирует два разных способа применения операторов инкремента и декремента: до и после операнда. Операторы, которые располагаются перед операндом, называются префиксными (prefix) операторами инкремента или декремента, а те, которые располагаются после, — постфиксными (postfix).
Результат выполнения постфиксных операторов заключается в том, что сначала l-значению присваивается r-значение, а потом r-значение увеличивается или уменьшается. Это значит, что во всех случаях использования постфиксного оператора значением переменной num2 будет прежнее значение переменной num1 (т.е. то значение, которое она имела до операции инкремента или декремента).
Действие префиксных операторов прямо противоположно: сначала изменяется r-значение, а затем оно присваивается l-значению. В этих случаях переменные num2 и num1 имеют одинаковые значения.
- В следующих выражениях префиксные или постфиксные операторы никак не влияют на результат:
- startValue++; // То же, что и…*
- ++startValue;*
- Дело в том, что здесь нет присваивания исходного значения и конечный результат в обоих случаях — увеличенное на единицу значение переменной startValue.
- Нередко приходится слышать о ситуациях, когда префиксные операторы инкремента или декремента являются более предпочтительными с точки зрения производительности, т.е. ++ startValue предпочтительнее, чем startValue++. Это правда, по крайней мере теоретически, поскольку при постфиксных операторах компилятор должен временно хранить исходное значение на случай его присваивания. Влияние на производительность в случае целых чисел незначительно, но в случае некоторых классов этот аргумент мог бы иметь смысл. Интеллектуальные компиляторы могут полностью устранить различия, оптимизируя код.
Операторы равенства (==) и неравенства (!=)
Зачастую необходимо проверить выполнение или не выполнение определенного условия прежде, чем предпринять некое действие. Операторы равенства == (операнды равны) и неравенства ! = (операнды не равны) позволяют сделать именно это.
Результат проверки равенства имеет логический тип bool, т.е. true (истина) или false (ложь).
Операторы сравнения
Логические операции НЕ, И, ИЛИ и ИСКЛЮЧАЮЩЕЕ ИЛИ
- Логическая операция НЕ выполняется с помощью оператора ! и выполняется над одним операндом.
- Для других операций, таких как И, ИЛИ или ИСКЛЮЧАЮЩЕЕ ИЛИ, необходимы два операнда. Логическая операция И возвращает значение true только тогда, когда каждый операнд содержит значение true.
- Логическая операция И выполняется с помощью оператора &&.
- Логическая операция ИЛИ возвращает значение true тогда, когда по крайней мере @один из операндов содержит значение true.
- Логическая операция ИЛИ выполняется с помощью оператора | |.
- Логическая операция ИСКЛЮЧАЮЩЕГО ИЛИ (XOR) немного отличается от логической операции ИЛИ и возвращает значение tru e тогда, когда любой из операндов содержит значение tru e, но не оба одновременно (т.е. когда логические значения операндов не равны).
- Логическая операция ИСКЛЮЧАЮЩЕГО ИЛИ выполняется с помощью оператора ^. Результат получается путем выполнения операции ИСКЛЮЧАЮЩЕГО ИЛИ над битами операндов.
Побитовые операторы &, | и ^
Побитовые операторы сдвига вправо (>>) и влево (<<)
- Различие между логическими и побитовыми операторами в том, что они возвращают не логический результат, а значение, отдельные биты которого получены в результате выполнения оператора над соответствующими битами операндов.
- Язык C++ позволяет выполнять такие операции, как НЕ, ИЛИ, И и ИСКЛЮЧАЮЩЕЕ ИЛИ (XOR) в побитовом режиме, позволяя работать с отдельными битами, инвертируя их с помощью оператора применяя операцию ИЛИ с помощью оператора | , операцию И с помощью оператора & и операцию XOR с помощью оператора ^.
- Операторы сдвига перемещают всю последовательность битов вправо или влево, позволяя осуществить умножение или деление на степень двойки, а также имеют многие другие применения.
- Вот типичный пример применения оператора сдвига для умножения на два:
- int doubledValue = Num << 1; // Для удвоения значения биты*
- // сдвигаются на одну позицию влево*
- Вот типичный пример применения оператора сдвига для деления на два:
- int halvedValue = Num >> 1; // Для деления значения на два биты*
- // сдвигаются на одну позицию вправо*
Составные операторы присваивания
- Составные операторы присваивания (compound assignment operator) — это операторы присваивания, в которых результат операции присваивается левому операнду. Рассмотрим следующий код:
- int num1 = 22;*
- int num2 = 5;*
- num1 += num2; // После операции numl содержит значение 27*
- Этот код эквивалентен следующей строке кода:
- num1 = num1+ num2;*
- Таким образом, результат оператора += это сумма этих двух операндов, присвоенная затем левому операнду (num1).
Использование оператора sizeof для определения объема памяти, занимаемого переменной
- Этот оператор возвращает объем памяти в байтах, используемой определенным типом или переменной. Оператор sizeof имеет следующий синтаксис:
- sizeof (Переменная) ;*
- или*
- sizeof (Тип);*
- Оператор sizeof( . . . ) выглядит как вызов функции, но это не функция, а оператор. Данный оператор не может быть определен программистом, а следовательно, не может быть перегружен.
Условное программирование с использованием конструкции if…else
- Условное выполнение кода реализовано в языке C++ на основе конструкции if…else , синтаксис которой имеет следующий вид:
- if (Условное_выражение)*
- Сделать нечто, когда условное_выражение равно true;*
- else // Необязательно*
- Сделать нечто иное, когда условное_выражение равно false;*
- Если вы хотите выполнить не одну, а несколько инструкций в зависимости от условий, заключите их в блок. По существу, это фигурные скобки ( { . . . } ) , включающие несколько инструкций, которые будут выполняться как единая инструкция. Рассмотрим пример:
- if (Условие)*
- {*
- // Блок при истинности условия*
- Инструкция 1;*
- Инструкция 2;*
- }*
- else*
- {*
- // Блок при ложности условия*
- Инструкция 3;*
- Инструкция 4;*
- }*
- Такие блоки именуются также составными инструкциями (compound statement).
- Нередки ситуации, когда необходимо проверить несколько разных условий, некоторые из которых зависят от результата проверки предыдущего условия. Язык С++ допускает вложенные инструкции if для выполнения таких действий.
- Конструкции if … else можно группировать через конструкцию else if
Условная обработка с использованием конструкции switch-case
- Задача конструкции switch-case в том, чтобы сравнить результат некоего выражения с набором заранее определенных возможных константных значений и выполнить разные действия, соответствующие каждой из этих констант. Новые ключевые слова C++, которые используются в такой конструкции, — это switch, case, default и break.Конструкция switch-case имеет следующий синтаксис:
- switch (Выражение)*
- {*
- case Метка_А:*
- Сделать_Нечто;*
- break;*
- case Метка_В:*
- Сделать_Нечто_Другое ;*
- break;*
- // И так далее…*
- default:*
- Сделать_Нечто_Если_Выражение_Не_ Равно_Ничему_Выше;*
}
- Код вычисляет результат Выражения и сравнивает его на равенство с каждой из меток частей case ниже (каждая Метка должна быть целочисленной константой), а затем выполняет код после этой метки. Если результат выражения не равен метке Метка_А, он сравнивается с меткой Метка_ В. Если значения совпадают, выполняется часть Cделать_Нечто_Другое. Выполнение продолжается до тех пор, пока не встретится оператор break .
- Оператор break означает выход из блока кода. Операторы break в рассматриваемой конструкции не обязательны, однако без них выполнение продолжится в коде следующей метки и так далее до конца всей конструкции (или до оператора break) . Такого явления, как правило, желательно избегать. Часть конструкции default также является необязательной; она выполняется тогда, когда результат выражения не соответствует ни одной из меток в конструкции switch-case.
- Не добавляйте две инструкции case с одинаковой меткой - это не имеет смысла и не будет компилироваться.
- Не усложняйте свои инструкции case, отказываясь от оператора break и разрешая последовательное выполнение. Такое решение может привести к неработоспособности кода позже, при перемещении инструкции case.
Тернарный условный оператор ( ? : )
- Язык C++ предоставляет интересный и мощный оператор, называемый тернарным условным оператором (conditional operator), который подобен сжатой конструкции if…else.
- Тернарный условный оператор, называемый также просто условным оператором, использует три операнда:
- (Логическое_выражение) ? Инструкция_для_true : Инструкция_для_fаlsе;*
- Такой оператор применим, например, при компактном сравнении двух чисел, как показано ниже.
int max = (numl > num2) ? numl : num2; // Максимум из numl и num2
- Не используйте в операторах ? : сложные условия или выражения.
Рудиментарный цикл с использованием инструкции goto
- Как подразумевает название инструкции goto, она приказывает процессору продолжать выполнение программы с определенной точки в коде. Вы можете использовать ее для перехода назад и повторного выполнения определенных инструкций. Синтаксис инструкции goto таков:
- SomeFunction ( )*
- {*
- Start: // Эта инструкция называется меткой*
- Многократно_выполняемый_код;*
- goto Start;*
- Вы объявляете метку Start и используете инструкцию goto для повторного выполнения кода с этого места. Если вы не выполните условие, которое приведет к пропуску выполнения инструкции goto, и если в многократно повторяемом коде не содержится оператор return, выполняемый при определенных условиях, то часть кода между командой goto и меткой будет повторяться бесконечно и программа никогда не завершится.
- Использование инструкции goto не рекомендуется для создания циклов, поскольку его массовое применение может привести к непредсказуемой последовательности выполнения кода, когда выполнение может переходить с одной строки на другую без всякого очевидного порядка или последовательности, оставляя переменные в непредсказуемых состояниях.
Тяжелый случай программы, использующей инструкции goto, называется запутанной программой, или кодом спагетти (spaghetti code). - Циклы while, do … while и for позволяют избежать использования инструкции goto.
Цикл while, цикл do…while
Синтаксис цикла while:
- whilе (Выражение)*
- {*
- // Если Выражение == true*
- Блок_Инструкций;*
- }*
Синтаксис цикла do … while:
- do*
- Блок_Инструкций; // Выполняется как минимум один раз*
- } while (Условие); // Цикл завершается, если Условие ложно*
- Обратите внимание, что строка, содержащая часть while (Условие), заканчивается точкой с запятой. Этим данный цикл отличается от цикла while, в котором точка с запятой фактически завершила бы цикл в первой строке, приведя к пустой инструкции.
Цикл for
- Синтаксис цикла for таков:
for (Выражение инициализации, выполняемое только раз;
Условие выхода, проверяемое в начале каждой итерации;
Выражение цикла, выполняемое в конце каждой итерации)
{
Блок инструкций;
}
- Применение инициализации, условия выхода и выражения, выполняемого в конце каждого цикла, является необязательным. Вполне возможно записать цикл for без некоторых из указанных выражений (или вовсе без них) - for ( ; ; )
- В пределах выражения инициализации цикла for можно инициализировать несколько переменных.
- for (int counter1 = 0, counter2 = 5; // Инициализация*
- counter1 < ARRAY_LENGTH; // Условие*
- ++counter1, – counter2) // Инкремент, декремент*
Цикл for для диапазона
- Стандарт C++11 ввел новый вариант цикла for, который работает со всеми элементами из диапазона значений, такого как, например, массив, с помощью более простого и удобочитаемого кода.
- Синтаксис цикла for для диапазона также использует ключевое слово for:
- for (VarType varName : Последовательность)*
- {*
- // varName в теле цикла содержит элемент последовательности*
- }*
Пример:
- int someNums [] = { 1, 101, -1, 40, 2040 };*
- cout << “Элементами массива являются:” << endl;*
- for (int aNum : someNums) // Цикл for для диапазона*
- cout << aNum << endl;*
- Можно дополнительно упростить приведенную инструкцию с помощью автоматического вывода типа переменной (ключевое слово auto ) и составить обобщенный цикл, который будет работать с массивами элементов любого типа:
- for (auto anElement : elements) // Цикл for для диапазона*
- cout << anElement << endl;*
Изменение поведения цикла с использованием операторов continue и break
- В некоторых случаях (особенно в сложных циклах с большим количеством параметров в условии) может не получиться грамотно сформулировать условие выхода из цикла, и тогда вам придется изменять поведение программы уже в пределах цикла. В этом вам могут помочь операторы continue и break.
- Оператор continue позволяет возобновить выполнение с начала цикла. Он просто пропускает весь код, расположенный в теле цикла после него. Таким образом, результат выполнения оператора continue в цикле while, do … while или for сводится к переходу к условию выхода из цикла и повторному входу в блок цикла, если условие истинно.
- В случае применения оператора continue в цикле for перед проверкой условия выхода выполняется выражение цикла (третье выражение в цикле for, которое обычно увеличивает значение счетчика).
- Оператор break осуществляет выход из блока цикла, завершая выполнение цикла, в котором он был вызван.
- Обычно программисты полагают, что пока условия цикла выполняются, выполняется и весь код в цикле. Операторы continue и break изменяют это поведение и могут привести к непонятному интуитивно коду. Поэтому операторы continue и break следует использовать реже.
Бесконечные циклы, которые никогда не заканчиваются, и управление ими
- Вспомните, что у циклов while, do … while и for есть условия, результат вычисления которых, равный false, приводит к завершению цикла. Если вы зададите условие, которое всегда возвращает значение true, цикл никогда не закончится.
- Как ни странно, у таких циклов действительно есть применение. Представьте, например, операционную систему, которая должна непрерывно проверять, подключено ли устройство USB к порту USB. Это действие должно выполняться регулярно, пока запущена операционная система.
- Для выхода из бесконечного цикла (например, перед завершением работы операционной системы в предыдущем примере) вы можете использовать оператор break (как правило, в пределах блока if (условие)).
- Не используйте бесконечные циклы с оператором break , если этого можно избежать.
Эквивалентны ли пустой цикл while и цикл for ( ; ; ) ?
Нет, цикл while всегда нуждается в наличии условия выхода.