Module 2.1

C Operators

Operators are the building blocks of any computation in C. Learn how to perform calculations, compare values, combine conditions, and manipulate data at the bit level. Master these tools to write powerful and efficient programs!

40 min read
Beginner
Hands-on Examples
What You'll Learn
  • Arithmetic operators (+, -, *, /, %)
  • Relational and comparison operators
  • Logical operators (&&, ||, !)
  • Bitwise operators for low-level control
  • Operator precedence and associativity
Contents
01

Introduction to Operators

Operators are special symbols that tell the compiler to perform specific mathematical, relational, or logical operations. Think of them as the "verbs" of programming - they describe the actions you want to perform on your data.

Beginner Tip: You already know many operators from basic math! The + sign adds numbers, - subtracts them. In C, we use these same symbols plus many more powerful ones.

What is an Operator?

An operator is a symbol that operates on one or more values (called operands) to produce a result. Operators are the tools you use to manipulate data in your programs.

In the expression 5 + 3, the + is the operator and 5 and 3 are the operands.

Categories of C Operators

C provides a rich set of operators organized into several categories:

Arithmetic

Math operations

+ - * / %
Relational

Compare values

== != < > <= >=
Logical

Combine conditions

&& || !
Bitwise

Bit manipulation

& | ^ ~ << >>
Assignment

Assign values

= += -= *= /=
Special

Other operations

?: sizeof & *

Unary, Binary, and Ternary Operators

Operators are also classified by how many operands they work with:

Type Operands Example Explanation
Unary 1 -x, ++i, !flag Works on a single value
Binary 2 a + b, x > y Works on two values
Ternary 3 a ? b : c Conditional operator (only one in C)
#include <stdio.h>

int main() {
    int x = 5;
    
    // Unary operators (1 operand)
    int negative = -x;      // Negation: -5
    x++;                    // Increment: x becomes 6
    
    // Binary operators (2 operands)
    int sum = 10 + 20;      // Addition: 30
    int isGreater = x > 3;  // Comparison: 1 (true)
    
    // Ternary operator (3 operands)
    int max = (x > 10) ? x : 10;  // Returns 10 (since 6 is not > 10)
    
    printf("negative: %d, sum: %d, max: %d\n", negative, sum, max);
    return 0;
}
02

Arithmetic Operators

Arithmetic operators perform mathematical calculations. These are the most commonly used operators and include addition, subtraction, multiplication, division, and the modulus (remainder) operation.

Beginner Tip: The modulus operator % might be new to you. It gives the remainder after division. For example, 7 % 3 equals 1 because 7 divided by 3 is 2 with remainder 1.

Basic Arithmetic Operators

Operator Name Example Result Description
+ Addition 10 + 3 13 Adds two operands
- Subtraction 10 - 3 7 Subtracts second from first
* Multiplication 10 * 3 30 Multiplies operands
/ Division 10 / 3 3 Divides (integer truncates)
% Modulus 10 % 3 1 Remainder after division
#include <stdio.h>

int main() {
    int a = 17, b = 5;
    
    printf("a = %d, b = %d\n\n", a, b);
    
    printf("Addition:       a + b = %d\n", a + b);    // 22
    printf("Subtraction:    a - b = %d\n", a - b);    // 12
    printf("Multiplication: a * b = %d\n", a * b);    // 85
    printf("Division:       a / b = %d\n", a / b);    // 3 (integer division)
    printf("Modulus:        a %% b = %d\n", a % b);   // 2 (remainder)
    
    return 0;
}

Integer vs Floating-Point Division

A common source of bugs! Division behaves differently depending on the operand types:

Integer Division (Truncates)
int result = 7 / 2;    // result = 3, NOT 3.5!
int result2 = 1 / 2;   // result2 = 0, NOT 0.5!

When both operands are integers, the decimal part is discarded.

Float Division (Preserves Decimals)
float result = 7.0 / 2;     // result = 3.5
float result2 = 7 / 2.0;    // result2 = 3.5
float result3 = (float)7/2; // result3 = 3.5

At least one operand must be float/double for decimal result.

Increment (++) and Decrement (--)

These unary operators increase or decrease a value by 1. They come in two forms:

Pre-increment/decrement
int x = 5;
int y = ++x;  // x becomes 6 FIRST, then y = 6
// x = 6, y = 6

Value changes BEFORE it's used in the expression.

Post-increment/decrement
int x = 5;
int y = x++;  // y = 5 (old value), THEN x becomes 6
// x = 6, y = 5

Value changes AFTER it's used in the expression.

#include <stdio.h>

int main() {
    int a = 5, b = 5;
    
    printf("Initial: a = %d, b = %d\n\n", a, b);
    
    // Pre-increment: increment first, then use
    printf("++a = %d\n", ++a);  // Prints 6, a is now 6
    printf("After ++a: a = %d\n\n", a);
    
    // Post-increment: use first, then increment
    printf("b++ = %d\n", b++);  // Prints 5, b becomes 6 after
    printf("After b++: b = %d\n\n", b);
    
    // Same logic applies to decrement (--)
    int c = 10;
    printf("--c = %d\n", --c);  // Prints 9
    printf("c-- = %d\n", c--);  // Prints 9, c becomes 8
    printf("Final c = %d\n", c); // Prints 8
    
    return 0;
}

Practical Uses of Modulus (%)

The modulus operator has many practical applications:

#include <stdio.h>

int main() {
    // 1. Check if a number is even or odd
    int num = 17;
    if (num % 2 == 0) {
        printf("%d is even\n", num);
    } else {
        printf("%d is odd\n", num);  // This prints
    }
    
    // 2. Extract digits from a number
    int number = 1234;
    int lastDigit = number % 10;     // 4
    int lastTwo = number % 100;      // 34
    printf("Last digit of %d: %d\n", number, lastDigit);
    
    // 3. Wrap around (circular behavior)
    // Useful for arrays, clocks, games
    int hours = 25 % 24;  // 1 (25 hours wraps to 1:00)
    int index = 7 % 5;    // 2 (index wraps in array of size 5)
    printf("25 hours = %d o'clock\n", hours);
    
    // 4. Check divisibility
    int year = 2024;
    if (year % 4 == 0) {
        printf("%d is divisible by 4\n", year);
    }
    
    return 0;
}
Warning: Division by zero causes undefined behavior in C. Always check that your divisor is not zero before dividing!
03

Relational Operators

Relational operators compare two values and return a boolean result (1 for true, 0 for false). They are essential for making decisions in your programs using conditions like if statements and loops.

Beginner Tip: In C, there is no dedicated boolean type (until C99). Instead, 0 means false and any non-zero value (typically 1) means true. Relational operators always return 0 or 1.

What is a Relational Operator?

A relational operator compares two operands and determines the relationship between them (equal, not equal, greater than, less than, etc.). The result is always 1 (true) or 0 (false).

Be careful: = is assignment, == is comparison. This is a very common source of bugs!

Relational Operators Table

Operator Name Example Result Description
== Equal to 5 == 5 1 (true) True if operands are equal
!= Not equal to 5 != 3 1 (true) True if operands are different
> Greater than 5 > 3 1 (true) True if left is greater
< Less than 5 < 3 0 (false) True if left is smaller
>= Greater or equal 5 >= 5 1 (true) True if left is greater or equal
<= Less or equal 5 <= 3 0 (false) True if left is smaller or equal
#include <stdio.h>

int main() {
    int a = 10, b = 20, c = 10;
    
    printf("a = %d, b = %d, c = %d\n\n", a, b, c);
    
    printf("a == b: %d\n", a == b);  // 0 (false)
    printf("a == c: %d\n", a == c);  // 1 (true)
    printf("a != b: %d\n", a != b);  // 1 (true)
    printf("a > b:  %d\n", a > b);   // 0 (false)
    printf("a < b:  %d\n", a < b);   // 1 (true)
    printf("a >= c: %d\n", a >= c);  // 1 (true)
    printf("b <= a: %d\n", b <= a);  // 0 (false)
    
    return 0;
}

Using Relational Operators in Conditions

Let's see how relational operators power decision-making in real programs:

Simple Condition Check
int age = 18;

// Simple condition - checking a single requirement
if (age >= 18) {
    printf("You are an adult.\n");
}
Basic If Statement: The simplest use of relational operators is checking a single condition. Here we use >= (greater than or equal) to verify if someone meets the minimum age requirement. This pattern is the foundation of all conditional logic - compare a value against a threshold and execute code only when the condition is true.
Checking Multiple Ranges (Grade Calculator)
int score = 85;

// Checking ranges with else-if chain
if (score >= 90) {
    printf("Grade: A\n");
} else if (score >= 80) {
    printf("Grade: B\n");  // This prints (85 >= 80)
} else if (score >= 70) {
    printf("Grade: C\n");
} else {
    printf("Grade: F\n");
}
Else-If Chain: When you need to categorize values into multiple ranges, use an else-if chain. The conditions are checked top-to-bottom, and only the FIRST true condition executes. Notice we only need >= checks because the else-if structure already guarantees the value didn't match previous conditions. This is the classic pattern for grading systems, tax brackets, and tier-based pricing.
Checking Exact Values and Boundaries
float temperature = 37.5;

// Checking equality and greater-than
if (temperature == 37.0) {
    printf("Normal temperature\n");
} else if (temperature > 37.0) {
    printf("Slight fever\n");  // This prints (37.5 > 37.0)
}
Equality vs Comparison: Use == to check for exact matches and > or < for boundary checks. Be cautious when comparing floating-point numbers with == - due to precision issues, it's often better to check if values are within a small range. For critical applications, use a tolerance: if (fabs(temp - 37.0) < 0.01) instead of exact equality.
Complete Program Structure
#include <stdio.h>

int main() {
    int age = 18;
    int score = 85;
    float temperature = 37.5;
    
    // Your conditional logic goes here...
    
    return 0;
}
Program Template: Every C program needs the proper structure - include headers at the top, declare variables with appropriate types, write your conditional logic, and return 0 to indicate successful execution. Always choose the right data type: int for whole numbers like age and score, float or double for decimal values like temperature.

Common Mistake: = vs ==

Wrong (Assignment)
int x = 5;
if (x = 10) {  // WRONG! This assigns 10 to x
    // Always executes because x=10 evaluates to 10 (true)
    printf("This always runs!\n");
}
Correct (Comparison)
int x = 5;
if (x == 10) {  // Correct! Compares x to 10
    printf("x is 10\n");
} else {
    printf("x is not 10\n");  // This prints
}
Pro Tip: Some programmers write if (10 == x) instead of if (x == 10). If you accidentally use =, the compiler will error because you can't assign to a constant!
04

Logical Operators

Logical operators combine multiple conditions to form more complex expressions. They work with boolean values (true/false) and are essential for creating sophisticated decision-making logic in your programs.

Beginner Tip: Think of logical operators like everyday language. "If it's sunny AND warm, go outside" requires BOTH conditions. "If it's Saturday OR Sunday, sleep in" requires at least ONE condition.

What is a Logical Operator?

A logical operator performs boolean logic on one or more conditions, returning true (1) or false (0). They let you combine simple conditions into complex ones.

C uses && for AND, || for OR, and ! for NOT. Don't confuse with bitwise & and |!

Logical Operators

Operator Name Description Example Result
&& Logical AND True if BOTH operands are true (5 > 3) && (8 > 5) 1 (true)
|| Logical OR True if AT LEAST ONE is true (5 > 3) || (8 < 5) 1 (true)
! Logical NOT Inverts the boolean value !(5 > 3) 0 (false)

Truth Tables

AND (&&)
ABA && B
000
010
100
111

Both must be true

OR (||)
ABA || B
000
011
101
111

At least one true

NOT (!)
A!A
01
10

Flips the value

Practical Examples

Let's see logical operators in action with real-world scenarios:

AND (&&) - All Conditions Must Be True
int age = 25;
int hasLicense = 1;  // 1 = true
int isSober = 1;

// All three conditions must be true to drive
if (age >= 18 && hasLicense && isSober) {
    printf("You can drive!\n");  // This prints
}
Real-World: To legally drive, you need to be 18+, have a license, AND be sober. The && operator returns true only when ALL conditions are true. If even ONE condition is false (underage, no license, or intoxicated), the entire expression becomes false. Think of it as a chain where every link must be strong - one weak link breaks the whole chain.
OR (||) - At Least One Must Be True
int isWeekend = 0;   // 0 = false (it's a weekday)
int isHoliday = 0;

// Either weekend OR holiday means day off
if (isWeekend || isHoliday) {
    printf("You have a day off!\n");
} else {
    printf("It's a work day\n");  // This prints
}
Real-World: You get a day off if it's a weekend OR a holiday - either one being true is enough. The || operator returns true if AT LEAST ONE condition is true. It only returns false when ALL conditions are false. Think of it as having multiple doors to enter - you only need one open door to get in. Use OR when you have alternative ways to satisfy a requirement.
NOT (!) - Inverts the Condition
int isRaining = 0;  // 0 = false (not raining)

// NOT raining means good weather
if (!isRaining) {
    printf("Great weather for outdoor activities!\n");  // This prints
}
Real-World: The NOT operator ! flips the boolean value - it turns true into false and false into true. Sometimes it's more natural to check the opposite condition. Instead of tracking isSunny, you might track isRaining and use !isRaining to check for good weather. This is especially useful when the "negative" condition is easier to detect or more commonly stored.
Combining Multiple Operators
int temperature = 25;
int isRaining = 0;

// Good weather: temperature between 20-30 AND not raining
if ((temperature > 20 && temperature < 30) && !isRaining) {
    printf("Perfect weather for a walk!\n");  // This prints
}
Tip: When combining multiple operators, use parentheses () to group conditions clearly and control evaluation order. Here we first check if temperature is in the comfortable range (20-30) using AND, then combine that with NOT raining. Without parentheses, operator precedence rules apply, which can lead to unexpected results. Always parenthesize complex conditions for clarity and correctness.
Range Checking Pattern
int score = 85;

// Check if score is in the B grade range (80-89)
if (score >= 80 && score < 90) {
    printf("Grade: B\n");  // This prints
}

// Common pattern for multiple ranges
if (score >= 90) printf("Grade: A\n");
else if (score >= 80) printf("Grade: B\n");
else if (score >= 70) printf("Grade: C\n");
else printf("Grade: F\n");
Common Pattern: Range checking is one of the most common uses of logical AND. To check if a value falls within a range, you need TWO conditions: value >= min && value < max. This pattern appears everywhere in programming - grade calculations, age group categorization, price tiers, input validation, and array bounds checking. Master this pattern as you'll use it constantly!

Short-Circuit Evaluation

C uses "short-circuit" evaluation for logical operators, which can affect performance and behavior:

AND (&&) Short-Circuit

If the first operand is false, the second is NOT evaluated (result is already false).

int x = 0;
// Second condition never checked
if (x != 0 && 10/x > 2) {
    // Safe! No division by zero
}
OR (||) Short-Circuit

If the first operand is true, the second is NOT evaluated (result is already true).

int valid = 1;
// Second condition never checked
if (valid || expensiveCheck()) {
    // expensiveCheck() not called
}
05

Bitwise Operators

Bitwise operators work at the binary level, manipulating individual bits of data. They are powerful tools for low-level programming, embedded systems, graphics, and performance optimization.

Beginner Tip: Every number in a computer is stored as binary (1s and 0s). The number 5 is stored as 0101, and 3 is 0011. Bitwise operators let you manipulate these individual bits directly!

What is a Bitwise Operator?

A bitwise operator performs operations on the binary representation of numbers, manipulating each bit independently. They treat operands as a sequence of 32 or 64 bits.

Don't confuse & (bitwise AND) with && (logical AND), or | (bitwise OR) with || (logical OR)!

Bitwise Operators

Operator Name Description Example (5 & 3)
& AND 1 if both bits are 1 0101 & 0011 = 0001 (1)
| OR 1 if at least one bit is 1 0101 | 0011 = 0111 (7)
^ XOR 1 if bits are different 0101 ^ 0011 = 0110 (6)
~ NOT Inverts all bits ~0101 = 1010 (-6 in 2's complement)
<< Left Shift Shifts bits left, fills with 0 0101 << 1 = 1010 (10)
>> Right Shift Shifts bits right 0101 >> 1 = 0010 (2)

Bitwise Operations in Action

Let's see each bitwise operator working on binary numbers step by step:

Setting Up Binary Values
unsigned int a = 5;   // Binary: 0101
unsigned int b = 3;   // Binary: 0011

printf("a = %u (binary: 0101)\n", a);
printf("b = %u (binary: 0011)\n\n", b);
Binary Representation: To understand bitwise operations, you need to think in binary. The number 5 in binary is 0101 (4+1) and 3 is 0011 (2+1). We use unsigned int to avoid complications with negative numbers. Each bit position represents a power of 2: from right to left, that's 1, 2, 4, 8, and so on.
Bitwise AND (&) - Both Bits Must Be 1
// Bitwise AND: both bits must be 1
printf("a & b  = %u\n", a & b);   // 0101 & 0011 = 0001 = 1

//   0101 (5)
// & 0011 (3)
// --------
//   0001 (1)
AND Operation: The AND operator compares each bit position - if BOTH bits are 1, the result bit is 1; otherwise it's 0. Think of it as a filter or mask. In our example, only position 0 has 1 in both numbers, so the result is 1. AND is commonly used to extract specific bits, check flags, and clear unwanted bits from a value.
Bitwise OR (|) - Either Bit Can Be 1
// Bitwise OR: at least one bit must be 1
printf("a | b  = %u\n", a | b);   // 0101 | 0011 = 0111 = 7

//   0101 (5)
// | 0011 (3)
// --------
//   0111 (7)
OR Operation: The OR operator sets the result bit to 1 if EITHER or BOTH input bits are 1. It combines the "on" bits from both numbers. In our example, positions 0, 1, and 2 all have at least one 1, giving us 0111 = 7. OR is perfect for setting specific bits to 1, combining flags, or merging bit patterns together.
Bitwise XOR (^) - Bits Must Be Different
// Bitwise XOR: bits must be different
printf("a ^ b  = %u\n", a ^ b);   // 0101 ^ 0011 = 0110 = 6

//   0101 (5)
// ^ 0011 (3)
// --------
//   0110 (6)
XOR Operation: XOR (exclusive OR) returns 1 only when the bits are DIFFERENT. If both bits are the same (both 0 or both 1), the result is 0. Notice position 0 has 1 in both, so result is 0. XOR has amazing properties: a ^ a = 0 and a ^ 0 = a. This makes it perfect for toggling bits, simple encryption, and swapping values without a temp variable.
Bitwise NOT (~) - Flip All Bits
// Bitwise NOT (complement)
printf("~a     = %d\n", ~a);      // Inverts all bits = -6

// ~0000...0101 = 1111...1010 = -6 (in 2's complement)
NOT Operation: The NOT operator flips every single bit - all 0s become 1s and all 1s become 0s. Since integers use all 32 (or 64) bits, flipping 5 gives a large negative number in two's complement representation (-6). NOT is useful for creating bit masks, finding the complement of a number, and in combination with AND to clear specific bits.
Left Shift (<<) - Multiply by Powers of 2
// Left shift (multiply by 2^n)
printf("a << 1 = %u\n", a << 1);  // 0101 << 1 = 1010 = 10
printf("a << 2 = %u\n", a << 2);  // 0101 << 2 = 10100 = 20

// 0101 << 1 = 1010  (5 * 2 = 10)
// 0101 << 2 = 10100 (5 * 4 = 20)
Left Shift: Shifting left moves all bits toward the left by n positions, filling empty positions on the right with 0s. Each shift LEFT multiplies by 2! So a << 1 is a * 2, and a << 3 is a * 8. This is much faster than multiplication because it's a single CPU instruction. Use it for quick multiplication by powers of 2.
Right Shift (>>) - Divide by Powers of 2
// Right shift (divide by 2^n)
printf("a >> 1 = %u\n", a >> 1);  // 0101 >> 1 = 0010 = 2

// 0101 >> 1 = 0010 (5 / 2 = 2, integer division)
Right Shift: Shifting right moves all bits toward the right by n positions. Each shift RIGHT divides by 2 (integer division, dropping remainders). So 5 >> 1 gives 2 (not 2.5). For unsigned numbers, empty left positions fill with 0s. Right shift is the fastest way to divide by powers of 2 - essential for performance-critical code like graphics rendering and embedded systems.

Practical Applications

#include <stdio.h>

int main() {
    // 1. Check if a number is even or odd (faster than modulus)
    int num = 7;
    if (num & 1) {
        printf("%d is odd\n", num);   // Last bit is 1 = odd
    } else {
        printf("%d is even\n", num);  // Last bit is 0 = even
    }
    
    // 2. Multiply/divide by powers of 2 (very fast)
    int x = 5;
    printf("%d * 4 = %d\n", x, x << 2);   // Left shift by 2 = multiply by 4
    printf("%d / 2 = %d\n", x, x >> 1);   // Right shift by 1 = divide by 2
    
    // 3. Set, clear, and toggle specific bits (flags)
    unsigned char flags = 0;          // 00000000
    
    // Set bit 2 (turn ON)
    flags = flags | (1 << 2);         // 00000100
    printf("After setting bit 2: %d\n", flags);
    
    // Clear bit 2 (turn OFF)
    flags = flags & ~(1 << 2);        // 00000000
    printf("After clearing bit 2: %d\n", flags);
    
    // Toggle bit 3 (flip)
    flags = flags ^ (1 << 3);         // 00001000
    printf("After toggling bit 3: %d\n", flags);
    
    // 4. Swap two numbers without temporary variable
    int p = 10, q = 20;
    printf("Before swap: p=%d, q=%d\n", p, q);
    p = p ^ q;
    q = p ^ q;
    p = p ^ q;
    printf("After swap:  p=%d, q=%d\n", p, q);
    
    return 0;
}
When to Use Bitwise Operators: Embedded systems, device drivers, graphics programming, cryptography, network protocols, and anywhere you need maximum performance or direct hardware control.
06

Assignment Operators

Assignment operators store values in variables. Beyond the basic = operator, C provides compound assignment operators that combine arithmetic or bitwise operations with assignment in a single step.

Beginner Tip: Instead of writing x = x + 5, you can write x += 5. It's shorter, cleaner, and the variable name only needs to be evaluated once (slightly more efficient).

Assignment Operators

Operator Example Equivalent To Description
= x = 5 x = 5 Simple assignment
+= x += 3 x = x + 3 Add and assign
-= x -= 3 x = x - 3 Subtract and assign
*= x *= 3 x = x * 3 Multiply and assign
/= x /= 3 x = x / 3 Divide and assign
%= x %= 3 x = x % 3 Modulus and assign
&= x &= 3 x = x & 3 Bitwise AND and assign
|= x |= 3 x = x | 3 Bitwise OR and assign
^= x ^= 3 x = x ^ 3 Bitwise XOR and assign
<<= x <<= 2 x = x << 2 Left shift and assign
>>= x >>= 2 x = x >> 2 Right shift and assign

Examples

#include <stdio.h>

int main() {
    int x = 10;
    printf("Initial x = %d\n\n", x);
    
    // Arithmetic compound assignments
    x += 5;   // x = x + 5 = 15
    printf("After x += 5:  x = %d\n", x);
    
    x -= 3;   // x = x - 3 = 12
    printf("After x -= 3:  x = %d\n", x);
    
    x *= 2;   // x = x * 2 = 24
    printf("After x *= 2:  x = %d\n", x);
    
    x /= 4;   // x = x / 4 = 6
    printf("After x /= 4:  x = %d\n", x);
    
    x %= 4;   // x = x % 4 = 2
    printf("After x %%= 4: x = %d\n\n", x);
    
    // Bitwise compound assignments
    unsigned int flags = 0b00001111;  // 15 in decimal
    printf("Initial flags = %u\n", flags);
    
    flags &= 0b00000011;  // Keep only last 2 bits
    printf("After flags &= 0b00000011: flags = %u\n", flags);  // 3
    
    flags |= 0b00010000;  // Set bit 4
    printf("After flags |= 0b00010000: flags = %u\n", flags);  // 19
    
    // Shift assignments
    int num = 4;
    num <<= 2;  // Multiply by 4
    printf("4 <<= 2 = %d\n", num);  // 16
    
    num >>= 1;  // Divide by 2
    printf("16 >>= 1 = %d\n", num);  // 8
    
    return 0;
}
07

Operator Precedence and Associativity

When an expression contains multiple operators, precedence rules determine which operations are performed first. Understanding precedence helps you write correct expressions and avoid subtle bugs.

Beginner Tip: Remember PEMDAS from math class? Parentheses, Exponents, Multiplication/Division, Addition/Subtraction. C follows similar rules, but with many more operators. When in doubt, use parentheses to make your intent clear!

Precedence vs Associativity

Precedence determines which operator is evaluated first when different operators appear in an expression. Associativity determines the order when operators have the same precedence (left-to-right or right-to-left).

In 2 + 3 * 4, multiplication has higher precedence, so it's evaluated as 2 + (3 * 4) = 14, not (2 + 3) * 4 = 20.

Operator Precedence (High to Low)

Priority Operators Description Associativity
1 (Highest) () [] -> . Parentheses, array, member access Left to Right
2 ! ~ ++ -- + - * & sizeof Unary operators Right to Left
3 * / % Multiplication, division, modulus Left to Right
4 + - Addition, subtraction Left to Right
5 << >> Bitwise shift Left to Right
6 < <= > >= Relational Left to Right
7 == != Equality Left to Right
8 & Bitwise AND Left to Right
9 ^ Bitwise XOR Left to Right
10 | Bitwise OR Left to Right
11 && Logical AND Left to Right
12 || Logical OR Left to Right
13 ?: Ternary conditional Right to Left
14 = += -= *= /= ... Assignment operators Right to Left
15 (Lowest) , Comma operator Left to Right

Precedence Examples

#include <stdio.h>

int main() {
    // Example 1: Arithmetic precedence
    int result1 = 2 + 3 * 4;        // 2 + 12 = 14 (not 20)
    int result2 = (2 + 3) * 4;      // 5 * 4 = 20 (parentheses override)
    printf("2 + 3 * 4 = %d\n", result1);
    printf("(2 + 3) * 4 = %d\n\n", result2);
    
    // Example 2: Relational vs logical
    int a = 5, b = 3, c = 8;
    // Without parentheses (works due to precedence)
    int test1 = a > b && b < c;     // (a > b) && (b < c) = 1 && 1 = 1
    printf("a > b && b < c = %d\n", test1);
    
    // Example 3: Assignment has low precedence
    int x = 5;
    int y = x + 3;                  // x + 3 is evaluated first, then assigned
    printf("y = x + 3 = %d\n\n", y);
    
    // Example 4: Be careful with bitwise vs comparison
    int n = 5;
    // WRONG: & has lower precedence than ==
    // if (n & 1 == 0)  // Evaluates as n & (1 == 0) = n & 0 = 0
    
    // CORRECT: Use parentheses
    if ((n & 1) == 0) {
        printf("%d is even\n", n);
    } else {
        printf("%d is odd\n", n);   // This prints
    }
    
    // Example 5: Chained assignment (right to left)
    int p, q, r;
    p = q = r = 10;                 // r=10, then q=10, then p=10
    printf("p=%d, q=%d, r=%d\n", p, q, r);
    
    return 0;
}
Best Practice: When in doubt, use parentheses! They make your code clearer and prevent precedence-related bugs. (a + b) * c is clearer than relying on precedence rules.

Key Takeaways

Arithmetic Operators

Use +, -, *, /, % for math. Remember integer division truncates - use floats for decimals

Relational Operators

Compare values with ==, !=, >, <, >=, <=. Returns 1 (true) or 0 (false). Don't confuse = with ==!

Logical Operators

Combine conditions with && (AND), || (OR), ! (NOT). Uses short-circuit evaluation

Bitwise Operators

Manipulate individual bits with &, |, ^, ~, <<, >>. Powerful for low-level programming

Compound Assignment

Use +=, -=, *=, etc. for cleaner code. x += 5 is equivalent to x = x + 5

Precedence Matters

Operators have priority order. When in doubt, use parentheses to make intent clear

Knowledge Check

Quick Quiz

Test what you've learned about C operators

1 What is the result of: 17 % 5?
2 What does the expression (5 > 3) && (8 < 5) evaluate to?
3 What is the result of: 5 << 2?
4 If int x = 5; what is the value of x after: int y = x++;?
5 Which operator has the highest precedence?
6 What is the difference between = and ==?
Answer all questions to check your score