Introduction

Control-flow statements decide which statement runs next. C has selection statements (if, if-else, switch), iteration statements (while, do-while, for) and jump statements (break, continue, goto, return). Every algorithm is built from them, and a large share of GATE C questions reduce to tracing them exactly: how many times a loop body runs, which case labels execute, which if an else belongs to.

Conventions: C11, LP64. A condition in C is any scalar expression; it is "true" when it compares unequal to 0.

Prerequisites

Core concepts

Statements and blocks

A compound statement (block) { ... } groups statements into one. Every control statement controls exactly one statement; use a block to control several. A lone ; is the null statement, which does nothing. A misplaced ; therefore changes meaning:

C
for (i = 0; i < 5; i++);      /* the body is the null statement */
printf("%d\n", i);            /* runs once, prints 5 */

if and the dangling else

if (c) S1 else S2 runs S1 when c is nonzero, otherwise S2. The else part is optional.

Rule: an else belongs to the nearest preceding unmatched if in the same block. Indentation is ignored by the compiler.

C
int a = 0, b = 5;
if (a > 0)
    if (b > 0) printf("A");
else
    printf("B");     /* belongs to "if (b > 0)": prints nothing here */

With a = 0, the outer if fails, so nothing is printed, despite the indentation suggesting B. Braces fix the intent: if (a > 0) { if (b > 0) printf("A"); } else printf("C"); prints C.

switch

C
switch (expression) {
    case constant-1: statements
    case constant-2: statements
    default:         statements
}
  • The controlling expression must have integer type (after the integer promotions); switch on a double or a string does not compile.
  • Each case label must be an integer constant expression, and no two labels may have the same value. default is optional and may appear anywhere.
  • Execution jumps to the matching label (or to default, or past the whole switch if there is no match and no default) and then runs sequentially, through later labels, until a break or the end of the switch. Falling into the next case is called fall-through.
  • case labels are just labels: they do not start new scopes, and the order of labels does not matter for matching.

Loops

LoopTestBody runs at least once?Typical use
while (c) Sbefore each iterationnounknown number of iterations
do S while (c);after each iterationyesinput validation, menus
for (init; c; step) Sbefore each iterationnocounting loops

for (init; c; step) S behaves like init; while (c) { S step; } with one difference: continue inside S jumps to step, not straight to the test. Any of the three parts may be omitted; a missing condition is treated as true, so for (;;) is an infinite loop. Since C99, init may declare variables, whose scope is the loop.

Flowcharts of the while, do-while and for loops, showing where the condition is tested and where continue and break transfer control in a for loop.
Figure 1. Control flow of the three loops. In a for loop, continue goes to the step expression and break leaves the loop; in while and do-while, continue goes to the test.

Jump statements

  • break leaves the innermost enclosing loop or switch. It does not leave an if, and it leaves only one level of nesting.
  • continue skips the rest of the current iteration of the innermost enclosing loop (it has no meaning for switch). In while and do-while it goes to the test; in for it goes to the step.
  • goto label; jumps to a labelled statement in the same function. It is legal but rarely needed; the usual legitimate use is leaving several nested loops or jumping to a common clean-up block.
  • return ends the current function, optionally with a value (Functions and Parameter Passing).

How to trace a loop

  1. Write the initial values of every variable the loop reads.
  2. For each iteration, evaluate the test with the current values, run the body, then the step.
  3. Stop at the first failed test; record the final values. The loop variable of a for loop usually ends one step past the last value for which the body ran.
  4. For counting questions, find a formula and check it on small inputs.

Counting iterations

Let n≥1n \ge 1 be an integer.

LoopBody executionsReason
for (i = 0; i < n; i++)nni=0,1,…,n−1i = 0, 1, \ldots, n-1
for (i = 1; i <= n; i *= 2)⌊lg⁡n⌋+1\lfloor \lg n \rfloor + 1i=20,21,…,2⌊lg⁡n⌋i = 2^0, 2^1, \ldots, 2^{\lfloor \lg n \rfloor}
for (i = n; i > 0; i /= 3)⌊log⁡3n⌋+1\lfloor \log_3 n \rfloor + 1integer division by 3 until 0
for (i = 1; i * i <= n; i++)⌊n⌋\lfloor \sqrt{n} \rfloorii runs to the largest square root
for (i = 0; i < n; i++) for (j = i; j < n; j++)n(n+1)/2n(n+1)/2inner runs n−in - i times
for (i = 0; i < n; i++) for (j = 0; j < i; j++)n(n−1)/2n(n-1)/2inner runs ii times

For n=100n = 100 the first four give 100, 7, 5 and 10, and the nested loop gives 5050. In the division loop, ii takes the values 100, 33, 11, 3, 1; integer division makes ⌊log⁡3100⌋+1=4+1=5\lfloor \log_3 100 \rfloor + 1 = 4 + 1 = 5 iterations. Asymptotic costs of such loops are treated in Complexity Analysis of Loops and Space.

Worked examples

All outputs below are for C11 with gcc on x86-64 Linux (LP64).

Example 1 (switch fall-through).

C
for (int x = 1; x <= 4; x++) {
    switch (x) {
        case 1: printf("one ");
        case 2: printf("two "); break;
        case 3: printf("three ");
        default: printf("other ");
    }
    printf("| ");
}

Output: one two | two | three other | other | . For x = 1 execution falls from case 1 into case 2 and stops at its break. For x = 3 it falls into default.

Example 2 (continue and break in a for loop).

C
int s = 0;
for (int k = 1; k <= 10; k++) {
    if (k % 3 == 0) continue;   /* skip 3, 6, 9: goes to k++ */
    if (k > 8) break;           /* leave the loop at k = 10 */
    s += k;
}

The body adds 1, 2, 4, 5, 7, 8, so s is 27. At k=9k = 9 continue runs first; at k=10k = 10 break ends the loop.

Example 3 (do-while versus while). do { n++; } while (0); runs once; while (0) { w++; } runs zero times.

Example 4 (assignment as a condition). int x = 5, cnt = 0; while (x = 0) cnt++; assigns 0 to x; the condition's value is 0, so the body never runs. Final: x = 0, cnt = 0.

Example 5 (comma operator in a for loop). for (i = 0, j = 10; i < j; i += 3, j -= 2) ; passes through (0,10),(3,8),(6,6)(0,10), (3,8), (6,6) and stops with i = 6, j = 6.

Example 6 (leaving nested loops).

C
int found = 0;
for (int a = 1; a <= 3 && !found; a++)
    for (int b = 1; b <= 3; b++)
        if (a * b == 4) { found = a * 10 + b; break; }

The break leaves only the inner loop; the !found test stops the outer one. The first pair with product 4 is a=2,b=2a = 2, b = 2, so found is 22.

goto, labelled loops and multi-level exit

C's goto targets a label in the same function. It may cross ordinary nested blocks, but shall not jump from outside into the scope of an identifier having a variably modified type (C11 6.8.6.1). This is a scope restriction, not merely a ban on skipping initializers; skipping an ordinary initialization can instead leave a later read invalid.

Pattern. A small program may use goto to build a loop or to break out of two levels of nesting. Trace it exactly as written; do not rewrite it into while in your head before counting iterations. Nested break leaves only the innermost loop; goto is the portable way in C to leave two levels without a flag variable.

Important properties and observations

  • An else matches the nearest unmatched if; braces override.
  • switch needs an integer expression and integer constant case labels; without break, control falls through.
  • do-while always runs its body at least once and ends with a semicolon.
  • continue in a for loop runs the step expression; in while it goes directly to the test.
  • break exits only one level, and only loops and switch.
  • A stray semicolon after for (...) or while (...) makes an empty body.
  • if (x = 5) is an assignment, always true; if (x == 5) is a comparison.

Loop arithmetic convention. Iteration-count tables above use mathematical unbounded integers, with positive integer n. They are not safe C templates without representability checks, including the final update. For C doubling, after each body use if (i > n / 2) break; before i *= 2; for positive square-test loops use i <= n / i, not i * i <= n. The loop variable must also be wide enough for its remaining updates.

GATE examination perspective

  • Count the prints. Nested loops with dependent bounds; use the iteration table and confirm with n=1,2,3n = 1, 2, 3.
  • Doubling and halving loops give logarithmic counts; be exact about < versus <= and about the starting value (i=0i = 0 with i *= 2 never terminates).
  • Fall-through traces in switch without break, and default placed in the middle.
  • Dangling else with misleading indentation.
  • Final value of the loop variable after the loop, especially with an empty body.

Summary

Sources

  1. ISO/IEC 9899:2011 (C11), committee draft N1570, (consulted 2026-11-09): Section 6.8.4 (selection statements, including 6.8.4.2 on switch), 6.8.5 (iteration statements), 6.8.6 (jump statements).
  2. B. W. Kernighan and D. M. Ritchie, The C Programming Language, 2nd ed., Prentice Hall, 1988: Chapter 3 (control flow).

Next steps