декрементирование: —
Для каждой формы операции инкремента имеется соответствующая форма операции декремента. Вместо ++ указывайте —:
--count; // префиксная форма операции декремента count--; // постфиксная форма операции декремента
Листинг 5.12 служит иллюстрацией того, что компьютер может быть опытным поэтом.
Листинг 5.12. Программа bottles. с

Вывод начинается примерно так:
100 бутылок родниковой воды на полке, 100 бутылок родниковой воды! Возьмите одну из них и пустите по кругу,
99 бутылок минеральной воды!
99 бутылок родниковой воды на полке, 99 бутылок родниковой воды! Возьмите одну из них и пустите по кругу,
98 бутылок родниковой воды!
Все это продолжается некоторое время и закачивается следующим образом:
1 бутылок родниковой воды на полке, 1 бутылок родниковой воды!
Возьмите одну из них и пустите по кругу,
0 бутылок родниковой воды!
Операции, выражения и операторы 177
Очевидно, что у опытного поэта есть проблема с множественным числом, но это можно исправить за счет использования условной операции, описанной в главе 7.
Кстати, операция > означает “больше чем”. Как и < (“меньше чем”), она является операцией оттаения. Более подробно операции отношений рассматриваются в главе 6.
Приоритеты операций
Операции инкремента и декремента имеют очень высокий приоритет; выше по приоритету только скобки. Поэтому х*у++ означает (х) * (у++), но не (х*у)++, что благоприятно, т.к. последняя конструкция не имеет смысла. Операции инкремента и декремента применяются только к переменным (или, в общем случае, к модифицируемым 1-значепиям), а само произведение х*у не является модифицируемым 1-значением, хотя его части таковыми являются.
Не путайте приоритеты этих двух операций с порядком их вычисления. Предположим, мы имеем такой код:
у = 2;
n = 3;
nextnum = {у + n++) * 6;
Какое значение получит nextnum? Подстановка значений дает следующее:
nextnum = (2 + 3)*6 = 5*6 = 30
Значение переменной n увеличивается до 4 только после ее использования. Приоритет операции говорит о том, что операция ++ применяется только к n, но не к у + n. Он также указывает, когда значение n используется для вычисления выражения, но момент изменения значения n определяется природой операции инкремента.
Когда n++ является частью выражения, можно считать, что это означает “использовать переменную n, а затем увеличить ее значение на единицу”. С другой стороны, ++п означает “увеличить значение переменной n на единицу, а затем использовать ее”.
Не умничайте
Слишком частое применение операции инкремента быстро приводит к путанице. Например, может показаться, что программу для вывода целых чисел и их квадратов squares.с (листинг 5.4) удастся улучшить, заменив в ней цикл while таким циклом:
while (num < 21)
{
printf("%10d %10d\n", num, num*num++);
}
Код выглядит вполне разумно. Вы выводите число num, умножаете его само на себя, чтобы получить квадрат, а затем увеличиваете значение num на 1. Действительно, эта программа может даже работать в некоторых системах, правда, не во всех. Проблема заключается в том, что когда функция printf() собирается извлекать значения для вывода, она может сначала вычислить последний аргумент, увеличив значение num на 1, и только затем перейти к следующему аргументу.
В результате вместо того, чтобы вывести
5 25 она может вывести
6 25
178 глава 5
Она даже может работать справа налево, используя 5 в качестве значения крайнего правого аргумента num и 6 в качестве значения следующих двух аргументов, приводя к такому выводу:
6 30
Компилятор языка С может самостоятельно решать, какой аргумент функции вычислять первым. Такая свобода выбора увеличивает эффективность компилятора, но может стать причиной проблем, если операция инкремента применяется к аргументу функции. Другим возможным источником неприятностей может стать оператор следующего вида:
ans = num/2 + 5*(1 + num+ + );
И снова проблема заключается в том, что компилятор может выполнять действия не в том порядке, который вы имели в виду. Вы могли предполагать, что сначала будет вычислено выражение num/2 и только затем произойдет переход к вычислению другой части выражения, однако компилятор вполне может первым вычислить последний элемент, увеличить значение num и использовать это новое значение для вычисления num/2. Здесь не существует никаких гарантий.
Еще одним источником проблем может стать такая конструкция:
Читать дальше