Arithmetic, Relational, and Logical Operators
The core operator families, integer versus floating division, the modulo operator, and how relational results are just ints.
Three Families That Do the Work
Chapter 2 gave you values; this chapter is about combining them. C sorts its everyday operators into three families: arithmetic operators compute numbers, relational operators compare them, and logical operators combine the results of comparisons. Two of the three hold surprises that exams probe relentlessly: integer division and the fact that in C, a comparison is itself just a number.
Arithmetic: Five Operators, Two Surprises
The five arithmetic operators are +, -, *, /, and %. Addition, subtraction, and multiplication behave as arithmetic always has. Division is where C shows its character:
Surprise one: integer division truncates. When both operands are integers, / throws the fractional part away: 17 / 5 is 3, not 3.4. Nothing rounds; the fraction is simply discarded. The companion operator % gives the remainder of that division: 17 % 5 is 2, because 17 is three fives with two left over. Together they decompose any integer division, and half the classic exam programs (digit sums, even/odd, clock arithmetic) are built from exactly this pair.
Negative operands are where the two C standards part company, so this is worth getting right once:
-17 / 5 = -3
-17 % 5 = -2
17 % -5 = 2
The rule these results follow is C99's: division truncates toward zero, and % takes the sign of the left operand, the dividend. C89, the standard this course compiles against, deliberately does not require that. When either operand is negative it leaves the direction of truncation implementation-defined: a conforming C89 compiler may give -17 / 5 as -4 with a remainder of 3, as long as it documents its choice and keeps the identity (a / b) * b + a % b == a intact. Every compiler you are likely to meet, GCC included, truncates toward zero as above.
Two practical consequences. Do not memorize a rule for negative operands as though it were a language guarantee, because on C89 it is not one. And do not reach for n % 2 == 1 to test for odd numbers: that is false for negative n on every implementation that truncates toward zero, since -7 % 2 is -1. Test n % 2 != 0 instead, which is correct whichever direction the implementation rounds.
Surprise two: % is integers only. Writing 17.0 % 5.0 is a compile error; remainders of double values need the library function fmod, which arrives with the math library later in this chapter. Also notice %% in the format string: since % introduces conversion specifiers, printing a literal percent sign takes two.
When either operand is floating, / divides exactly as you expect: 17.0 / 5.0 is 3.4. What happens when integer meets double in one expression is the conversions lesson's story, later this chapter.
Relational: Comparisons Are Numbers
Six operators compare values: <, <=, >, >=, == (equal), and != (not equal). Here is the idea that separates C from most languages you might know: a comparison is an ordinary expression whose value is an int, 1 when true, 0 when false. There is no separate boolean type in ANSI C; truth is arithmetic.
The consequences are everywhere. You can print a comparison, store it in an int, or do arithmetic with it. And one of C's most notorious bugs is born here: == compares, but = assigns, and both are legal in almost every position. Typing marks = 100 where you meant marks == 100 quietly stores 100 rather than testing it. The compiler's warnings catch many cases; your eyes must catch the rest. Exam papers plant this deliberately.
Logical: Combining Truths
Three operators work on truth values: && (and), || (or), ! (not). Their operands follow one simple rule: zero is false, anything non-zero is true, and like the relational family they produce 1 or 0.
One property worth knowing from day one: && and || evaluate left to right and stop as soon as the answer is known. If the left side of && is false, the right side is never evaluated at all; likewise a true left side of ||. This is called short-circuit evaluation. Its full power appears once conditions guard dangerous operations ("only divide if the divisor is non-zero"), and the branching chapter uses it hard; for now, remember that the right-hand side is not guaranteed to run.
Note also that ! binds to the single thing after it, which is why the third example parenthesizes: !(marks >= 40) negates the comparison, while !marks >= 40 would negate marks first, a different and almost never intended expression. Precedence, the ranking that decides such fights, is this chapter's final lesson.
De Morgan's Rule: Moving a Negation Inward
Look again at the first two lines of that example. They are not two independent facts; each is the exact opposite of the other. "Passed both" is marks >= 40 && attendance >= 75, and "failed either" is what you get by negating it: marks < 40 || attendance < 75. Notice what the negation did. It flipped every comparison, and it turned the && into an ||.
That is De Morgan's rule, and it comes as a matched pair:
!(a && b) is the same as !a || !b
!(a || b) is the same as !a && !b
The and becomes an or, the or becomes an and, and each operand gets negated. The half that people forget is the operator swap, which is exactly the half that changes the answer.
Working an example by hand, negating "the year is a leap year under the simple rule":
!(year % 4 == 0 && year % 100 != 0)
Flip each comparison and swap the connective:
year % 4 != 0 || year % 100 == 0
Convince yourself with the machine rather than taking it on trust:
The pairs agree, and they agree for every set of values you can substitute. This is the tool for turning a condition you understand into the condition you actually need to write, which in the branching chapter is usually "what does it take to reject this input" derived from "what does it take to accept it". It also cleans up code: a nested negation like !(x < 0 || x > 100) reads far better as x >= 0 && x <= 100.
The Exam Staples These Unlock
With /, %, and comparisons producing numbers, a family of classic one-liners opens up. The last digit of n is n % 10. Removing that digit is n / 10. A year divisible by 4 is year % 4 == 0. Whether n is even is n % 2 == 0. Every one of these appears in the exercise sets ahead, and each is just the two integer-division operators plus a comparison.
Key Takeaways
- Arithmetic:
+ - * / %; integer/discards the fraction and%gives the remainder, integers only. - With a negative operand, C89 leaves the direction of truncation implementation-defined; GCC and the C99 rule truncate toward zero, making
%take the sign of the dividend. - Test oddness with
n % 2 != 0, nevern % 2 == 1, which is false for negativen. %%prints a literal percent sign in printf.- Relational:
< <= > >= == !=produce int1or0; there is no boolean type in ANSI C. =assigns and==compares; the swap is legal code and a classic planted bug.- Logical:
&& || !treat zero as false and non-zero as true, and&&/||stop evaluating once the answer is known. - De Morgan's rule:
!(a && b)is!a || !band!(a || b)is!a && !b; negating a condition flips every comparison and swaps&&with||. n % 10,n / 10, andn % 2 == 0are the building blocks of half the classic exam problems.
How did you find this lesson?
Your rating helps us improve the content.
Create an account to track your progress and access interactive exercises. Already have one? Sign in.
Arithmetic, Relational, and Logical Operators - Quiz
Test your understanding of the lesson.
Practice Exercises
The Integer Division Report
Read two integers a and b and print five lines: their sum, difference, product, integer quotient, and remainder, in the exact format a op b = result. The quotient line demonstrates truncation, so do not convert anything to double.
Lesson Discussion
Share your thoughts and questions
No comments yet. Be the first to share your thoughts!