C · Beginner
Conditions in C: if, else and switch
In short: An if statement runs its block when its condition is non-zero; else if and else add alternatives that are tried in order until one succeeds. switch compares one integer or character value against fixed case labels and needs a break after each case, because otherwise execution falls through into the next case.
Making a decision
A program that always does the same thing is a calculator. Conditions are what let it react to its input: charge a fine only when a book is overdue, print a warning only when a tank runs low. In C the decision statement is if, and its condition is any expression in parentheses. The block runs when the expression is non-zero and is skipped when it is zero. Comparisons produce exactly 1 or 0, so if (level < 2.0) reads naturally, but any int works: if (count) runs when count is not zero.
else names what happens otherwise, and else if lets you test a second, third and fourth condition in a chain. C evaluates the conditions top to bottom, runs the first block whose condition holds, and skips the rest of the chain entirely. Order therefore matters: in a chain that classifies a level as below 0.5, then below 2.0, each test can assume the earlier ones failed. Put the most specific test first when ranges overlap, or the general one will swallow it.
Braces are technically optional when the body is a single statement, but leaving them out is how a second statement ends up outside the if without anyone noticing. Use braces every time; the cost is two characters. Blocks can nest, so an if inside an if is common, and combining conditions with && and || from the operators lesson often removes a level of nesting.
switch is the statement for "which of these fixed values is it?". It takes an integer expression, which includes char, and jumps to the case label whose constant matches; default catches everything else. Execution then continues downward through every following case until it meets break. That fall-through is deliberate and occasionally useful, for treating 'S' and 's' alike by stacking their labels, but forgetting break is the most common switch bug. switch cannot compare strings or doubles, and each case must be a constant known at compile time.
Tests on doubles deserve care: two calculations that look equal on paper can differ in the last binary digit, so == between doubles is unreliable. Compare the difference against a small tolerance instead. Finally, the conditional operator ?: is an expression, not a statement: use it to pick a value, and use if to pick an action.
Syntax
if (condition) {
statements;
} else if (other_condition) {
statements;
} else {
statements;
}
switch (integer_expression) {
case CONSTANT_1:
statements;
break;
case CONSTANT_2:
case CONSTANT_3: /* two labels share one body */
statements;
break;
default:
statements;
break;
}The condition must be in parentheses. Zero is false and every other value is true. In a switch, execution runs from the matching label until a break.
if versus switch
| Situation | Use |
|---|---|
Ranges such as x < 10 or x <= 100 | if / else if |
| Several conditions on different variables | if with && and || |
| One int or char against a handful of fixed values | switch |
| A menu letter or a status code | switch |
| Comparing strings or doubles | if with strcmp, or a tolerance |
| Choosing between two values inside an expression | the ?: operator |
An if / else if chain on a reading
A tank level in litres is read from input and classified; the input is 1.4.
#include <stdio.h>
int main(void)
{
double level;
if (scanf("%lf", &level) != 1) {
printf("no reading\n");
return 1;
}
if (level < 0.5) {
printf("Tank empty: refill now\n");
} else if (level < 2.0) {
printf("Tank low: refill soon\n");
} else if (level <= 9.0) {
printf("Tank ok\n");
} else {
printf("Overflow risk: %.1f litres\n", level);
}
return 0;
}
Input given to the program: 1.4
Output
Tank low: refill soon
1.4 is not below 0.5, so the first block is skipped; it is below 2.0, so the second block runs and the chain ends. The <= 9.0 and else branches are never tested. Reordering the tests would break the logic: if level < 2.0 came first, an empty tank would be reported as merely low. Checking the return value of scanf before the chain ensures level holds a real number.
Combining and nesting conditions
A library loan is 12 days overdue, is not a reference copy, and the borrower has 3 items out.
#include <stdio.h>
#include <stdbool.h>
int main(void)
{
int days_overdue = 12;
bool reference_copy = false;
int items_out = 3;
if (days_overdue > 0 && !reference_copy) {
int fine = days_overdue * 20;
printf("Fine: %d pence\n", fine);
if (fine > 200 || items_out >= 5) {
printf("Borrowing suspended\n");
}
} else {
printf("Nothing owed\n");
}
return 0;
}
Output
Fine: 240 pence Borrowing suspended
The outer test needs both facts, so it uses &&; !reference_copy is true because the flag is false. Inside, fine is declared in the block and is visible only there. The inner test uses ||: 240 > 200 already makes it true, so items_out >= 5 is never evaluated. Change days_overdue to 0 and the whole outer block is skipped, printing Nothing owed.
switch with stacked cases and default
A single size letter is read from input; the input is the lower-case letter m.
#include <stdio.h>
int main(void)
{
char code;
if (scanf(" %c", &code) != 1) {
return 1;
}
switch (code) {
case 'S':
case 's':
printf("Small: 250 ml\n");
break;
case 'M':
case 'm':
printf("Medium: 400 ml\n");
break;
case 'L':
case 'l':
printf("Large: 600 ml\n");
break;
default:
printf("Unknown size '%c'\n", code);
break;
}
return 0;
}
Input given to the program: m
Output
Medium: 400 ml
" %c" in scanf skips any leading whitespace and reads one character. switch jumps to case 'm', which shares its body with case 'M' because there is no code or break between the two labels. The body prints and break leaves the switch. Without that break, execution would continue into the 'L' case and print the large size too. default handles any other character and reports it.
Common mistakes
Forgetting break in a switch
Why it goes wrong: After the matching case, C keeps executing the statements of the following cases until it hits a break or the closing brace, so a customer asking for small gets small, medium and large printed.
Fix: End every case body with
break;unless you deliberately want fall-through, and comment it when you do. gcc's-Wimplicit-fallthrough(part of -Wextra) flags the accidental kind.C · fixcase 'S': printf("Small\n"); break; case 'M': printf("Medium\n"); break;A semicolon straight after the condition
Why it goes wrong:
if (x > 5);is a complete if statement with an empty body. The block that follows in braces always runs, whatever x is. The same trap exists forwhileandfor.Fix: Never put
;after the closing parenthesis of a condition.C · fixif (x > 5) { printf("big\n"); }Two statements under an if without braces
Why it goes wrong: Only the first statement belongs to the if; the second runs every time. Indentation suggests otherwise, but the compiler ignores indentation.
Fix: Always use braces, even around one statement.
C · fixif (overdue) { fine = 20; printf("fine due\n"); }Using switch on a string, or == on doubles
Why it goes wrong:
switch (name)where name is a char array does not compile, because cases must be integer constants.if (total == 0.3)may be false even when total was computed to be 0.3, because binary doubles cannot represent most decimals exactly.Fix: Compare strings with
strcmpfrom<string.h>and doubles with a tolerance such asfabs(a - b) < 1e-9, withfabsfrom<math.h>.
Rejecting bad input early
Every exercise here reads its input from standard input, and an early if is the simplest way to make a program robust against input that is missing or out of range. Read the value, check it, and return 1 with a message when it is unusable; the rest of the program can then assume the value is valid, which keeps the real logic free of defensive clutter. The same guard pattern protects divisions from a zero denominator and array indexes from going out of bounds. A switch fits the second common shape, a command or menu letter that selects what the program does next.
int n;
if (scanf("%d", &n) != 1 || n < 1 || n > 100) {
printf("n must be between 1 and 100\n");
return 1;
}
/* from here on, n is known to be valid */Key points
if (expr)runs its block when expr is non-zero; comparisons give 1 or 0.- In an if / else if / else chain only the first true branch runs; order the tests carefully.
- Always use braces around the body, and never put a semicolon right after the condition.
switchworks on int and char values against constant cases;defaultcatches the rest.- Every case body needs
break, or execution falls through into the next case. - Compare strings with strcmp and doubles with a tolerance, not
==.
Try it yourself
Read an hour of the day as an integer from 0 to 23 and print Morning for 5 to 11, Afternoon for 12 to 17, Evening for 18 to 21 and Night for anything else. The input is 19.
#include <stdio.h>
int main(void)
{
int hour;
if (scanf("%d", &hour) != 1) {
return 1;
}
/* classify the hour with an if / else if chain */
return 0;
}
19Evening#include <stdio.h>
int main(void)
{
int hour;
if (scanf("%d", &hour) != 1) {
return 1;
}
if (hour >= 5 && hour <= 11) {
printf("Morning\n");
} else if (hour >= 12 && hour <= 17) {
printf("Afternoon\n");
} else if (hour >= 18 && hour <= 21) {
printf("Evening\n");
} else {
printf("Night\n");
}
return 0;
}
Practise this
Exercises for this lesson are in the C practice set.
Related lessons
- Operators in CC arithmetic, comparison, logical, assignment and increment operators: why 7 / 2 is 3, how % behaves, what comparisons return, precedence and = versus ==.9 min
- Loops in C: for, while and do-whileThe three C loops and when each fits: how a for loop's three parts run, reading input until it ends with while and scanf, and using break and continue safely.9 min
- Functions in CHow to define and call C functions: prototypes before the first call, arguments copied by value, void functions, early returns and local variables.10 min
Frequently asked questions
Is 0 the only false value in C?
Yes. Any expression that evaluates to zero, whether the int 0, the char '\0', the double 0.0 or a null pointer, is false, and every other value is true. This is why if (count) means if (count != 0) and while (n--) is a valid countdown. The bool type from <stdbool.h> follows the same rule: false is 0 and true is 1.
Can a switch statement use a string in C?
No. The controlling expression and every case label must be integers (including char and enum values), because switch is compiled into comparisons against constants. To branch on a string, compare it with strcmp in an if / else if chain, or map the string to an integer code first and switch on that.
Do I need braces for a one-line if?
The grammar allows if (x) statement; without braces, but a second line added later ends up outside the if and runs unconditionally, and a stray semicolon after the condition becomes invisible. Writing the braces every time costs nothing and removes both bugs, so this site's examples always use them.
How this page was checked. Every program on it was run with GCC 13 (C11) at build time by the publishing checks, and the output shown is what it printed. Running C inside the browser is not available yet, so the Run button is absent rather than pretending; copy the code and run it with GCC 13 (C11) locally.