|$ curl https://forge-ai.dev/api/markdown?path=docs/c/control-flow
$cat docs/c-—-control-flow.md
updated Recently·40 min read·published

C — Control Flow

CControl FlowLoopsBeginnerBeginner🎯Free Tools
Introduction

Control flow determines the order in which statements execute. C provides conditional branching (if, switch), three loop constructs (for, while, do-while), and jump statements (break, continue, goto, return). Mastering these constructs is essential for writing efficient, correct C programs.

Unlike some languages, C treats any non-zero value as true and zero as false. This applies to if conditions, loop conditions, and logical operators. There is no separate boolean type in C89 — C99 introduced _Bool via <stdbool.h>.

This page covers conditionals, loops, jump statements, common patterns, and comprehensive examples.

intro.c
C
1#include <stdio.h>
2
3int main(void) {
4 int score = 85;
5
6 if (score >= 90) {
7 printf("Grade: A\n");
8 } else if (score >= 80) {
9 printf("Grade: B\n");
10 } else if (score >= 70) {
11 printf("Grade: C\n");
12 } else {
13 printf("Grade: F\n");
14 }
15
16 // Any non-zero value is true
17 int flag = 42;
18 if (flag) {
19 printf("flag is truthy\n");
20 }
21
22 return 0;
23}
if / else if / else

The if statement evaluates a condition and executes the body if it's non-zero. The else clause executes when the condition is zero. You can chain conditions with else if.

if-else.c
C
1#include <stdio.h>
2
3int main(void) {
4 int x = 15;
5
6 if (x > 0) {
7 printf("Positive\n");
8 } else if (x < 0) {
9 printf("Negative\n");
10 } else {
11 printf("Zero\n");
12 }
13
14 // Dangling else problem
15 // Without braces, else binds to the NEAREST if
16 int a = 1, b = 2;
17
18 // WRONG — else binds to inner if, not outer
19 if (a)
20 if (b)
21 printf("Both true\n");
22 else // This else matches the INNER if
23 printf("This is confusing\n");
24
25 // CORRECT — always use braces
26 if (a) {
27 if (b) {
28 printf("Both true (correct)\n");
29 } else {
30 printf("b is false (correct)\n");
31 }
32 }
33
34 // Nested if for range checking
35 int age = 25;
36 if (age >= 0) {
37 if (age < 13) {
38 printf("Child\n");
39 } else if (age < 18) {
40 printf("Teenager\n");
41 } else if (age < 65) {
42 printf("Adult\n");
43 } else {
44 printf("Senior\n");
45 }
46 } else {
47 printf("Invalid age\n");
48 }
49
50 return 0;
51}

info

The dangling else problem is a classic C pitfall. Always use braces{ } even for single-statement bodies. This prevents bugs when adding more statements later and makes the code more maintainable.
switch Statement

The switch statement selects among multiple cases based on an integer expression. It's more readable than long else if chains when comparing the same variable against many values.

switch.c
C
1#include <stdio.h>
2
3int main(void) {
4 int day = 3;
5
6 switch (day) {
7 case 1:
8 printf("Monday\n");
9 break; // Without break, execution "falls through"
10 case 2:
11 printf("Tuesday\n");
12 break;
13 case 3:
14 printf("Wednesday\n");
15 break;
16 case 4:
17 case 5:
18 printf("Thursday or Friday\n"); // Intentional fall-through
19 break;
20 case 6:
21 case 7:
22 printf("Weekend\n");
23 break;
24 default:
25 printf("Invalid day\n");
26 break;
27 }
28
29 // switch requires integer expressions (int, char, enum)
30 // You CANNOT use: float, double, string, or complex types
31
32 // Multiple case labels for the same code
33 char grade = 'B';
34 switch (grade) {
35 case 'A': case 'a':
36 printf("Excellent\n");
37 break;
38 case 'B': case 'b':
39 printf("Good\n");
40 break;
41 case 'F': case 'f':
42 printf("Fail\n");
43 break;
44 default:
45 printf("Unknown grade\n");
46 break;
47 }
48
49 return 0;
50}
Featureswitchif-else
Best forComparing one variable against many constantsComplex conditions, ranges
Condition typeInteger expression onlyAny expression
Fall-throughYes (must use break)No
PerformanceJump table (fast for many cases)Sequential evaluation
Duplicate casesNot allowedAllowed (last wins)

warning

Missing break in a switch case is one of the most common C bugs. The compiler will warn with -Wimplicit-fallthrough, but always include break or a /* fallthrough */ comment. Case values must be integer constant expressions — no variables.
for Loop

The for loop is the most versatile loop construct in C. It combines initialization, condition, and increment into a single line. All three parts are optional.

for-loop.c
C
1#include <stdio.h>
2
3int main(void) {
4 // Standard counting loop
5 for (int i = 0; i < 10; i++) {
6 printf("%d ", i);
7 }
8 printf("\n");
9
10 // Counting backwards
11 for (int i = 10; i > 0; i--) {
12 printf("%d ", i);
13 }
14 printf("\n");
15
16 // Skip by 2
17 for (int i = 0; i < 20; i += 2) {
18 printf("%d ", i);
19 }
20 printf("\n");
21
22 // Infinite loop (all parts optional)
23 int count = 0;
24 for (;;) {
25 if (count >= 5) break;
26 printf("count: %d\n", count++);
27 }
28
29 // Multiple loop variables
30 for (int i = 0, j = 10; i < j; i++, j--) {
31 printf("i=%d, j=%d\n", i, j);
32 }
33
34 // Nested for loops — multiplication table
35 for (int i = 1; i <= 5; i++) {
36 for (int j = 1; j <= 5; j++) {
37 printf("%4d", i * j);
38 }
39 printf("\n");
40 }
41
42 return 0;
43}
while Loop

The while loop evaluates the condition before each iteration. If the condition is false on the first check, the body never executes.

while-loop.c
C
1#include <stdio.h>
2
3int main(void) {
4 // Basic while loop
5 int i = 0;
6 while (i < 5) {
7 printf("%d ", i);
8 i++;
9 }
10 printf("\n");
11
12 // Reading input until sentinel value
13 int sum = 0, val;
14 printf("Enter numbers (0 to stop): ");
15 while (scanf("%d", &val) == 1 && val != 0) {
16 sum += val;
17 }
18 printf("Sum: %d\n", sum);
19
20 // Processing a linked list (common pattern)
21 // while (current != NULL) {
22 // process(current);
23 // current = current->next;
24 // }
25
26 // Factorial using while
27 int n = 5, fact = 1;
28 while (n > 1) {
29 fact *= n--;
30 }
31 printf("5! = %d\n", fact); // 120
32
33 return 0;
34}
do-while Loop

The do-while loop evaluates the condition aftereach iteration, guaranteeing the body executes at least once. It's ideal for input validation and menu systems.

do-while.c
C
1#include <stdio.h>
2
3int main(void) {
4 // Input validation — must run at least once
5 int age;
6 do {
7 printf("Enter your age (1-120): ");
8 scanf("%d", &age);
9 } while (age < 1 || age > 120);
10
11 printf("Age: %d\n", age);
12
13 // Menu system
14 int choice;
15 do {
16 printf("\n--- Menu ---\n");
17 printf("1. Play\n");
18 printf("2. Settings\n");
19 printf("3. Quit\n");
20 printf("Choice: ");
21 scanf("%d", &choice);
22
23 switch (choice) {
24 case 1: printf("Starting game...\n"); break;
25 case 2: printf("Opening settings...\n"); break;
26 case 3: printf("Goodbye!\n"); break;
27 default: printf("Invalid choice\n"); break;
28 }
29 } while (choice != 3);
30
31 // Number guessing game
32 int secret = 42, guess, attempts = 0;
33 do {
34 printf("Guess (1-100): ");
35 scanf("%d", &guess);
36 attempts++;
37 if (guess < secret) printf("Too low!\n");
38 else if (guess > secret) printf("Too high!\n");
39 else printf("Correct in %d attempts!\n", attempts);
40 } while (guess != secret);
41
42 return 0;
43}
Nested Loops

Nesting loops is essential for multi-dimensional iteration — matrices, grids, and combinatorial algorithms. Each inner loop runs to completion for every iteration of the outer loop.

nested-loops.c
C
1#include <stdio.h>
2
3#define ROWS 3
4#define COLS 4
5
6int main(void) {
7 // Matrix initialization and printing
8 int matrix[ROWS][COLS] = {
9 {1, 2, 3, 4},
10 {5, 6, 7, 8},
11 {9, 10, 11, 12}
12 };
13
14 // Print matrix
15 for (int i = 0; i < ROWS; i++) {
16 for (int j = 0; j < COLS; j++) {
17 printf("%4d", matrix[i][j]);
18 }
19 printf("\n");
20 }
21
22 // Find maximum value
23 int max = matrix[0][0];
24 for (int i = 0; i < ROWS; i++) {
25 for (int j = 0; j < COLS; j++) {
26 if (matrix[i][j] > max) {
27 max = matrix[i][j];
28 }
29 }
30 }
31 printf("Max: %d\n", max);
32
33 // Transpose matrix
34 int transposed[COLS][ROWS];
35 for (int i = 0; i < ROWS; i++) {
36 for (int j = 0; j < COLS; j++) {
37 transposed[j][i] = matrix[i][j];
38 }
39 }
40
41 return 0;
42}
break and continue

break exits the innermost loop or switch immediately. continue skips to the next iteration of the innermost loop. Both only affect the innermost enclosing loop.

break-continue.c
C
1#include <stdio.h>
2
3int main(void) {
4 // break — exit loop early
5 for (int i = 0; i < 100; i++) {
6 if (i == 10) {
7 printf("Found 10, stopping\n");
8 break; // exits the for loop
9 }
10 }
11
12 // continue — skip to next iteration
13 for (int i = 0; i < 10; i++) {
14 if (i % 2 == 0) {
15 continue; // skip even numbers
16 }
17 printf("%d ", i); // prints: 1 3 5 7 9
18 }
19 printf("\n");
20
21 // break in nested loops — only exits inner loop
22 for (int i = 0; i < 5; i++) {
23 for (int j = 0; j < 5; j++) {
24 if (j == 3) break; // exits inner loop only
25 printf("(%d,%d) ", i, j);
26 }
27 printf("\n");
28 }
29
30 // Pattern: find first prime after 100
31 for (int n = 101; ; n++) {
32 int is_prime = 1;
33 for (int i = 2; i * i <= n; i++) {
34 if (n % i == 0) {
35 is_prime = 0;
36 break;
37 }
38 }
39 if (is_prime) {
40 printf("First prime after 100: %d\n", n);
41 break;
42 }
43 }
44
45 return 0;
46}
goto Statement

The goto statement performs an unconditional jump to a labeled statement. It is generally discouraged, but has one legitimate use: centralized cleanup in functions with multiple resources to free.

goto.c
C
1#include <stdio.h>
2#include <stdlib.h>
3
4// goto for cleanup — the one legitimate pattern
5int process_data(const char *filename) {
6 FILE *fp = NULL;
7 char *buffer = NULL;
8 int result = -1;
9
10 fp = fopen(filename, "r");
11 if (fp == NULL) goto cleanup;
12
13 buffer = malloc(1024);
14 if (buffer == NULL) goto cleanup;
15
16 // ... process data ...
17 if (fgets(buffer, 1024, fp) == NULL) goto cleanup;
18
19 printf("Data: %s\n", buffer);
20 result = 0; // success
21
22cleanup:
23 if (buffer) free(buffer);
24 if (fp) fclose(fp);
25 return result;
26}
27
28// Equivalent without goto — more verbose
29int process_data_nogoto(const char *filename) {
30 FILE *fp = fopen(filename, "r");
31 if (fp == NULL) return -1;
32
33 char *buffer = malloc(1024);
34 if (buffer == NULL) {
35 fclose(fp);
36 return -1;
37 }
38
39 if (fgets(buffer, 1024, fp) == NULL) {
40 free(buffer);
41 fclose(fp);
42 return -1;
43 }
44
45 printf("Data: %s\n", buffer);
46 free(buffer);
47 fclose(fp);
48 return 0;
49}
50
51int main(void) {
52 // Avoid goto for general flow control
53 // goto is only useful for multi-resource cleanup
54 printf("See process_data() for goto cleanup pattern\n");
55 return 0;
56}
📝

note

The goto statement is often villainized, but Linus Torvalds and the Linux kernel use it extensively for error handling. The cleanup pattern with a single cleanup: label is cleaner than duplicating cleanup code at every error exit point. Avoid goto for regular control flow.
Infinite Loop Patterns

Infinite loops are common in servers, event loops, and embedded systems. C provides several syntactically valid ways to write them, each with different readability and portability characteristics.

infinite-loops.c
C
1#include <stdio.h>
2
3int main(void) {
4 // Preferred: for(;;) — most idiomatic in C
5 int count = 0;
6 for (;;) {
7 if (count >= 3) break;
8 printf("for(;;): %d\n", count++);
9 }
10
11 // Also common: while(1) — clear intent
12 count = 0;
13 while (1) {
14 if (count >= 3) break;
15 printf("while(1): %d\n", count++);
16 }
17
18 // while(1) — equivalent
19 count = 0;
20 while (1) {
21 if (count >= 3) break;
22 printf("while(1): %d\n", count++);
23 }
24
25 // Practical: server event loop pattern
26 // while (1) {
27 // Client *client = accept(server_fd, ...);
28 // handle_client(client);
29 // }
30
31 // Practical: embedded main loop
32 // for (;;) {
33 // check_sensors();
34 // update_display();
35 // __asm__("wfi"); // wait for interrupt
36 // }
37
38 return 0;
39}
Common Patterns

Control flow patterns recur frequently in C programs. Mastering these patterns helps you write idiomatic, efficient code.

patterns.c
C
1#include <stdio.h>
2
3// Pattern 1: Sentinel-controlled loop
4void read_names(void) {
5 char name[64];
6 printf("Enter names (type 'quit' to stop):\n");
7 while (scanf("%63s", name) == 1) {
8 if (name[0] == 'q' && name[1] == 'u') break;
9 printf(" Hello, %s!\n", name);
10 }
11}
12
13// Pattern 2: Flag-controlled loop
14void find_first_negative(int arr[], int n) {
15 int found = 0;
16 for (int i = 0; i < n && !found; i++) {
17 if (arr[i] < 0) {
18 printf("First negative at index %d\n", i);
19 found = 1;
20 }
21 }
22 if (!found) printf("No negatives found\n");
23}
24
25// Pattern 3: Nested iteration with early exit
26int has_common_element(int a[], int na, int b[], int nb) {
27 for (int i = 0; i < na; i++) {
28 for (int j = 0; j < nb; j++) {
29 if (a[i] == b[j]) return 1; // found
30 }
31 }
32 return 0; // not found
33}
34
35// Pattern 4: Switch-based state machine
36enum State { IDLE, RUNNING, PAUSED, STOPPED };
37
38int main(void) {
39 int data[] = {3, -1, 4, -2, 5};
40 int set1[] = {1, 3, 5};
41 int set2[] = {2, 4, 6};
42
43 read_names();
44 find_first_negative(data, 5);
45 printf("Common: %s\n",
46 has_common_element(set1, 3, set2, 3) ? "yes" : "no");
47
48 return 0;
49}
Comprehensive Examples

These examples combine multiple control flow constructs to solve practical problems.

examples.c
C
1#include <stdio.h>
2#include <math.h>
3
4// Prime number checker
5int is_prime(int n) {
6 if (n < 2) return 0;
7 if (n == 2) return 1;
8 if (n % 2 == 0) return 0;
9 for (int i = 3; i <= (int)sqrt((double)n); i += 2) {
10 if (n % i == 0) return 0;
11 }
12 return 1;
13}
14
15// Print number pyramid
16void print_pyramid(int rows) {
17 for (int i = 1; i <= rows; i++) {
18 // Print leading spaces
19 for (int j = 0; j < rows - i; j++) {
20 printf(" ");
21 }
22 // Print ascending numbers
23 for (int j = 1; j <= i; j++) {
24 printf("%d", j);
25 }
26 // Print descending numbers
27 for (int j = i - 1; j >= 1; j--) {
28 printf("%d", j);
29 }
30 printf("\n");
31 }
32}
33
34int main(void) {
35 // Find primes up to 50
36 printf("Primes up to 50:\n");
37 for (int i = 2; i <= 50; i++) {
38 if (is_prime(i)) {
39 printf("%d ", i);
40 }
41 }
42 printf("\n\n");
43
44 // Print pyramid
45 printf("Number pyramid:\n");
46 print_pyramid(5);
47
48 // FizzBuzz
49 printf("\nFizzBuzz (1-20):\n");
50 for (int i = 1; i <= 20; i++) {
51 if (i % 15 == 0) printf("FizzBuzz");
52 else if (i % 3 == 0) printf("Fizz");
53 else if (i % 5 == 0) printf("Buzz");
54 else printf("%d", i);
55 printf(" ");
56 }
57 printf("\n");
58
59 return 0;
60}
$Blueprint — Engineering Documentation·Section ID: C-CONTROL-FLOW·Revision: 1.0