C Programming: Low-Level Mastery
HomeInsightsCoursesC ProgrammingLoops (for, while, do-while)
Control Flow

Loops (while, do-while, for)

Master C's three loop constructs to repeat code execution. Learn while, do-while, and for loops, understand when to use each, and control loop flow with break and continue.

Understanding Loops

Loops allow repeating code without writing it multiple times. Instead of manually copying code 100 times, a loop executes the same block repeatedly based on a condition. This is fundamental to programming - processing arrays, reading files, handling user input, and countless other tasks require iteration. C provides three loop types, each suited for different situations.

All loops share a common structure: a condition that determines whether to continue looping, and a body that executes repeatedly. The differences lie in when the condition is checked (before or after each iteration) and whether initialization and increment are built into the loop syntax. Understanding these differences helps you choose the right loop for each task.

Three Loop Types:

  • while: Condition checked before each iteration
  • do-while: Condition checked after each iteration (runs at least once)
  • for: Compact syntax with initialization, condition, and increment

The while Loop

The while loop is C's simplest loop construct. It checks a condition before each iteration - if true, the body executes; if false, the loop terminates and execution continues after the loop. Because the condition is checked first, a while loop might never execute if the condition is initially false.

C
#include <stdio.h>

int main(void) {
    /* Basic while loop */
    int count = 0;
    
    while (count < 5) {
        printf("%d ", count);
        count++;  // Don't forget to update condition variable!
    }
    printf("\n");  // Output: 0 1 2 3 4
    
    /* Loop that doesn't execute */
    int x = 10;
    while (x < 5) {  // False from start
        printf("Never runs\n");
    }
    
    /* Reading input until valid */
    int num;
    printf("Enter positive number: ");
    scanf("%d", &num);
    
    while (num <= 0) {
        printf("Invalid! Enter positive number: ");
        scanf("%d", &num);
    }
    printf("You entered: %d\n", num);
    
    /* Processing array elements */
    int arr[] = {10, 20, 30, 40, 50};
    int i = 0;
    
    while (i < 5) {
        printf("%d ", arr[i]);
        i++;
    }
    printf("\n");
    
    /* Infinite loop (careful!) */
    while (1) {  // Always true
        printf("Press Ctrl+C to stop\n");
        // Need break or return to exit
        break;  // Exit immediately
    }
    
    return 0;
}

Common while Loop Patterns

C
/* Pattern 1: Countdown */
int n = 10;
while (n &gt; 0) {
    printf("%d...\n", n);
    n--;
}
printf("Liftoff!\n");

/* Pattern 2: Sentinel-controlled loop */
int value;
printf("Enter numbers (-1 to stop):\n");
scanf("%d", &value);

while (value != -1) {
    printf("You entered: %d\n", value);
    scanf("%d", &value);
}

/* Pattern 3: EOF-controlled file reading */
int ch;
while ((ch = getchar()) != EOF) {
    putchar(ch);  // Echo input
}

/* Pattern 4: Condition-controlled processing */
while (!end_of_data() && !error_occurred()) {
    process_next_item();
}

/* Pattern 5: Waiting for event */
while (!ready_to_continue) {
    check_status();
    update_display();
}

The do-while Loop

The do-while loop checks its condition after each iteration, guaranteeing the body executes at least once. This is useful when you need to perform an action before testing whether to continue. Menu systems, input validation that requires one attempt, and post-test loops are natural do-while applications.

C
/* Basic do-while loop */
int count = 0;

do {
    printf("%d ", count);
    count++;
} while (count < 5);
printf("\n");  // Output: 0 1 2 3 4

/* Runs at least once even if condition false */
int x = 10;
do {
    printf("Runs once: x = %d\n", x);
} while (x < 5);  // False, but body already executed

/* Menu system (common use case) */
int choice;

do {
    printf("\nMenu:\n");
    printf("1. Option A\n");
    printf("2. Option B\n");
    printf("3. Option C\n");
    printf("4. Exit\n");
    printf("Enter choice: ");
    scanf("%d", &choice);
    
    switch (choice) {
        case 1:
            printf("Option A selected\n");
            break;
        case 2:
            printf("Option B selected\n");
            break;
        case 3:
            printf("Option C selected\n");
            break;
        case 4:
            printf("Goodbye!\n");
            break;
        default:
            printf("Invalid choice\n");
    }
} while (choice != 4);

/* Input validation */
int age;

do {
    printf("Enter age (1-120): ");
    scanf("%d", &age);
    
    if (age < 1 || age &gt; 120) {
        printf("Invalid age! Try again.\n");
    }
} while (age < 1 || age &gt; 120);

printf("Age: %d\n", age);

/* Play again pattern */
char play_again;

do {
    play_game();
    
    printf("Play again? (y/n): ");
    scanf(" %c", &play_again);
} while (play_again == 'y' || play_again == 'Y');

The for Loop

The for loop is C's most compact and commonly used loop. It combines initialization, condition checking, and increment/decrement in one line, making it perfect for counting loops. The classic use is iterating over array indices or repeating code a specific number of times. Despite its compact syntax, for loops are just as powerful as while loops.

C
/* Basic for loop syntax */
// for (initialization; condition; increment/decrement)

for (int i = 0; i < 10; i++) {
    printf("%d ", i);
}
printf("\n");  // Output: 0 1 2 3 4 5 6 7 8 9

/* for loop is equivalent to while: */
{
    int i = 0;  // Initialization
    while (i < 10) {  // Condition
        printf("%d ", i);
        i++;  // Increment
    }
}

/* Counting backwards */
for (int i = 10; i &gt; 0; i--) {
    printf("%d ", i);
}
printf("\n");  // Output: 10 9 8 7 6 5 4 3 2 1

/* Incrementing by different amounts */
for (int i = 0; i < 100; i += 10) {
    printf("%d ", i);
}
printf("\n");  // Output: 0 10 20 30 40 50 60 70 80 90

/* Multiple variables */
for (int i = 0, j = 10; i < j; i++, j--) {
    printf("i=%d, j=%d\n", i, j);
}

/* Array processing */
int arr[] = {10, 20, 30, 40, 50};
int size = sizeof(arr) / sizeof(arr[0]);

for (int i = 0; i < size; i++) {
    printf("arr[%d] = %d\n", i, arr[i]);
}

/* Nested loops */
for (int row = 0; row < 3; row++) {
    for (int col = 0; col < 4; col++) {
        printf("(%d,%d) ", row, col);
    }
    printf("\n");
}

/* Empty sections (unusual but valid) */
int k = 0;
for (; k < 5; ) {  // Initialization and increment elsewhere
    printf("%d ", k);
    k++;
}

/* Infinite loop */
for (;;) {  // All sections empty = infinite
    printf("Forever\n");
    break;  // Need break to exit
}

Common for Loop Patterns

C
/* Pattern 1: Iterate over array */
int numbers[] = {1, 2, 3, 4, 5};
for (int i = 0; i < 5; i++) {
    printf("%d\n", numbers[i]);
}

/* Pattern 2: Accumulation */
int sum = 0;
for (int i = 1; i <= 100; i++) {
    sum += i;
}
printf("Sum 1-100: %d\n", sum);  // 5050

/* Pattern 3: Multiplication table */
int n = 7;
for (int i = 1; i <= 10; i++) {
    printf("%d x %d = %d\n", n, i, n * i);
}

/* Pattern 4: Finding maximum */
int arr[] = {23, 45, 12, 67, 34};
int max = arr[0];

for (int i = 1; i < 5; i++) {
    if (arr[i] &gt; max) {
        max = arr[i];
    }
}
printf("Maximum: %d\n", max);

/* Pattern 5: String traversal */
char *str = "Hello";
for (int i = 0; str[i] != '\0'; i++) {
    printf("%c ", str[i]);
}
printf("\n");

/* Pattern 6: 2D array processing */
int matrix[3][3] = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};

for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
        printf("%d ", matrix[i][j]);
    }
    printf("\n");
}

Loop Control: break and continue

Break and continue statements alter normal loop flow. Break immediately exits the loop, continuing execution after it. Continue skips the rest of the current iteration and jumps to the next iteration. These control statements make loops more flexible, allowing early termination or selective skipping without complex condition logic.

C
/* break: Exit loop immediately */
for (int i = 0; i < 10; i++) {
    if (i == 5) {
        break;  // Exit loop when i equals 5
    }
    printf("%d ", i);
}
printf("\n");  // Output: 0 1 2 3 4

/* Finding element in array */
int arr[] = {10, 20, 30, 40, 50};
int target = 30;
int found = 0;

for (int i = 0; i < 5; i++) {
    if (arr[i] == target) {
        printf("Found %d at index %d\n", target, i);
        found = 1;
        break;  // No need to continue searching
    }
}

if (!found) {
    printf("%d not found\n", target);
}

/* continue: Skip to next iteration */
for (int i = 0; i < 10; i++) {
    if (i % 2 == 0) {
        continue;  // Skip even numbers
    }
    printf("%d ", i);
}
printf("\n");  // Output: 1 3 5 7 9

/* Processing valid items only */
for (int i = 0; i < count; i++) {
    if (items[i].invalid) {
        continue;  // Skip invalid items
    }
    
    // Process valid item
    process(items[i]);
}

/* break with nested loops (only exits innermost) */
for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
        if (j == 1) {
            break;  // Exits inner loop only
        }
        printf("(%d,%d) ", i, j);
    }
    printf("\n");
}
// Output:
// (0,0)
// (1,0)
// (2,0)

/* Using flag to break outer loop */
int found_outer = 0;
for (int i = 0; i < 3 && !found_outer; i++) {
    for (int j = 0; j < 3; j++) {
        if (condition_met) {
            found_outer = 1;
            break;  // Break inner
        }
    }
}

/* continue with while loop */
int n = 0;
while (n < 10) {
    n++;
    if (n % 3 == 0) {
        continue;  // Skip multiples of 3
    }
    printf("%d ", n);
}
printf("\n");  // Output: 1 2 4 5 7 8 10

Choosing the Right Loop

Each loop type has ideal use cases. While you can technically use any loop for any task, choosing the most appropriate loop makes code clearer and more maintainable. Consider what you know before the loop starts and when the condition should be checked.

C
/* Use for loop when: */
// 1. Number of iterations known
for (int i = 0; i < 10; i++) {
    printf("%d\n", i);
}

// 2. Iterating over array indices
for (int i = 0; i < array_size; i++) {
    process(array[i]);
}

// 3. Counting up or down
for (int count = 100; count &gt; 0; count--) {
    printf("%d bottles...\n", count);
}

/* Use while loop when: */
// 1. Number of iterations unknown
while (!end_of_file) {
    line = read_line();
    process(line);
}

// 2. Waiting for condition
while (!ready) {
    wait();
}

// 3. Sentinel-controlled input
int value;
scanf("%d", &value);
while (value != -999) {
    sum += value;
    scanf("%d", &value);
}

/* Use do-while loop when: */
// 1. Loop must execute at least once
do {
    show_menu();
    get_choice();
} while (choice != EXIT);

// 2. Input validation requiring first attempt
do {
    printf("Enter password: ");
    get_password();
} while (!is_valid_password());

// 3. Game loops
do {
    play_round();
    printf("Continue? ");
    scanf("%c", &response);
} while (response == 'y');

/* General guidelines */
// - for: Known iteration count, array processing
// - while: Unknown iteration count, condition-driven
// - do-while: Must execute once, post-test needed

/* Converting between loop types */
// These are equivalent:

// for version:
for (int i = 0; i < 10; i++) {
    printf("%d\n", i);
}

// while version:
int i = 0;
while (i < 10) {
    printf("%d\n", i);
    i++;
}

// do-while version (if you want at least one iteration):
int i = 0;
if (i < 10) {  // Check once
    do {
        printf("%d\n", i);
        i++;
    } while (i < 10);
}

Common Loop Pitfalls

Loops are prone to specific errors that can cause infinite loops, off-by-one errors, or skipped iterations. Recognizing these patterns helps you write correct loop code and debug problems quickly.

C
/* Pitfall 1: Infinite loop (condition never false) */
int i = 0;
while (i < 10) {
    printf("%d\n", i);
    // Forgot to increment i!
}

/* Pitfall 2: Off-by-one error */
// Wrong: Misses last element
for (int i = 0; i < 10; i++) {
    arr[i] = 0;  // Only clears 0-9, missing index 10
}

// Correct:
for (int i = 0; i <= 10; i++) {
    arr[i] = 0;  // Clears 0-10
}

/* Pitfall 3: Modifying loop variable incorrectly */
for (int i = 0; i < 10; i++) {
    printf("%d\n", i);
    i++;  // DON'T DO THIS! i incremented twice
}

/* Pitfall 4: Floating-point comparison */
// Risky: May not terminate due to rounding
for (double d = 0.0; d != 1.0; d += 0.1) {
    printf("%f\n", d);
}

// Better: Use inequality
for (double d = 0.0; d < 1.0; d += 0.1) {
    printf("%f\n", d);
}

/* Pitfall 5: Wrong array bounds */
int arr[10];
for (int i = 0; i <= 10; i++) {  // Goes to 10!
    arr[i] = 0;  // Buffer overflow! arr[10] out of bounds
}

/* Correct */
for (int i = 0; i < 10; i++) {  // 0 to 9
    arr[i] = 0;
}

/* Pitfall 6: Semicolon after loop header */
for (int i = 0; i < 10; i++);  // Empty loop body!
{
    printf("%d\n", i);  // Only runs once, i is 10
}

/* Pitfall 7: Uninitialized loop variable */
int count;  // Garbage value
while (count < 10) {  // Undefined behavior
    count++;
}

/* Correct: Initialize */
int count = 0;
while (count < 10) {
    count++;
}

Summary & What's Next

Key Takeaways:

  • ✅ while: Pre-test loop, may not execute at all
  • ✅ do-while: Post-test loop, always executes at least once
  • ✅ for: Compact syntax with init, condition, increment
  • ✅ break exits loop immediately
  • ✅ continue skips to next iteration
  • ✅ Always update loop control variable to avoid infinite loops
  • ✅ Watch for off-by-one errors with array bounds
  • ✅ Choose loop type based on when condition is known/checked

What's Next?

Let's learn about switch statements for multi-way branching!