- •1. Краткие теоретические сведения
- •1.4. Пустой оператор
- •1.5. Составной оператор (блок)
- •1.6. Операторы начала и конца программы
- •Int main()
- •1.7. Оператор return
- •1.8. Оператор присваивания
- •1.8.1. Множественное присваивание
- •1.8.2. Ошибки при присваивании
- •1.8.3. Не путайте операторы равенства и присвоения
- •1.8.4. Составные операторы присвоения
- •1.8.6. Присваивание значения при объявлении
- •1.9. Операторы ввода-вывода
- •1.10. Функции ввода и вывода
- •1.10.1. Функция printf
- •1.10.2. Функция scanf
- •1.11. Операторы потокового ввода и вывода
- •1.11.1. Использование cout для отображения вывода на экран
- •1.11.2. Использование cout для вывода чисел
- •1.11.3. Вывод нескольких значений одновременно
- •1.11.4. Использование специальных символов вывода
- •1.11.5. Другие специальные символы
- •1.11.5. Вывод восьмеричных и шестнадцатеричных значений
- •1.11.6. Вывод на стандартное устройство ошибок
- •1.11.7. Управление шириной вывода
- •1.11.8. Директива #define
- •1.11.9. Оператор потокового вывода cin
- •1.11.10. Второе знакомство с cin
- •1.11.11. Следите за ошибками переполнения
- •1.11.12. Следите за ошибками несовпадения типов
- •1.11.13. Чтение символьных данных
- •1.11.14. Чтение слов с клавиатуры
- •1.11.15. Чтение строковых данных
- •1.12. Комментарии. Использование пробелов
- •1.13. Линейный вычислительный процесс
- •1.16. Таблица выбора идентификаторов
- •2. Задание
- •2.10. Задания
- •2.10.1. Задание 1
- •2.10.2. Задание 2
- •2.10.3. Задание 3 (домашнее)
- •3. Выводы
- •4. Требование к отчету
- •5. Вопросы для самоконтроля
- •Литература
- •Оглавление
1.8.3. Не путайте операторы равенства и присвоения
Предупреждение: не путайте знак операции присваивания = и знак операции сравнения!!!
То, что оператор присвоения можно использовать в условии, приводит иногда к удивительным результатам.
if (i = 42)
Этот код вполне допустим: здесь переменной i присваивается значение 42, которое затем используется при проверке условия. Поскольку значение 42 отлично от нуля, оно интерпретируется как значение true. Однако автор этого кода почти наверняка предполагал проверить равенство содержимого переменной i значению 42: if (i == 42)
Найти подобную ошибку довольно трудно. Правда, некоторые компиляторы, но не все, могут предупредить о подобном коде.
1.8.4. Составные операторы присвоения
В языке С++ также существует операция комбинированного (составного) присваивания. Общая синтаксическая форма составного оператора присвоения имеет следующий вид
V1 OP = V;
что эквивалентно
V1 = V1 OP V;
где V1 – переменная, V – выражение, OP – одна из 10 составных операций:
+ = - = *= /= %= // арифметические операторы
<<= >>= &= ^ = |= // побитовые операторы
Например, оператор а += b; эквивалентен оператору а = а + b; Составной оператор присвоения += добавляет правый операнд к левому, а результат сохраняет в левом операнде.
Обычная и составная формы присваивания имеют одно очень важное различие: в составном операторе присвоения левый операнд вычисляется только один раз. При использовании эквивалентной, но более длинной версии левый операнд вычисляется дважды: один раз как правый операнд, а затем как левый. В подавляющем большинстве случаев это различие несущественно, возможно, кроме тех, где производительность критически важна.
В таблице 5.1 приведены все операции присваивания и примеры их использования.
Таблица 5.1
Операции присваивания языка С++
Знак |
Операция и пример использования |
= |
Присвоить значение выражения-операнда из правой части операнду левой части: р =10.3 - 2*х; |
*= |
Присвоить операнду левой части произведение значений обоих операндов: р *= 2 эквивалентно р = р * 2; |
/= |
Присвоить операнду левой части частное от деления значения левого операнда на значение правого: р /= 2.2 – d эквивалентно р = р / (2.2 - d); |
%= |
Присвоить операнду левой части остаток от деления целочисленного значения левого операнда на целочисленное значение правого операнда: n %= 3 эквивалентно n = n % 3; |
+= |
Присвоить операнду левой части сумму значений обоих операндов а +=b в эквивалентно a = а + b; |
-= |
Присвоить операнду левой части разность значений левого и правого операндов: х -= 4.3 - z эквивалентно х = х - (4.3 - z); |
<<= |
Присвоить целочисленному операнду левой части значение, полученное сдвигом влево его битового представления на количество разрядов, равное значению правого целочисленного операнда: а <<= 4 эквивалентно а = а << 4; |
>>= |
Присвоить целочисленному операнду левой части значение, полученное сдвигом вправо его битового представления на количество разрядов, равное значению правого целочисленного операнда: а >>= 4 эквивалентно а = а >> 4; |
&= |
Присвоить целочисленному операнду левой части значение, полученное поразрядной конъюнкцией (И) его битового представления с битовым представлением целочисленного операнда правой части: е &= 44 эквивалентно е = в & 44; |
|= |
Присвоить целочисленному операнду левой части значение, полученное поразрядной дизъюнкцией (ИЛИ) его битового представления с битовым представлением целочисленного операнда правой части: а |=b эквивалентно а = а | b; |
^= |
Присвоить целочисленному операнду левой части значение, полученное применением поразрядной операции исключающего ИЛИ к битовым представлениям значений обоих операндов: z ^= х + у эквивалентно z = z^ (х + у). |
Иллюстрацией некоторых особенностей выполнения операций присваивания служит программа, приведенная в примере 5.8.
Пример 5.8.
/*Программа LR5-Primer8*/
//Операции присваивания
#include<iostream.h>
#include<conio.h>
int main()
{
int k;
cout << "\n\n k = 35/4 равняется " << (k=35/4);
cout << "\t k /= 1 + 1 + 2 равняется "<< (k/=1+1+2)<< endl;
cout << "\n k *= 5 - 2 равняется " << (k*=5-2);
cout << "\t k %= 3 + 2 равняется " << (k%=3+2)<< endl;
cout << "\n k += 21/3 равняется " << (k+=21/3);
cout << "\t k -= 6 - 6/2 равняется " << (k-=6-6/2)<< endl;
cout << "\n k <<= 2 равняется " << (k<<=2);
cout << "\t k >>= 6-5 равняется " << (k>>=6-5)<< endl;
cout << "\n k &= 9 + 4 равняется " << (k&=9+4);
cout << "\t k |= 8 - 2 равняется " << (k|=8-2)<< endl;
cout << "\n k ^= 10 равняется " << (k^=10)<< endl;
getch();
return 0;
}
В первом присваивании обратите внимание на выполнение деления целочисленных операндов, при котором выполняется округление за счет отбрасывания дробной части результата.
Результаты выполнения:
Полученные числовые значения, во-первых, подтверждают эквивалентность записей El ор= Е2 и El = El op (Е2). Кроме того, анализируя результаты, можно еще раз рассмотреть особенности поразрядных операций. Двоичный код для к, равного 5, будет 101. Сдвиг влево на 2 дает 10100 (десятичное 20). Затем сдвиг на 1 вправо формирует код 1010 (десятичное 10). Поразрядная конъюнкция 101061101 дает 1000 (десятичное 8). Затем 1000|100 дает значение 1110 (десятичное 14). Результатом 1110^1010 будет 0100 (десятичное 4).
1.8.5. L-значения и r-значения
Более подробная информация о выражениях приведена в главе 5, "Выражения", а пока отметим, что выражения языка С++ имеют две части.
1. L-значение (lvalue). Выражение, являющееся l-значением, может располагаться как с левой, так и с правой стороны оператора присвоения.
2. R-значение (rvalue). Выражение, являющееся r-значением, может располагаться только с правой, но никак не с левой стороны оператора присвоения.
Переменные, которые являются l-значениями, могут располагаться как с левой, так и с правой стороны оператора присвоения, а числовые литералы, являющиеся r-значениями, подлежат лишь присвоению, их значение изменить нельзя. Предположим, что определено несколько переменных.
int units_sold = 0;
double sales_price = 0, total__revenue = 0;
Код, приведенный ниже, содержит ошибки, которые проявятся во время компиляции.
//ошибка: арифметическое выражение не является l-значением
units_sold * sales__price = total__revenue;
// ошибка: литеральная константа не является 1-значением
0 = 1;
Некоторые операторы, например оператор присвоения, требуют, чтобы один из его операндов был l-значением. Поэтому l-значения применяются значительно чаще, чем r-значения. Способ использования l-значения определяет контекст, в котором оно присутствует в выражении. Рассмотрим пример.
units_sold = units_sold + 1;
В этом выражении переменная units__sold используется как операнд двух разных операторов. Оператору + нужны только значения его операндов. Значением переменной (value) называют текущее значение, хранимое в области памяти, принадлежащей данной переменной. Оператор сложения получает эти значения, а вычисленную сумму возвращает как результат.
Переменная units_sold используется как левая сторона оператора присвоения (=). Оператор присвоения читает выражение с правой стороны и заносит его результат в переменную, указанную с левой стороны. В этом выражении результат сложения сохраняется в области памяти, которая принадлежит переменной units_sold. Прежнее значение переменной units_sold при этом перезаписывается.
Операции присваивания.
В качестве левого операнда в операциях присваивания может использоваться только модифицируемое /-значение - ссылка на некоторую именованную область памяти, значение которой доступно изменениям. Термин /-значение {left value), иначе - леводопустимое выражение, происходит от объяснения действия операции присваивания е - d, в которой операнд е слева от знака операции присваивания может быть только модифицируемым /-значением. Примером модифицируемого /-значения служит имя переменной, которой выделена память и соответствует некоторый класс памяти.