C Conditionals: if, else, and switch
Introduction
In C programming, conditionals let your program make decisions. They control which parts of your code run based on values or logic. This is essential for tasks like checking user input, handling errors, or choosing between actions.
Why conditionals matter
Without conditionals, your program would run the same way every time. Conditionals let you:
- Respond to different inputs
- Branch into different logic paths
- Make your program interactive and robust
They keep code clear, testable, and efficient - especially when combined with good naming and small functions.
if, else if, and else
Syntax
if (condition) {
// do stuff if condition is true
} else if (another_condition) {
// do stuff if another_condition is true
} else {
// do stuff if none of the above are true
}
Rules of thumb
- Conditions are evaluated top to bottom; the first true branch runs, the rest are skipped.
- Always use braces
{}even for one-line statements after e.g.if (x >1) y=1but its not good practice as its easy to get confused when adding more lines later. - Keep conditions simple; extract complex checks into well-named helper functions. i.e. better use
if (CheckInput(input,limits) == 1 )thanif ( input < X && X < Y and input >= Z .......... ) - Enable warnings (
-Wall -Wextra -Werror) to catch mistakes like=vs==. I promise you will make this mistake at least once! :D
Example 1 — Simple if
#include <stdio.h>
int main(void) {
int score = 85;
if (score >= 50) {
printf("Pass\n");
}
return 0;
}
Example 2 — if...else
#include <stdio.h>
int main(void) {
int score = 45;
if (score >= 50) {
printf("Pass\n");
} else {
printf("Fail\n");
}
return 0;
}
Example 3 — if...else if...else chain
#include <stdio.h>
int main(void) {
int grade = 72;
if (grade >= 70) {
printf("Class I\n");
} else if (grade >= 60) {
printf("Class II.i\n");
} else if (grade >= 50) {
printf("Class II.ii\n");
} else if (grade >= 40) {
printf("Class III\n");
} else {
printf("Fail\n");
}
return 0;
}
Example 4 — Nested if (use sparingly)
#include <stdio.h>
int main(void) {
int x = 15;
if (x > 0) {
if (x % 2 == 0) {
printf("positive even\n");
} else {
printf("positive odd\n");
}
} else {
printf("non-positive\n");
}
return 0;
}
Notice things can get complicated quickly with many nested if statements! If you find yourself in this situation it might be better to reconsider the approach.
switch statement
A more readable way to handle multiple branches is with a switch statement, which allow you to choose between several possible values of a single variable:
Syntax
switch (expression) {
case VALUE_1:
// statements
break;
case VALUE_2:
// statements
break;
default:
// statements if no case matches
break;
}
expressionis evaluated once; control jumps to the matchingcaselabel.caselabels must be integer constant expressions (e.g., literals, enum constants).- Add
break;to avoid the program continuing on to the next case, in some extremely rare cases you might want this but probably not! - Use
defaultfor unexpected values. Here you might log or handle the errors
Example 1 — Switch-based menu
#include <stdio.h>
int main(void) {
int choice = 0;
printf("Menu:\n1. Start\n2. Stop\n3. Exit\nEnter choice: ");
if (scanf("%d", &choice) != 1) return 1;
switch (choice) {
case 1:
printf("Starting...\n");
break;
case 2:
printf("Stopping...\n");
break;
case 3:
printf("Exiting...\n");
break;
default:
printf("Invalid choice.\n");
break;
}
return 0;
}
Example 2 — Switch with enum
Switch statements are useful when combined with enums especially when using finite state machines in Semester 2. For example if we had a program that could be in three states, we can use a switch statement using our enum variables:
#include <stdio.h>
typedef enum {
MODE_IDLE = 0,
MODE_RUN = 1,
MODE_ERR = 2
} mode_t;
int main(void) {
mode_t m = MODE_RUN;
switch (m) {
case MODE_IDLE:
printf("idle\n");
break;
case MODE_RUN:
printf("run\n");
break;
case MODE_ERR:
printf("error\n");
break;
default:
printf("unknown mode\n");
break;
}
return 0;
}
Example 3 — Declaring variables in a switch case safely
This is something I personally have got wrong many times! Each case within {} creates its own scope so that variables declared in the case are local to that case only.
#include <stdio.h>
int main(void) {
int x = 2;
switch (x) {
case 1: {
int a = 10; // this 'a' belongs to the scope within {}
printf("case 1: a = %d\n", a);
break;
}
case 2: {
int a = 20; // this is ok as we are in a separate scope to case 1
printf("case 2: a = %d\n", a);
break;
}
default:
printf("default\n");
break;
}
return 0;
}
When to use which?
- Use
if/else if/elsefor:- Ranges or relational logic (e.g.,
x < 10,a <= b && b < c) - Complex boolean expressions
- Situations where conditions are not small, fixed constants
- Ranges or relational logic (e.g.,
- Use
switchfor:- Discrete values (menu options, key codes, protocol IDs)
- Cleaner, flatter code when there are many exact-match branches
- Enums, where each constant maps to a branch
Summary table
| Feature | if / else if / else | switch |
|---|---|---|
| Best for | Ranges, complex conditions | Discrete values, enums |
| Readability | Great for few branches | Great for many exact matches |
| Fall-through | Not applicable | Possible; requires break or comment |
| Expression types | Any expression yielding boolean truth | Integral types / enums |
| Maintenance | Can grow nested | Scales well with many cases |
Quick tips
- Prefer clear, simple conditions; extract complicated logic into helper functions.
- Always use braces
{}for consistency and safety. - In
switch, break each case unless you intentionally fall through. - Consider enabling
-Wswitchand-Wswitch-enumto catch unhandled enum values. - Compile with strict warnings:
-Wall -Wextra -Werror.