if and else

C has no boolean type at the level of if: the condition is an integer expression, zero means false and every other value means true. The comparison and logical operators that build those expressions were covered in lesson 8; this lesson uses them to choose between branches.

Truth values

A condition accepts any scalar value, not only the result of a comparison. Zero is false; one, minus one and any other non-zero number are true. That rule is why a function returning an error code can be tested directly, and why an accidental assignment of zero silently takes the false branch.

#include <stdio.h> int main(void) { int values[] = {0, 1, -1, 42}; for (int i = 0; i < 4; i++) { if (values[i]) { printf("%d is true\n", values[i]); } else { printf("%d is false\n", values[i]); } } return 0; }

gcc -Wall -Wextra truth.c -o truth
./truth

0 is false
1 is true
-1 is true
42 is true

The braces around a single statement are optional, but this course keeps them: a second statement added later is the usual way a missing pair of braces becomes a bug.

else if chains

A chain of else if tests the branches in order and stops at the first true one. The order is the logic: test the narrowest or highest range first, otherwise a later branch can never run. The final else catches every value that reached the end.

#include <stdio.h> int main(void) { int score = 78; if (score >= 90) { printf("A\n"); } else if (score >= 80) { printf("B\n"); } else if (score >= 70) { printf("C\n"); } else if (score >= 60) { printf("D\n"); } else { printf("F\n"); } return 0; }

gcc -Wall -Wextra grades.c -o grades
./grades

C

Writing the chain from 60 upward would print D for every score of 70 or more, because 78 already satisfies the first test. Each branch is reached only when all earlier tests were false.

Combining conditions

A range needs two comparisons joined with &&. Both sides must be true, and the left one is evaluated first. The parentheses are not required, but the pair of comparisons reads better than a chain, and the compiler warned about chains in lesson 8.

#include <stdio.h> int main(void) { int low = 10; int high = 20; for (int value = 8; value <= 22; value += 2) { if (value >= low && value <= high) { printf("%d is inside\n", value); } else { printf("%d is outside\n", value); } } return 0; }

gcc -Wall -Wextra range.c -o range
./range

8 is outside
10 is inside
12 is inside
14 is inside
16 is inside
18 is inside
20 is inside
22 is outside

The boundaries are inclusive, so 10 and 20 are inside. Changing <= to < on either side moves the boundary, and the two ends of the range are the first values to test.

The conditional operator

When both branches only produce a value, the conditional operator ?: keeps the expression in one place. It is an expression, not a statement, so it can initialise a variable or sit inside a printf. Nesting it works but quickly hurts readability.

#include <stdio.h> int main(void) { int a = 12; int b = 30; int max = (a > b) ? a : b; int distance = (a > b) ? a - b : b - a; printf("max: %d\n", max); printf("distance: %d\n", distance); printf("sign: %d\n", (a < 0) ? -1 : (a > 0) ? 1 : 0); return 0; }

gcc -Wall -Wextra ternary.c -o ternary
./ternary

max: 30
distance: 18
sign: 1

The third line nests two operators: the first false branch is itself a conditional. With one more level, an if chain is easier to read, so the operator pays off only for short choices.

Assignment and the dangling else

An assignment is an expression with a value, so if (count = 0) compiles and always takes the false branch. GCC recognises the pattern and asks for parentheses, which in turn makes the intent explicit:

#include <stdio.h> int main(void) { int count = 3; if (count = 0) { printf("zero\n"); } else { printf("not zero\n"); } return 0; }

gcc -Wall -Wextra assign.c -o assign
./assign

assign.c: In function 'main':
assign.c:7:9: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
7 | if (count = 0) {
| ^~~~~
not zero

The second trap is indentation that lies. An else binds to the nearest unmatched if, whatever the indentation suggests, and GCC warns that the braces would remove the ambiguity:

#include <stdio.h> int main(void) { int a = -1; int b = 1; if (a > 0) if (b > 0) printf("both positive\n"); else printf("a is not positive\n"); printf("done\n"); return 0; }

gcc -Wall -Wextra dangling.c -o dangling
./dangling

dangling.c: In function 'main':
dangling.c:8:8: warning: suggest explicit braces to avoid ambiguous 'else' [-Wdangling-else]
8 | if (a > 0)
| ^
done

The else belongs to the inner if, so with a negative a neither message prints. Braces around both branches make the outer else do what the layout promised, and the warning disappears.

Exercises

  1. Print whether a number is negative, zero or positive using one chain, then rewrite the same logic with nested conditional operators.
  2. Test a year for a leap day with the full rule: divisible by 4, not by 100, or divisible by 400. Find the four boundary years that prove the rule.
  3. Write a chain that maps a character code to a category (letter, digit, space, other) without using ctype.h.

Questions

A new set of questions in a new order every time. Choose one answer for each, then check.

  1. Which values make an if condition true in C?

    Answer

    Every non-zero value

    A condition is an integer expression: zero is false and every other value, including negative ones, is true.

  2. Why does the order of an else if chain matter?

    Answer

    The first true branch wins and later tests are skipped

    Each test is reached only when the earlier ones were false, so a broad first test can hide every later branch.

  3. How is a range such as 10 to 20 written in one condition?

    Answer

    x >= 10 && x <= 20

    Two comparisons joined with && test both ends; a chained comparison does not have its mathematical meaning.

  4. What is the conditional operator ?:?

    Answer

    An expression that produces one of two values

    ?: yields a value, so it can initialise a variable or sit inside an expression, unlike an if statement.

  5. What does this program print? #include <stdio.h> int main(void) { int value = -1; if (value) { printf("%d is true\n", value); } else { printf("%d is false\n", value); } return 0; }

    Answer

    -1 is true

    Only zero is false, so -1 takes the true branch and prints with its value.

  6. A chain tests 90 first, then 80, then 70. What does it print for a score of 78?

    Answer

    C

    78 is below 80 and below 90, but it is at least 70, so the third branch prints C.

  7. What does this program print? #include <stdio.h> int main(void) { int value = 20; if (value >= 10 && value <= 20) { printf("%d is inside\n", value); } else { printf("%d is outside\n", value); } return 0; }

    Answer

    20 is inside

    Both comparisons are true, including the upper boundary, so the inside branch runs.

  8. What does this program print? #include <stdio.h> int main(void) { int a = 12, b = 30; printf("distance: %d\n", (a > b) ? a - b : b - a); return 0; }

    Answer

    distance: 18

    The condition is false, so the false branch computes b - a, which is 18.

  9. What does if (count = 0) do when count is 3?

    Answer

    It assigns zero and takes the false branch

    Assignment stores zero, the value of the expression is zero, and the false branch runs; GCC warns and suggests parentheses.

  10. What does this program print? #include <stdio.h> int main(void) { int a = -1, b = 1; if (a > 0) if (b > 0) printf("both positive\n"); else printf("a is not positive\n"); printf("done\n"); return 0; }

    Answer

    done

    The else binds to the inner if, so with a negative a neither message prints and only done appears.

The code on this page was run with gcc (Alpine 15.2.0) 15.2.0 on Alpine Linux 3.24.3 (x86_64) in a Docker container.

Article author: Arthur Isaev

Banner image