C ProgrammingUnit 311 min read
Operators & Expressions: Types, Precedence, Side Effects & Real-World Math
Unit 3 of C Programming covers arithmetic/logical operators, operator precedence, expressions, type casting, and side effects with visual traces of how they work in memory and code—linked to real systems like eSewa’s transaction math and Ncell’s billing calculations.
TAKEAWAYS:
- Arithmetic operators (
+,-,*,/,%) perform math but can overflow or truncate; logical operators (&&,||,!) evaluate to 1/0 and short-circuit. - Operator precedence and associativity determine evaluation order—always parenthesize to avoid surprises (e.g.,
a = b + c * d≠a = (b + c) * d). - Type casting forces conversions (e.g.,
(float)5/2→2.5), but implicit casting can lose precision (e.g.,int/float→int). - Side effects (e.g.,
i++vs++i) and expressions (combinations of operators/operands) are the building blocks of all C logic. - Bitwise operators (
&,|,^,<<,>>) manipulate individual bits—critical for low-level tasks like network packet headers or file compression. - Expressions evaluate left-to-right unless parentheses or precedence rules dictate otherwise; tracing variable states step-by-step reveals bugs.
---
### **1. Arithmetic Operators: Math in C (and Why It Breaks)**
Arithmetic operators perform basic math, but C’s strict typing and integer division can cause unexpected results. Here’s how they work:
```mermaid
flowchart TD
A["a = 5; b = 2;"] --> B["a + b → 7"]
A --> C["a - b → 3"]
A --> D["a * b → 10"]
A --> E["a / b → 2 (integer division)"]
A --> F["a % b → 1 (remainder)"]
Key Rules:
- Division (
/) truncates toward zero. For5 / 2, result is2(not2.5). - Modulus (
%) returns the remainder.5 % 2=1, but(-5) % 2=-1(sign follows dividend). - Overflow: Adding two large
ints (e.g.,INT_MAX + 1) wraps around toINT_MIN. Uselong longfor safety.
Worked Example: eSewa Transaction Fee Calculation eSewa charges a 2% fee on top-ups. If a user sends NPR 5000, the fee is calculated as:
float amount = 5000.0;
float fee = (amount * 2) / 100; // 100.00
float total = amount + fee; // 5100.00
Trace Table:
| Step | amount |
fee |
total |
|---|---|---|---|
| Start | 5000.0 | 0.0 | 0.0 |
fee = ... |
5000.0 | 100.0 | 0.0 |
total = ... |
5000.0 | 100.0 | 5100.0 |
Why This Matters:
- Using
intforamountwould truncate the fee to0(integer division). - Always use
floatordoublefor monetary calculations.
2. Logical Operators: Boolean Logic in Code
Logical operators (&&, ||, !) evaluate expressions to 1 (true) or 0 (false). They short-circuit:
&&: Stops if left operand is0.||: Stops if left operand is1.
flowchart TD
A["x = 5; y = 0;"] --> B["x && y → 0 (short-circuits)"]
A --> C["x || y → 1 (no short-circuit)"]
A --> D["!x → 0"]Worked Example: Ncell Bill Validation
Ncell checks if a user’s balance (balance) is ≥ min_balance and their plan is active (is_active):
int balance = 1000;
int min_balance = 500;
int is_active = 1;
int can_use = (balance >= min_balance) && is_active; // 1 (true)
Trace Table:
| Condition | Value | Result |
|---|---|---|
balance >= min_balance |
1 | 1 |
is_active |
1 | 1 |
can_use = 1 && 1 |
- | 1 |
Short-Circuiting in Action:
int a = 5, b = 0;
int result = (a > 0) && (b++ > 0); // b remains 0 (not incremented)
Here, b++ is never evaluated because a > 0 is already 1.
3. Operator Precedence: The Hidden Rules
C evaluates operators in a fixed order. Parentheses override precedence.
flowchart TD
A["a = 5; b = 2; c = 3;"] --> B["a + b * c → 11 (b*c first)"]
A --> C["(a + b) * c → 21 (parentheses first)"]
A --> D["a = b = c → 3 (right-to-left)"]Precedence Table (Highest to Lowest):
| Category | Operators | Example |
|---|---|---|
| Postfix | (), [], ++, -- |
x++ |
| Unary | +, -, !, (type) |
!x, (int)3.5 |
| Multiplicative | *, /, % |
a * b % c |
| Additive | +, - |
a + b - c |
| Shift | <<, >> |
a << 2 |
| Relational | <, >, <=, >= |
a > b |
| Equality | ==, != |
a == b |
| Logical AND | && |
a && b |
| Logical OR | ` | |
| Ternary | ? : |
a > b ? x : y |
| Assignment | =, +=, -=, etc. |
a += b |
Common Pitfall:
int x = 10;
int y = x++ + ++x; // Undefined behavior!
Why?
x++uses the old value (10) but incrementsxto11.++xincrementsxagain to12and uses12.- Result:
y = 10 + 12 = 22(but compiler may optimize differently).
4. Type Casting: Forcing Conversions
C implicitly converts types (e.g., int to float), but explicit casting ((type)value) gives control.
flowchart TD
A["int a = 5; float b = 2.5;"] --> B["a + b → 7.5 (implicit)"]
A --> C["(int)(a + b) → 7 (explicit truncation)"]
A --> D["(float)a / b → 2.0 (avoids integer division)"]Worked Example: Daraz Discount Calculation Daraz offers a 15% discount on orders ≥ NPR 1000. For an order of NPR 1200:
int order = 1200;
float discount = (order >= 1000) ? (order * 0.15) : 0;
float final_price = order - discount; // 1020.00
Trace Table:
| Step | discount |
final_price |
|---|---|---|
order * 0.15 |
180.0 | - |
order - discount |
180.0 | 1020.0 |
Key Point:
- Without
(float),order * 0.15would truncate to0(integer division).
5. Bitwise Operators: Low-Level Control
Bitwise operators manipulate individual bits. Used in:
- Network protocols (packet flags)
- File compression
- Hardware registers
flowchart TD
A["int a = 5; (0101)"]
A --> B["a & 3 → 1 (0101 & 0011 = 0001)"]
A --> C["a | 2 → 7 (0101 | 0010 = 0111)"]
A --> D["a << 1 → 10 (0101 << 1 = 1010)"]
A --> E["a >> 1 → 2 (0101 >> 1 = 0010)"]Worked Example: NTC Traffic Light Control
NTC uses bitwise flags to control traffic lights. A status variable encodes:
- Bit 0: Red light (
1= on) - Bit 1: Yellow light
- Bit 2: Green light
int status = 0b001; // Green light on (001)
status |= 0b010; // Turn on yellow (001 | 010 = 011)
status &= ~(0b001); // Turn off green (011 & 110 = 010)
Trace Table:
| Operation | status (binary) |
Meaning |
|---|---|---|
| Start | 001 |
Green on |
| `status | = 010` | 011 |
status &= 110 |
010 |
Yellow only |
6. Side Effects and Expressions
An expression combines operators/operands to produce a value. Side effects modify state (e.g., i++ changes i).
flowchart TD
A["int i = 5;"] --> B["i++ → 5 (post-increment)"]
A --> C["++i → 6 (pre-increment)"]
A --> D["i += 2 → 7 (compound assignment)"]Worked Example: Kathmandu Traffic Route Optimization A traffic system uses a loop to count cars passing a checkpoint:
int count = 0;
while (sensors[0].detect()) {
count++; // Side effect: increments count
}
Trace Table:
| Iteration | count |
sensors[0].detect() |
Action |
|---|---|---|---|
| 1 | 0 | 1 (true) | count++ → 1 |
| 2 | 1 | 1 (true) | count++ → 2 |
| 3 | 2 | 0 (false) | Exit loop |
Key Difference:
count++returns the old value (5) but increments afterward.++countincrements first, then returns the new value (6).
7. Common Operator Pitfalls
| Pitfall | Example | Fix |
|---|---|---|
| Integer division truncation | 5 / 2 → 2 |
Use (float)5 / 2 |
| Unintended short-circuiting | a && b++ |
Parenthesize: (a) && (b++) |
| Bitwise vs logical operators | a & b vs a && b |
&& works on booleans only |
| Overflow in arithmetic | INT_MAX + 1 |
Use long long |
| Undefined behavior in mixed ops | a = b = c = 5 |
Assign sequentially |
In the Real World
eSewa Transaction Math
- Idea Used: Arithmetic operators and type casting.
- How? eSewa calculates fees, deductions, and final amounts using
floatto avoid truncation (e.g.,(amount * fee_rate)). Implicit casting tointwould lose cents.
Ncell Billing System
- Idea Used: Logical operators (
&&,||) and short-circuiting. - How? Ncell checks if a user can make a call by verifying:
Ifcan_call = (balance >= min_balance) && (is_active) && (roaming_off);balanceis insufficient, the other checks are skipped (short-circuiting saves computation).
- Idea Used: Logical operators (
Daraz Order Processing Queue
- Idea Used: Compound assignment (
+=,-=) and expressions. - How? Daraz updates inventory counts using:
This ensures real-time stock updates without manual recalculations.inventory[id] -= quantity; // Side effect: modifies inventory
- Idea Used: Compound assignment (
Exam Tip
Always Parenthesize:
- Write
(a + b) * cinstead ofa + b * cto avoid precedence errors. - Exam Question: "What is the output of
printf("%d", 5 + 2 * 3)?" Answer:11(not21). Parentheses change the result.
- Write
Trace Step-by-Step:
- For questions like "What is the value of
xafterx = 10; x = x++ + ++x;?", draw a table:Step x(old)x(new)Operation Start 10 - - x++10 11 Post-increment ++x11 12 Pre-increment x = ...- 22 10 + 12 - Answer:
22(but note: this is undefined behavior in C; compilers may optimize differently).
- For questions like "What is the value of
Watch for Type Casting:
- Exam Question: "Why does
printf("%d", 5 / 2)print2instead of2.5?" Answer: Integer division truncates. Use(float)5 / 2to get2.5.
- Exam Question: "Why does
Bitwise Operators in Flags:
- Exam Question: "How would you toggle the 3rd bit of
0b1010?" Answer:0b1010 ^ 0b0100 = 0b1110(XOR flips the bit).
- Exam Question: "How would you toggle the 3rd bit of
Side Effects in Loops:
- Exam Question: "What does this loop print?"
Trace:for (int i = 0; i < 3; i++) printf("%d ", i++);Iteration i(old)i(new)Printed 1 0 1 0 2 1 2 1 3 2 3 2 Answer: 0 1 2(butibecomes3after the loop).
- Exam Question: "What does this loop print?"
Final Advice:
- Memorize precedence (or use a cheat sheet during exams).
- Always test edge cases (e.g.,
0, negative numbers, overflow). - Draw tables for complex expressions—examiners love step-by-step reasoning.
Based on the TU BIM syllabus for C Programming (IT232), unit 3.
Discussion
Loading…