Home C / C++ Operators in C Explained — Types, Examples and Common Mistakes

Operators in C Explained — Types, Examples and Common Mistakes

In Plain English 🔥
Think of operators like the buttons on a calculator. The numbers are your data, and the buttons (+, -, ×, ÷) tell the calculator WHAT TO DO with those numbers. In C, operators are the symbols that tell your program how to work with values — add them, compare them, combine them, or flip them. Without operators, your program would just be a list of numbers sitting there doing nothing.
⚡ Quick Answer
Think of operators like the buttons on a calculator. The numbers are your data, and the buttons (+, -, ×, ÷) tell the calculator WHAT TO DO with those numbers. In C, operators are the symbols that tell your program how to work with values — add them, compare them, combine them, or flip them. Without operators, your program would just be a list of numbers sitting there doing nothing.

Every useful program on the planet — from a banking app calculating your balance to a game engine deciding if a bullet hit a target — makes decisions and performs calculations. None of that is possible without operators. They are the verbs of your code. If variables are the nouns (the things), operators are the actions performed on those things. Understanding them deeply isn't optional — it's the foundation everything else is built on.

Before operators existed in programming languages, writing even simple math required multiple low-level machine instructions. C gave programmers a concise, expressive set of symbols that map closely to what the hardware actually does — which is why C is still used in embedded systems, operating systems, and performance-critical software today. Operators solve the problem of expressing computation, comparison, and logic in a way that's both human-readable and highly efficient.

By the end of this article you'll know every major category of C operator, understand exactly what each one does and why it exists, be able to read real C code without getting tripped up by symbols like >>= or !=, and you'll know the two most common operator mistakes beginners make — so you can avoid them from day one.

Arithmetic Operators — Your Program's Built-In Calculator

Arithmetic operators do exactly what the name suggests: math. C gives you six of them — addition (+), subtraction (-), multiplication (*), division (/), modulus (%), and unary negation (-). You already know the first four from school. The one that surprises beginners is modulus.

Modulus (%) gives you the REMAINDER after division. So 10 % 3 gives you 1, because 10 divided by 3 is 3 with 1 left over. This is incredibly useful in real code — use it to check if a number is even or odd, to wrap a value around a range (like keeping a game character on screen), or to cycle through array indices.

One critical thing to understand: when you divide two integers in C, you get integer division. That means 7 / 2 gives you 3, not 3.5. The decimal part is thrown away — not rounded, just discarded. This catches virtually every beginner at least once. If you need the decimal result, at least one of the operands must be a float or double.

arithmetic_operators.c · C
12345678910111213141516171819202122232425262728293031323334353637
#include <stdio.h>

int main() {
    int apples = 17;
    int children = 5;

    // Basic arithmetic
    int total_after_buying_more = apples + 8;   // addition
    int eaten = apples - 3;                      // subtraction
    int doubled = apples * 2;                    // multiplication

    // Integer division: the decimal part is SILENTLY dropped
    int each_child_gets = apples / children;     // 17 / 5 = 3 (not 3.4)

    // Modulus: gives the leftover after division
    int leftover_apples = apples % children;     // 17 % 5 = 2

    printf("Apples after buying more: %d\n", total_after_buying_more);
    printf("Apples after eating 3: %d\n", eaten);
    printf("Apples if we doubled: %d\n", doubled);
    printf("Each child gets: %d apples\n", each_child_gets);
    printf("Leftover apples: %d\n", leftover_apples);

    // To get the decimal result, use float
    float precise_share = (float)apples / children;  // cast one to float
    printf("Precise share per child: %.2f apples\n", precise_share);

    // Checking even/odd with modulus — a classic use case
    int mystery_number = 42;
    if (mystery_number % 2 == 0) {
        printf("%d is even\n", mystery_number);  // remainder 0 means even
    } else {
        printf("%d is odd\n", mystery_number);
    }

    return 0;
}
▶ Output
Apples after buying more: 25
Apples after eating 3: 14
Apples if we doubled: 34
Each child gets: 3 apples
Leftover apples: 2
Precise share per child: 3.40 apples
42 is even
⚠️
Watch Out: Integer Division Silently Drops Decimals7 / 2 in C gives 3, not 3.5. There's no error, no warning — your program just quietly gives you the wrong answer. If you need decimal precision, write (float)7 / 2 or make one of your variables a float. This silent truncation is one of the most common bugs in beginner C programs.

Relational and Logical Operators — Teaching Your Program to Make Decisions

Arithmetic operators crunch numbers. Relational operators compare them and return either 1 (true) or 0 (false). They're the basis of every if-statement, every loop condition, every decision your program makes. C has six: == (equal to), != (not equal to), > (greater than), < (less than), >= (greater than or equal to), and <= (less than or equal to).

Logical operators let you combine those comparisons. Think of them as the words 'and', 'or', and 'not' in English. In C: && means AND (both conditions must be true), || means OR (at least one must be true), and ! means NOT (flips true to false or false to true).

Here's a real-world framing: you're building a ride at an amusement park. The rule is: you must be AT LEAST 120cm tall AND you must be UNDER 200cm tall. That's two conditions joined by AND — exactly what && handles. If either condition is false, you don't get on the ride. This kind of gating logic appears in virtually every program ever written.

relational_logical_operators.c · C
12345678910111213141516171819202122232425262728293031323334353637383940
#include <stdio.h>

int main() {
    int height_cm = 145;
    int age = 12;
    int has_parent_with_them = 1;  // 1 = true, 0 = false in C

    // --- Relational Operators ---
    // Each comparison returns 1 (true) or 0 (false)
    printf("height_cm > 120: %d\n", height_cm > 120);   // 1 (true)
    printf("height_cm > 200: %d\n", height_cm > 200);   // 0 (false)
    printf("age == 12: %d\n", age == 12);               // 1 (true)
    printf("age != 10: %d\n", age != 10);               // 1 (true)

    // --- Logical AND (&&) ---
    // BOTH sides must be true for the result to be true
    int allowed_on_ride = (height_cm >= 120) && (height_cm <= 200);
    printf("\nAllowed on ride (height check): %d\n", allowed_on_ride);

    // --- Logical OR (||) ---
    // AT LEAST ONE side must be true
    int can_enter_park = (age >= 18) || (has_parent_with_them == 1);
    printf("Can enter park (age OR has parent): %d\n", can_enter_park);

    // --- Logical NOT (!) ---
    // Flips 0 to 1, and anything non-zero to 0
    int is_adult = (age >= 18);       // 0 (false, age is 12)
    int is_minor = !is_adult;         // flips 01 (true)
    printf("Is adult: %d\n", is_adult);
    printf("Is minor (!is_adult): %d\n", is_minor);

    // --- Combining everything in a real decision ---
    if (allowed_on_ride && can_enter_park) {
        printf("\nWelcome! Enjoy the ride!\n");
    } else {
        printf("\nSorry, you cannot go on this ride.\n");
    }

    return 0;
}
▶ Output
height_cm > 120: 1
height_cm > 200: 0
age == 12: 1
age != 10: 1

Allowed on ride (height check): 1
Can enter park (age OR has parent): 1
Is adult: 0
Is minor (!is_adult): 1

Welcome! Enjoy the ride!
⚠️
Watch Out: == vs = Is the #1 Beginner Bug in CWriting if (score = 10) instead of if (score == 10) doesn't cause an error — it ASSIGNS 10 to score and then evaluates to true, because 10 is non-zero. Your program runs, but with completely wrong behaviour. Always double-check your if-conditions. Some compilers warn about this with -Wall — always compile with warnings enabled.

Assignment and Compound Assignment Operators — Writing Less, Doing More

The single equals sign (=) in C is the assignment operator. It takes the value on the right and stores it in the variable on the left. It does NOT check equality — that's ==. Read it as 'gets the value of', not 'equals'.

C also gives you compound assignment operators, which combine an arithmetic operation WITH assignment into one step. Instead of writing score = score + 10, you write score += 10. They're shorthand — nothing more, nothing less. But they appear everywhere in real C code, so you need to be completely comfortable reading them.

The full set is: += (add and assign), -= (subtract and assign), *= (multiply and assign), /= (divide and assign), and %= (modulo and assign). There's also a special pair called the increment (++) and decrement (--) operators. These add or subtract exactly 1. You'll see them constantly in loops. They come in two flavours — prefix (++counter) and postfix (counter++) — and the difference matters in certain situations, so pay attention to the code below.

assignment_operators.c · C
1234567891011121314151617181920212223242526272829303132333435363738394041
#include <stdio.h>

int main() {
    int player_score = 0;

    // Basic assignment: stores 100 into player_score
    player_score = 100;
    printf("Starting score: %d\n", player_score);

    // Compound assignment operators — shorthand for common operations
    player_score += 50;   // same as: player_score = player_score + 50
    printf("After bonus (+50): %d\n", player_score);

    player_score -= 30;   // same as: player_score = player_score - 30
    printf("After penalty (-30): %d\n", player_score);

    player_score *= 2;    // same as: player_score = player_score * 2
    printf("After double-score event (*2): %d\n", player_score);

    player_score /= 4;    // same as: player_score = player_score / 4
    printf("After quarter reduction (/4): %d\n", player_score);

    // --- Increment and Decrement ---
    int lives = 3;

    // Postfix ++: USE the current value FIRST, THEN increment
    int lives_displayed = lives++;   // lives_displayed gets 3, THEN lives becomes 4
    printf("\nLives displayed: %d\n", lives_displayed);  // 3
    printf("Lives after postfix++: %d\n", lives);        // 4

    // Prefix ++: INCREMENT FIRST, then use the new value
    int next_level = ++lives;   // lives becomes 5 FIRST, then next_level gets 5
    printf("Lives after prefix++: %d\n", lives);         // 5
    printf("Next level value: %d\n", next_level);        // 5

    // Decrement works the same way
    lives--;   // lives goes from 5 to 4
    printf("Lives after lives--: %d\n", lives);          // 4

    return 0;
}
▶ Output
Starting score: 100
After bonus (+50): 150
After penalty (-30): 120
After double-score event (*2): 240
After quarter reduction (/4): 60

Lives displayed: 3
Lives after postfix++: 4
Lives after prefix++: 5
Next level value: 5
Lives after lives--: 4
⚠️
Pro Tip: Use Prefix ++ in Loops When In DoubtWhen you write for (int i = 0; i < 10; i++), postfix vs prefix makes no difference because the result isn't being assigned anywhere. But when you use ++ inside an expression like array[i++] vs array[++i], the difference is critical. If you're unsure, use prefix (++i) — it's also marginally faster on some older compilers because it doesn't need to store a temporary copy of the old value.

Bitwise Operators — Working Directly With the Zeros and Ones

Every value in your computer is stored as binary — a sequence of 0s and 1s called bits. Bitwise operators let you manipulate those individual bits directly. This sounds advanced, but it's used everywhere: setting hardware flags in embedded systems, optimising memory in tight loops, building permission systems (read/write/execute flags in Linux are a perfect example), and even fast graphics programming.

C has six bitwise operators: & (AND), | (OR), ^ (XOR), ~ (NOT/complement), << (left shift), and >> (right shift). The AND and OR work bit-by-bit, just like logical && and || but on the individual bits of both operands simultaneously.

Left shift (<<) multiplies a number by powers of 2 very efficiently. Shifting left by 1 is the same as multiplying by 2, shifting left by 2 is multiplying by 4, and so on. Right shift (>>) divides by powers of 2. This is why you'll often see bitwise operations in performance-sensitive C code — they're single CPU instructions, much faster than multiplication and division.

bitwise_operators.c · C
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
#include <stdio.h>

int main() {
    // Think of permissions like a Unix file system:
    // Bit 2 = Read, Bit 1 = Write, Bit 0 = Execute
    unsigned int READ    = 0b100;  // binary 100 = decimal 4
    unsigned int WRITE   = 0b010;  // binary 010 = decimal 2
    unsigned int EXECUTE = 0b001;  // binary 001 = decimal 1

    // --- Bitwise OR (|): SET a permission (turn a bit ON) ---
    unsigned int user_permissions = READ | WRITE;  // 100 | 010 = 110
    printf("User permissions (READ|WRITE): %u\n", user_permissions);  // 6

    // --- Bitwise AND (&): CHECK if a permission is set ---
    // If the bit is ON in both, result is 1 for that bit
    int can_read    = (user_permissions & READ)    ? 1 : 0;
    int can_write   = (user_permissions & WRITE)   ? 1 : 0;
    int can_execute = (user_permissions & EXECUTE) ? 1 : 0;
    printf("Can read: %d, Can write: %d, Can execute: %d\n",
           can_read, can_write, can_execute);

    // --- Bitwise AND (&): CLEAR a permission (remove WRITE) ---
    // ~WRITE flips all bits of WRITE: 010 becomes ...11111101
    user_permissions = user_permissions & ~WRITE;  // removes the WRITE bit
    printf("After removing WRITE: %u\n", user_permissions);  // 4 (just READ)

    // --- Bitwise XOR (^): TOGGLE a bit (flip it) ---
    // XOR with 1 flips the bit; XOR with 0 leaves it alone
    unsigned int flag = 0b1010;   // decimal 10
    unsigned int toggled = flag ^ 0b1111;  // flips all 4 bits → 0101 = 5
    printf("Toggled bits: %u\n", toggled);  // 5

    // --- Left Shift (<<): Multiply by powers of 2 ---
    int base_damage = 3;
    int double_damage  = base_damage << 1;  // 3 * 2 = 6
    int quad_damage    = base_damage << 2;  // 3 * 4 = 12
    printf("Base: %d, Double: %d, Quad: %d\n",
           base_damage, double_damage, quad_damage);

    // --- Right Shift (>>): Divide by powers of 2 ---
    int total_points = 64;
    int half_points    = total_points >> 1;  // 64 / 2 = 32
    int quarter_points = total_points >> 2;  // 64 / 4 = 16
    printf("Total: %d, Half: %d, Quarter: %d\n",
           total_points, half_points, quarter_points);

    return 0;
}
▶ Output
User permissions (READ|WRITE): 6
Can read: 1, Can write: 1, Can execute: 0
After removing WRITE: 4
Toggled bits: 5
Base: 3, Double: 6, Quad: 12
Total: 64, Half: 32, Quarter: 16
🔥
Interview Gold: Why Use Bitwise Over Boolean Arrays for Flags?Storing 8 permission flags as separate boolean variables uses 8 bytes (minimum). Storing them as bits inside a single unsigned char uses 1 byte — 8x more memory-efficient. In embedded systems with kilobytes of RAM, this difference is mission-critical. Interviewers love asking this exact question when they see bitwise operators on your resume.
Operator CategoryPurposeReturnsCommon Use Case
Arithmetic (+, -, *, /, %)Perform math calculationsNumeric resultScore calculation, geometry, counters
Relational (==, !=, >, <, >=, <=)Compare two values1 (true) or 0 (false)if-conditions, loop bounds, sorting
Logical (&&, ||, !)Combine boolean conditions1 (true) or 0 (false)Multi-condition checks, access control
Assignment (=, +=, -=, *=, /=)Store values in variablesThe assigned valueUpdating variables, running totals
Increment/Decrement (++, --)Add or subtract 1Old or new value (prefix vs postfix)Loop counters, pointer traversal
Bitwise (&, |, ^, ~, <<, >>)Manipulate individual bitsNumeric result (bit pattern)Flags, permissions, fast math, hardware

🎯 Key Takeaways

  • Integer division in C silently truncates — 7 / 2 is 3, not 3.5. Cast to float explicitly when you need decimals.
  • = assigns, == compares. Mixing them up compiles without error but produces wrong behaviour — this is one of C's most dangerous silent bugs.
  • Postfix counter++ returns the old value then increments; prefix ++counter increments first then returns the new value. The difference only matters when the result is used in an expression.
  • Bitwise operators work on individual bits and are used for flags, permissions, and fast power-of-2 math — understanding them is what separates systems programmers from script writers.

⚠ Common Mistakes to Avoid

  • Mistake 1: Using = instead of == in conditions — Writing if (temperature = 100) assigns 100 to temperature and always evaluates as true (since 100 is non-zero), so your else branch is unreachable and the variable is silently corrupted. Fix: always use == for comparison inside if, while, and for conditions. Compile with gcc -Wall to catch this — the compiler will say 'suggest parentheses around assignment used as truth value'.
  • Mistake 2: Assuming integer division gives a decimal result — Writing int result = 7 / 2 gives 3, not 3.5. There's no compiler warning; you just get a wrong answer silently. Fix: cast at least one operand to float before dividing — float result = (float)7 / 2 — or declare the variables as float/double from the start if decimal precision matters.
  • Mistake 3: Confusing prefix and postfix ++ inside expressions — Writing int snapshot = counter++ stores the ORIGINAL value of counter in snapshot, then increments counter. Writing int snapshot = ++counter increments counter FIRST, then stores the NEW value. Using the wrong one inside array indexing (arr[i++] vs arr[++i]) causes off-by-one errors that are notoriously hard to debug. Fix: never use ++ or -- inside a larger expression unless you're certain which version you need. When in doubt, put the increment on its own line.

Interview Questions on This Topic

  • QWhat is the difference between the prefix and postfix forms of the increment operator in C? Given int a = 5; int b = a++; int c = ++a; — what are the final values of a, b, and c?
  • QHow would you use bitwise operators to check whether a specific bit is set in an integer, and how would you set, clear, and toggle that bit? Walk me through the code.
  • QWhat is the result of 5 / 2 in C, and why? How would you change the code to get 2.5 instead of 2 — and what's the fastest way to do it without declaring a new float variable?

Frequently Asked Questions

How many types of operators are there in C?

C has eight main categories of operators: arithmetic, relational, logical, assignment, increment/decrement, bitwise, conditional (ternary), and the sizeof operator. For beginners, arithmetic, relational, logical, and assignment operators are the most important to master first — the rest build naturally on top of them.

What is the modulus operator in C and when should I use it?

The modulus operator (%) gives you the remainder after integer division. For example, 17 % 5 equals 2 because 5 goes into 17 three times with 2 left over. Use it to check if a number is even or odd (number % 2 == 0 means even), to wrap values around a range, or to cycle through a fixed set of options repeatedly.

Why do bitwise operators exist if we already have logical operators like && and ||?

Logical operators (&&, ||) work on entire values treated as true or false — they only care whether something is zero or non-zero, and they short-circuit (stop evaluating early). Bitwise operators (&, |) work on every individual bit simultaneously and never short-circuit. Bitwise operators are essential for packing multiple flags into a single integer, manipulating hardware registers, and writing memory-efficient code — tasks where logical operators simply don't have the precision needed.

🔥
TheCodeForge Editorial Team Verified Author

Written and reviewed by senior developers with real-world experience across enterprise, startup and open-source projects. Every article on TheCodeForge is written to be clear, accurate and genuinely useful — not just SEO filler.

← PreviousVariables and Data Types in CNext →Control Flow in C
Forged with 🔥 at TheCodeForge.io — Where Developers Are Forged