Skip to content

Chapter 6 of 21

Control Flow

Make decisions with if, else, switch, and clear boolean expressions.

24 minutes 10 quick checksBy Subha Prasad
Lesson 6 of 21Course navigation

Lesson content

Read, practise, then check your understanding

Control flow selects which statements execute. In C, zero is false and any nonzero scalar value is true. Conditions should describe intent clearly and keep exceptional cases visible.

if, else if, and else

if (temperature >= 35) {
    puts("Heat warning");
} else if (temperature >= 25) {
    puts("Warm");
} else {
    puts("Mild or cool");
}

Only the first true branch runs. Order overlapping tests from most specific to least specific. Always use braces in team code; they make later edits safer and eliminate the “dangling else” ambiguity for readers.

Compound conditions

Logical AND (&&) requires both operands; logical OR (||) requires at least one. Both short-circuit.

bool valid_range(int value, int minimum, int maximum) {
    return value >= minimum && value <= maximum;
}

Prefer named predicates or intermediate boolean variables when a condition mixes several rules. Compare explicitly where doing so removes ambiguity, especially for masks and function results.

switch

switch compares one integer or enumeration expression against constant case labels.

switch (command) {
    case 's':
    case 'S':
        save_document();
        break;
    case 'q':
    case 'Q':
        request_exit();
        break;
    default:
        report_unknown_command(command);
        break;
}

Multiple labels may share a body. Without break, return, or another transfer, execution falls through. Deliberate fall-through should use the compiler-supported annotation or a clear comment.

Declarations immediately after a label can be awkward because a label applies to a statement, not a declaration. Create a block:

case LOAD: {
    int result = load_data();
    handle_result(result);
    break;
}

Early returns and goto

Early returns reduce nesting when rejecting invalid input:

int send_message(const char *message) {
    if (message == NULL) return -1;
    if (*message == '\0') return -2;
    return transmit(message);
}

goto should not create arbitrary control flow, but one forward jump to a cleanup label is idiomatic when a function acquires several resources.

Avoid control-flow traps

  • if (value = 5) assigns; if (value == 5) compares. Enable warnings.
  • Floating values should rarely be tested for exact equality after calculations.
  • A missing default can be intentional for an exhaustive enum, but document it.
  • Extract a function when complex branches hide the work being performed.

Knowledge check

Answer every question correctly to complete this chapter.

Which condition includes the value 18 and everything larger?
What usually prevents a switch case from falling through?
Which branch runs in an if / else if chain?
What scalar value is false in a C condition?
Which types can directly control a switch?
What is the purpose of default in switch?
Why should case-local declarations often be wrapped in braces?
What is the risk in if (value = 5)?
When is an early return useful?
Which use of goto is commonly accepted in C?

0 of 10 checks passed

Your progress is saved on this device.