Unit 3: Control Statements and Decision Making

CAP1008 — C Programming 4 min read

By default a C program executes top to bottom, one statement after another. Control statements break that straight-line flow, letting the program choose paths and repeat work based on runtime data. They are the constructs that turn a fixed sequence of instructions into logic that reacts to input.

  • Definition: A control statement is a statement that alters the normal sequential execution order of a program.
  • Three families: selection (choose a branch), iteration (repeat a block), and jump (transfer control unconditionally).
  • Statement block: one or more statements grouped by { }; a control statement governs a single statement or a block.
  • Truth convention: C has no dedicated boolean type in early standards. Any expression evaluating to 0 is false; any non-zero value is true.
  • Relational and logical operators: conditions are built from ==, !=, <, >, <=, >= and combined with &&, ||, !. && and || short-circuit, stopping as soon as the result is known.

II. Condition Statements — Selection and Decision Making

A. Condition statements

A condition statement evaluates a test expression and executes a block only when that expression is true, so the program can react differently to different data.

  • Test expression: any expression yielding a scalar value; the decision hinges on whether it is zero or non-zero.
  • Purpose: to guard code so it runs only when a stated logical condition holds, e.g. dividing only when the divisor != 0.
  • Role in this unit: the if, if-else, nested if and switch constructs are all condition (selection) statements built on this idea.

B. if

The if statement runs a block only when its condition is true, and otherwise skips it.

C
if (condition)
    statement;      // or { block }
  • Flow: evaluate condition; if non-zero, execute the statement, else fall through to the next line.
  • Single vs block: without braces only the immediately following statement is controlled; a common bug is expecting two lines to be guarded.
  • Example:
C
if (marks >= 40)
    printf("Pass\n");


prints only when marks is 40 or more.

C. if-else

if-else chooses between two mutually exclusive blocks: one for the true case, one for the false.

C
if (condition)
    statement1;
else
    statement2;
  • Guarantee: exactly one of the two branches runs on every pass.
  • else-if ladder: chaining else if tests conditions in order and stops at the first true one, ideal for graded ranges.
C
if (m >= 75)      grade = 'A';
else if (m >= 60) grade = 'B';
else if (m >= 40) grade = 'C';
else              grade = 'F';
  • Conditional operator: ? : is a compact expression form, e.g. big = (a > b) ? a : b;.

D. nested if

A nested if places one if (or if-else) inside another so a second condition is tested only after the first succeeds.

C
if (age >= 18) {
    if (citizen == 1)
        printf("Eligible to vote\n");
}
  • Layered logic: inner tests run only when the outer condition is true, modelling dependent decisions.
  • Dangling else rule: an else binds to the nearest unmatched if. Use braces to force the intended pairing.
  • Alternative: independent conditions joined by && often read better than deep nesting: if (age >= 18 && citizen == 1).

E. switch statement

switch selects one of many branches by matching an integer expression against constant case labels, replacing a long else-if ladder.

C
switch (expression) {
    case c1: statements; break;
    case c2: statements; break;
    default: statements;
}
  • Expression type: must evaluate to an integer or character; case labels must be distinct compile-time constants.
  • break: ends the switch; without it control falls through into the next case, executing it too.
  • default: optional catch-all when no case matches; may appear anywhere but conventionally last.
  • Deliberate fall-through: stacking labels shares code, e.g. case 'a': case 'e': case 'i': ... vowel++;.
  • Example:
C
switch (choice) {
    case 1: printf("Add\n");      break;
    case 2: printf("Subtract\n"); break;
    default: printf("Invalid\n");
}

III. Looping Statements — Iteration

A loop repeats a block while a condition remains true. Every loop needs three parts to terminate: initialization, a test condition, and an update that moves toward the exit; omitting the update causes an infinite loop.

A. while loop

while is an entry-controlled loop that tests before each iteration, so the body may run zero times.

C
initialization;
while (condition) {
    body;
    update;
}
  • Entry-controlled: the condition is checked first; if false at the start the body never executes.
  • Use when: the number of repetitions is unknown and depends on runtime state, e.g. reading until end-of-file.
  • Example:
C
int i = 1;
while (i <= 5) {
    printf("%d ", i);
    i++;
}


prints 1 2 3 4 5.

B. do-while loop

do-while is an exit-controlled loop that runs the body first and tests afterwards, guaranteeing at least one execution.

C
initialization;
do {
    body;
    update;
} while (condition);
  • Exit-controlled: the condition follows the body, so the body always runs at least once.
  • Terminating semicolon: the while (condition); line must end with a semicolon.
  • Use when: input must be taken before it can be validated, e.g. re-prompting a menu until a valid choice.
  1. while: test-then-execute; zero iterations possible when the condition starts false.
  2. do-while: execute-then-test; a minimum of one iteration always occurs.

C. for loop

for packs initialization, condition and update into one header, making it the natural choice for counting a known number of times.

C
for (initialization; condition; update)
    body;
  • Order of evaluation: initialization runs once; then for each pass the condition is tested, the body runs, and the update executes.
  • Entry-controlled: like while, it may iterate zero times.
  • Flexible parts: any of the three sections may be empty; for(;;) is a deliberate infinite loop. Multiple expressions can be separated by commas.
  • Nested for: loops inside loops handle grids and tables; the inner loop completes fully for each step of the outer.
  • Example:
C
for (int i = 1; i <= 3; i++) {
    for (int j = 1; j <= 3; j++)
        printf("%d ", i * j);
    printf("\n");
}


prints a 3×3 multiplication grid.

IV. Jump Statements — Unconditional Transfer

Jump statements move control directly to another point, bypassing the normal loop or selection flow.

A. break statement

break immediately terminates the innermost enclosing loop or switch and resumes execution after it.

  • In loops: exits early once a goal is met, e.g. stopping a search when the target is found.
  • In switch: prevents fall-through to later cases.
  • Scope limit: with nested loops, break leaves only the loop that directly contains it.
  • Example:
C
for (int i = 1; i <= 100; i++) {
    if (i == 5) break;   // loop stops when i reaches 5
    printf("%d ", i);
}


prints 1 2 3 4.

B. continue statement

continue skips the rest of the current iteration and jumps to the loop's next test or update, without leaving the loop.

  • In while/do-while: control returns to the condition; ensure the update still runs or the loop may hang.
  • In for: control jumps to the update section, then the condition.
  • Use: to bypass unwanted values while continuing to iterate, e.g. skipping negatives.
  • Example:
C
for (int i = 1; i <= 6; i++) {
    if (i % 2 == 0) continue;  // skip even numbers
    printf("%d ", i);
}


prints 1 3 5.

C. goto statement

goto transfers control unconditionally to a labelled statement anywhere in the same function.

C
goto label;
...
label:
    statement;
  • Label: an identifier followed by a colon; it marks the destination and must lie in the same function.
  • Direction: the jump may go forward or backward in the code.
  • Typical use: breaking out of deeply nested loops in one step, where a single break cannot.
  • Caution: unrestricted jumps produce tangled "spaghetti" code that is hard to read and debug; structured constructs (if, loops, break, continue) are almost always preferable.
  • Example:
C
    i = 0;
loop:
    if (i < 3) {
        printf("%d ", i);
        i++;
        goto loop;
    }


prints 0 1 2 by jumping back to the label.

D. Choosing the right construct

Selecting the correct control statement keeps logic clear and efficient.

  • Fixed count: prefer for, since its header states the bounds plainly.
  • Unknown count, test first: use while when the body may need to be skipped entirely.
  • Run at least once: use do-while for input validation and menu prompts.
  • Many discrete values: use switch for readability over a long else-if ladder.
  • Reserve goto: limit it to rare exits from nested loops, favouring structured flow elsewhere.