Арифметические и логические операторы
Урок систематизирует операторы C: арифметику, сравнение, логику и инкремент, а также объясняет коварные места — целочисленное деление, остаток и приоритет операций.
В C деление двух целых даёт целое: 7 / 2 равно 3, а не 3.5. Дробная часть отбрасывается. Это не баг, а следствие типизации, и источник бесчисленных ошибок у новичков.
Арифметические операторы привычны: + - * / и оператор остатка %. Но в C тип операндов решает всё. Если оба операнда целые, то и результат деления будет целым с отброшенной дробной частью:
int a = 7, b = 2;
printf("%d\n", a / b); // 3, а не 3.5
printf("%d\n", a % b); // 1 — остаток от деления
printf("%f\n", 7.0 / 2); // 3.5 — хотя бы один операнд дробный
Оператор остатка % отвечает на вопрос «что останется после деления нацело». 7 % 2 равно 1. Он невероятно полезен: проверка чётности (n % 2 == 0), зацикливание индекса, разбиение числа на цифры.
Операторы сравнения (== != < > <= >=) возвращают целое: 1 если истина, 0 если ложь. В C нет отдельного типа «логическое значение» в классическом смысле — любое ненулевое число считается истиной, ноль — ложью. Логические операторы: && (И), || (ИЛИ), ! (НЕ).
Как работает под капотом
Два важнейших механизма: приоритет операторов и сокращённое вычисление логики. Приоритет определяет порядок: * и / выполняются раньше + и -, как в математике. А логические && и || вычисляются «лениво» — слева направо, с ранним выходом.
Выражение: 2 + 3 * 4
Шаг 1: 3 * 4 = 12 (умножение раньше сложения)
Шаг 2: 2 + 12 = 14
Логика && (короткое замыкание):
(x != 0) && (10 / x > 1)
| |
если ЛОЖЬ ----------+--> правая часть НЕ вычисляется
(защита от деления на ноль!)
Сокращённое вычисление — не просто оптимизация, а инструмент защиты. В выражении x != 0 && 10 / x > 1, если x равен нулю, левая часть ложна, и правая (с делением на ноль) вообще не выполнится.
Частые ошибки
- Целочисленное деление там, где ждали дробь.
double avg = sum / count;при целыхsumиcountсначала делит нацело, теряя дробь, и только потом сохраняет в double. - Путаница
=и==.if (x = 0)присваивает ноль и всегда ложно;if (x == 0)сравнивает. - Расчёт на приоритет наугад.
a & b == cработает не так, как кажется:==приоритетнее побитового&. - Остаток от отрицательных чисел. Знак результата
%в C совпадает со знаком делимого, что может удивить.
Best practices
- Ставьте скобки, даже когда приоритет «и так понятен». Скобки бесплатны, а читаемость и защита от ошибок — нет.
- Чтобы получить дробное деление целых, приводите тип явно:
(double)sum / count. - Используйте сокращённое вычисление осознанно: ставьте проверку-защиту слева от
&&.
Целочисленное деление и остаток одинаково работают в Python (оператор // и %), поэтому логику легко проверить там же.
# Разбиваем число на цифры через % и // — как в C через % и /
n = 1234
digits = []
while n > 0:
digits.append(n % 10) # последняя цифра
n = n // 10 # отбрасываем её (в C это n / 10 для int)
print("Цифры справа налево:", digits)
print("Сумма цифр:", sum(digits))
Та же логика на Python ▶ — связка «остаток + деление нацело» одинакова в обоих языках. В C для целых n / 10 ведёт себя как // в Python.
Побитовые операторы
Помимо логических, в C есть побитовые операторы, работающие с отдельными битами числа: & (И), | (ИЛИ), ^ (исключающее ИЛИ), ~ (инверсия) и сдвиги <<, >>. Их легко спутать с логическими && и ||, но смысл другой: 5 & 3 сравнивает биты и даёт 1, а 5 && 3 — это логическое И, дающее 1 как «истина И истина». Побитовые операции широко применяют там, где важна каждая копейка памяти или скорость: флаги-битмаски (несколько булевых настроек в одном числе), работа с регистрами устройств, быстрое умножение и деление на степени двойки через сдвиги. Это одна из причин, по которой C незаменим в системном и встраиваемом программировании.
Итоги
Операторы C чувствительны к типам: деление двух целых отбрасывает дробь, а оператор % даёт остаток. Сравнения и логика возвращают 0 или 1, причём && и || вычисляются с коротким замыканием, что можно использовать для защиты. Главные ловушки — целочисленное деление, путаница = и == и приоритет операций; лечатся явным приведением типа и скобками.