C Selection Statements Explained: if, Ternary Operator, and switch Control Flow

C selection statements let a program follow different branches based on conditions. The core constructs include if, else, the ternary operator, and switch. They help beginners avoid common mistakes in branch evaluation, short-circuit logic, and fallthrough execution. Keywords: C, selection statements, switch.

Technical Specification Snapshot

Parameter Value
Language C
License CC 4.0 BY-SA as stated in the source
Stars Not provided
Core Dependency stdio.h

Selection statements are the core entry point for control flow in C programs

Selection statements determine which block of code a program executes under different conditions. For beginners, the real difficulty is not the syntax itself, but understanding how an expression is evaluated as true, when a branch ends, and whether side effects occur.

In C, a condition does not need to return a Boolean type. Any non-zero value is true, and is false. Because of this, understanding expression evaluation rules is a prerequisite for mastering both if and switch.

Logical expressions are built from relational and logical operators

Relational operators include >, <, >=, <=, ==, and !=. They produce only two results: true returns 1, and false returns . That makes them a natural fit for if conditions.

#include <stdio.h>

int main(void) {
    int i = 0;

    if (0 == i) {  // Put the constant on the left to avoid mistyping == as =
        printf("i is equal to 0\n");
    }

    return 0;
}

This example demonstrates the standard way to use a relational expression as a condition.

Logical AND and logical OR both support short-circuit evaluation

Logical NOT !, logical AND &&, and logical OR || interpret operands as true or false. Pay special attention to the short-circuit behavior of && and ||: if the left side is enough to determine the result, the right side is not evaluated.

#include <stdio.h>

int main(void) {
    int i = 0;
    int j = 10;

    if ((i != 0) && (j / i > 0)) {  // Check that i is non-zero first to avoid division by zero
        printf("valid\n");
    }

    return 0;
}

This example uses short-circuit evaluation to safely avoid a division-by-zero error.

The if statement is ideal for range-based and hierarchical conditions

if is the most general selection construct. It can express single-branch, two-branch, and multi-branch logic, and it is especially suitable for scenarios such as range checks, precondition validation, and complex combined conditions.

if (score >= 90) {
    printf("A\n");
} else if (score >= 80) {
    printf("B\n");
} else {
    printf("C\n");
}

This example shows a typical chained if structure. Once a condition matches, the program exits the entire branch chain.

The dangling else is the most common source of confusion in nested if statements

When braces are omitted, else always matches the nearest unmatched if. This is known as the dangling else problem. Indentation does not change the meaning. Only braces can make the association explicit.

if (y != 0) {
    if (x != 0) {  // The inner if checks whether the divisor is valid
        result = y / x;
    } else {
        printf("Error\n");  // This else binds to the nearest if (x != 0)
    }
}

This example removes ambiguity by using explicit braces.

The ternary operator is best for compact simple branch expressions

The conditional expression has the form condition ? expression1 : expression2. It is fundamentally a branch construct that returns a value, which makes it suitable for two-way assignment or two-way output, but not for complex logic.

#include <stdio.h>

int main(void) {
    int a = 5;
    int b = 8;

    int max = (a > b) ? a : b;  // Return the larger value based on the condition
    printf("max = %d\n", max);

    return 0;
}

This example uses the ternary operator instead of a short if-else block.

The result type of a ternary expression participates in the usual arithmetic conversions

If the two branches use different types, C promotes the narrower type to the wider type, and the full expression returns the wider type. This conversion affects only the expression result. It does not change the declared types of the original variables.

The switch statement is better suited for discrete value matching

When the condition is whether an integer or character equals one fixed value from a known set, switch is often clearer than a long if-else chain. The expression after switch must be an integer expression, and each case label must be a constant expression.

#include <stdio.h>

int main(void) {
    int code = 29;

    switch (code) {
        case 29:
            printf("Pomegranate flower\n");
            break;  // Exit immediately after a match to avoid executing later cases
        case 10:
            printf("Rose\n");
            break;
        case 21:
            printf("White magnolia\n");
            break;
        default:
            printf("NOT FOUND\n");
    }

    return 0;
}

This example shows the standard use of switch for discrete value mapping.

Omitting break triggers case fallthrough

After switch matches a case, execution continues downward from that point until it reaches a break or the end of the statement. If you forget break, execution continues into the following branches. This behavior is called fallthrough.

switch (score) {
    case 3:
        printf("A\n");
    case 2:
        printf("B\n");
        break;
    case 1:
        printf("C\n");
        break;
}

In this example, when score == 3, the program prints both A and B, which demonstrates fallthrough.

Fallthrough can also be used intentionally for cumulative logic

In some cases, fallthrough is not a bug but a useful technique. For example, when accumulating the number of days up to a given month, you can start from the target month and continue downward without repeating conditions.

#include <stdio.h>

int main(void) {
    int month = 5;
    int sum = 0;

    switch (month) {
        case 12: sum += 31;  // Number of days in December
        case 11: sum += 30;  // Number of days in November
        case 10: sum += 31;
        case 9:  sum += 30;
        case 8:  sum += 31;
        case 7:  sum += 31;
        case 6:  sum += 30;
        case 5:  sum += 31;
        case 4:  sum += 30;
        case 3:  sum += 31;
        case 2:  sum += 28;
        case 1:  sum += 31;
    }

    printf("%d\n", sum);
    return 0;
}

This example uses switch fallthrough to calculate the cumulative number of days up to the current month.

Article Illustration

AI Visual Insight: This image serves as a general article illustration rather than showing a specific code interface, flowchart, or program output. It does not contain technically structured information that can be parsed into reusable implementation details.

Understanding expression evaluation rules matters more than memorizing syntax

From if to switch, the surface topic is syntax, but the deeper lesson is how expressions drive control flow. Short-circuit evaluation, type promotion, else binding, and case fallthrough all work together to determine the final execution path.

For beginners, the safest habits are to use braces consistently, watch for side effects, add break by default, and use parentheses to make precedence explicit. These habits reduce errors and significantly improve readability.

FAQ

Why does an if condition in C not require true or false?

Because C represents truth values numerically: means false, and any non-zero value means true. As long as an expression can be interpreted with integer semantics, it can be used in a condition.

How should I choose between if-else and switch?

Use if-else for range checks, compound conditions, and multiple logical combinations. Use switch when you need discrete matching against a single integer or character value.

Why do so many developers emphasize never omitting braces casually?

Because omitting braces increases the risk of dangling else confusion, accidental maintenance errors, and incorrect assumptions about branch scope. Keeping braces consistently is a low-cost engineering habit that improves reliability.

Core Summary: This article systematically reconstructs the knowledge model for C selection statements, including logical expressions, relational and logical operators, if/else, the conditional operator, switch, and break-driven fallthrough behavior. It helps beginners build a clear mental model of branch control while avoiding common mistakes such as dangling else and short-circuit side effects.