Arithmetic Operators
Master arithmetic operations in C including addition, subtraction, multiplication, division, and modulus. Learn integer vs floating-point arithmetic, operator precedence, and avoid common pitfalls.
Basic Arithmetic Operators
C provides five basic arithmetic operators for performing mathematical calculations. These operators work on numeric types (integers and floating-point numbers) and follow standard mathematical rules. Understanding how these operators behave with different data types is crucial for writing correct calculations and avoiding bugs.
The arithmetic operators are binary operators, meaning they work on two operands (values). The result's data type depends on the operands' types. When both operands are integers, integer arithmetic is performed. When at least one operand is floating-point, floating-point arithmetic is used. This distinction affects division behavior significantly.
#include <stdio.h>
int main(void) {
/* Basic arithmetic operators */
int a = 10, b = 3;
/* Addition */
int sum = a + b;
printf("%d + %d = %d\n", a, b, sum); // 10 + 3 = 13
/* Subtraction */
int diff = a - b;
printf("%d - %d = %d\n", a, b, diff); // 10 - 3 = 7
/* Multiplication */
int product = a * b;
printf("%d * %d = %d\n", a, b, product); // 10 * 3 = 30
/* Division */
int quotient = a / b;
printf("%d / %d = %d\n", a, b, quotient); // 10 / 3 = 3 (integer division!)
/* Modulus (remainder) */
int remainder = a % b;
printf("%d %% %d = %d\n", a, b, remainder); // 10 % 3 = 1
return 0;
}The Five Arithmetic Operators:
- + Addition
- - Subtraction
- * Multiplication
- / Division
- % Modulus (remainder)
Integer vs Floating-Point Arithmetic
The behavior of arithmetic operators changes dramatically based on operand types. Integer arithmetic truncates results - 10 / 3 gives 3, not 3.333. This isn't rounding; the fractional part is simply discarded. Floating-point arithmetic preserves the fractional part, giving more accurate results for real-number calculations.
When mixing integer and floating-point operands, C automatically promotes the integer to floating-point before the operation. This type conversion (coercion) ensures consistent results but can sometimes surprise programmers who expect integer division. Understanding these rules prevents calculation errors.
/* Integer arithmetic */
int a = 10, b = 3;
int result1 = a / b;
printf("Integer: %d / %d = %d\n", a, b, result1); // 3 (truncated)
/* Floating-point arithmetic */
double x = 10.0, y = 3.0;
double result2 = x / y;
printf("Double: %.2f / %.2f = %.2f\n", x, y, result2); // 3.33
/* Mixed arithmetic (int and double) */
int i = 10;
double d = 3.0;
double result3 = i / d; // int promoted to double
printf("Mixed: %d / %.2f = %.2f\n", i, d, result3); // 3.33
/* Common mistake: both integers */
int num = 5;
int denom = 2;
double result4 = num / denom; // Division happens as int first!
printf("Mistake: %d / %d = %.2f\n", num, denom, result4); // 2.00 (not 2.50!)
/* Solution: Cast to double */
double result5 = (double)num / denom; // Cast one operand
printf("Correct: %d / %d = %.2f\n", num, denom, result5); // 2.50
/* Alternative: make one operand double */
double result6 = num / 2.0; // 2.0 is double
printf("Correct: %d / 2.0 = %.2f\n", num, result6); // 2.50The Modulus Operator
The modulus operator (%) returns the remainder after integer division. It only works with integer types - you cannot use % with floating-point numbers. Modulus is extremely useful for cyclical operations, checking divisibility, extracting digits, and many algorithms.
/* Basic modulus */
printf("%d %% %d = %d\n", 10, 3, 10 % 3); // 10 % 3 = 1
printf("%d %% %d = %d\n", 15, 4, 15 % 4); // 15 % 4 = 3
printf("%d %% %d = %d\n", 20, 5, 20 % 5); // 20 % 5 = 0
/* Check if even or odd */
int num = 7;
if (num % 2 == 0) {
printf("%d is even\n", num);
} else {
printf("%d is odd\n", num); // 7 is odd
}
/* Check divisibility */
if (num % 3 == 0) {
printf("%d is divisible by 3\n", num);
} else {
printf("%d is not divisible by 3\n", num);
}
/* Wrap around (cycling) */
int hour = 25; // 25 hours
int day_hour = hour % 24; // Wraps to 1 (1 AM)
printf("%d hours = %d (24-hour format)\n", hour, day_hour);
/* Extract digits */
int number = 1234;
int last_digit = number % 10; // 4
printf("Last digit of %d is %d\n", number, last_digit);
/* Get all digits */
number = 9876;
printf("Digits: ");
while (number > 0) {
printf("%d ", number % 10); // Print last digit
number /= 10; // Remove last digit
}
printf("\n"); // Output: 6 7 8 9 (reversed)
/* Negative modulus (implementation-defined behavior in C89) */
printf("%d %% %d = %d\n", -10, 3, -10 % 3); // Usually -1
printf("%d %% %d = %d\n", 10, -3, 10 % -3); // Usually 1
printf("%d %% %d = %d\n", -10, -3, -10 % -3); // Usually -1Increment and Decrement Operators
The increment (++) and decrement (--) operators increase or decrease a variable's value by 1. They come in two forms: prefix (++x) and postfix (x++). The difference is subtle but important - prefix modifies then returns the new value, while postfix returns the old value then modifies. This affects expressions where the value is used.
/* Increment operators */
int x = 5;
/* Prefix increment: increment first, then use */
int a = ++x; // x becomes 6, a gets 6
printf("x = %d, a = %d\n", x, a); // x = 6, a = 6
/* Postfix increment: use first, then increment */
x = 5;
int b = x++; // b gets 5, then x becomes 6
printf("x = %d, b = %d\n", x, b); // x = 6, b = 5
/* Decrement operators */
x = 5;
/* Prefix decrement */
int c = --x; // x becomes 4, c gets 4
printf("x = %d, c = %d\n", x, c); // x = 4, c = 4
/* Postfix decrement */
x = 5;
int d = x--; // d gets 5, then x becomes 4
printf("x = %d, d = %d\n", x, d); // x = 5, d = 4
/* Standalone usage (no difference) */
x = 5;
x++; // x becomes 6
++x; // x becomes 7
printf("x = %d\n", x); // x = 7
/* Common usage in loops */
for (int i = 0; i < 10; i++) { // Postfix common, but...
printf("%d ", i);
}
printf("\n");
for (int i = 0; i < 10; ++i) { // Prefix slightly more efficient
printf("%d ", i);
}
printf("\n");
/* Complex expression (confusing - avoid!) */
x = 5;
int result = x++ + ++x; // x=5, then x=6, then x=7
// result = 5 + 7 = 12, x = 7
printf("result = %d, x = %d\n", result, x);
/* Better: use separate statements */
x = 5;
int val1 = x;
x++;
x++;
int val2 = x;
result = val1 + val2; // Clear and readableCompound Assignment Operators
Compound assignment operators combine arithmetic operations with assignment. Instead of writing x = x + 5, you can write x += 5. These operators are shorter, clearer, and potentially more efficient. They're syntactic sugar that makes code more concise while maintaining clarity.
/* Compound assignment operators */
int x = 10;
/* Addition assignment */
x += 5; // Equivalent to: x = x + 5
printf("x = %d\n", x); // 15
/* Subtraction assignment */
x -= 3; // Equivalent to: x = x - 3
printf("x = %d\n", x); // 12
/* Multiplication assignment */
x *= 2; // Equivalent to: x = x * 2
printf("x = %d\n", x); // 24
/* Division assignment */
x /= 4; // Equivalent to: x = x / 4
printf("x = %d\n", x); // 6
/* Modulus assignment */
x %= 4; // Equivalent to: x = x % 4
printf("x = %d\n", x); // 2
/* More complex expressions */
int a = 10;
int b = 3;
a += b * 2; // Equivalent to: a = a + (b * 2)
printf("a = %d\n", a); // 16
/* All compound operators */
int n = 100;
n += 10; // n = 110
n -= 5; // n = 105
n *= 2; // n = 210
n /= 3; // n = 70
n %= 7; // n = 0Operator Precedence and Associativity
When an expression contains multiple operators, precedence rules determine evaluation order. Multiplication and division have higher precedence than addition and subtraction, just like in mathematics. Associativity determines order for operators with the same precedence - arithmetic operators are left-to-right associative.
/* Precedence examples */
int result;
result = 2 + 3 * 4; // Multiplication first: 2 + 12 = 14
printf("%d\n", result);
result = (2 + 3) * 4; // Parentheses first: 5 * 4 = 20
printf("%d\n", result);
result = 10 - 5 - 2; // Left-to-right: (10 - 5) - 2 = 3
printf("%d\n", result);
result = 10 / 5 * 2; // Left-to-right: (10 / 5) * 2 = 4
printf("%d\n", result);
/* Precedence hierarchy (highest to lowest) */
// 1. Parentheses ()
// 2. Unary + - (sign), ++ --
// 3. * / %
// 4. + - (addition/subtraction)
// 5. Assignment =, +=, -=, etc.
/* Complex expression */
int x = 5;
result = x * 2 + 10 / 2 - 1;
// Step 1: x * 2 = 10
// Step 2: 10 / 2 = 5
// Step 3: 10 + 5 = 15
// Step 4: 15 - 1 = 14
printf("%d\n", result);
/* Use parentheses for clarity */
result = (x * 2) + (10 / 2) - 1; // Same result, much clearer
printf("%d\n", result);
/* Assignment has low precedence */
int a, b;
a = b = 5; // Right-to-left: b=5, then a=5
printf("a=%d, b=%d\n", a, b);Common Pitfalls and Best Practices
Arithmetic operations can produce unexpected results due to overflow, truncation, and type conversions. Understanding these edge cases helps you write robust code that handles all possible inputs correctly.
/* Pitfall 1: Integer overflow */
int large = 2147483647; // Maximum int value
int overflow = large + 1; // Wraps around (undefined for signed!)
printf("Overflow: %d\n", overflow); // Typically -2147483648
/* Pitfall 2: Integer division truncation */
double avg = 5 / 2; // Integer division first! Result: 2.0
printf("Wrong: %.2f\n", avg);
double correct_avg = 5.0 / 2; // Correct: 2.50
printf("Correct: %.2f\n", correct_avg);
/* Pitfall 3: Division by zero */
int x = 10;
int y = 0;
// int result = x / y; // CRASH: undefined behavior
// Always check before dividing:
if (y != 0) {
int result = x / y;
printf("%d\n", result);
} else {
printf("Error: Division by zero\n");
}
/* Pitfall 4: Modulus with zero */
// int r = x % 0; // CRASH: undefined behavior
/* Pitfall 5: Floating-point precision */
double a = 0.1 + 0.2;
if (a == 0.3) { // May be false due to rounding!
printf("Equal\n");
} else {
printf("Not equal: %.20f\n", a); // 0.30000000000000004441
}
/* Best practices */
// 1. Use parentheses for clarity
int result = (a + b) * (c - d); // Clear intention
// 2. Cast when mixing types
double ratio = (double)numerator / denominator;
// 3. Check for division by zero
if (denominator != 0) {
result = numerator / denominator;
}
// 4. Use appropriate types
double precise = 1.0 / 3.0; // Use double for precision
int whole = 10 / 3; // Use int when truncation desired
// 5. Be aware of overflow
long long big_result = (long long)big_num1 * big_num2;Summary & What's Next
Key Takeaways:
- ✅ Five arithmetic operators: +, -, *, /, %
- ✅ Integer division truncates: 10 / 3 = 3
- ✅ Modulus (%) gives remainder, works with integers only
- ✅ Increment/decrement: prefix (++x) vs postfix (x++)
- ✅ Compound assignment: +=, -=, *=, /=, %=
- ✅ Precedence: * / % before + -
- ✅ Cast to double for precise division
- ✅ Always check for division by zero