Loops
Master C's three loop constructs — for, while, and do-while — along with break, continue, nested loops, and common patterns.
Doing things repeatedly
Imagine a factory assembly line. Workers repeat the same task for every item that comes down the belt. A for loop is like knowing in advance exactly how many items will come — "process exactly 100 parts." A while loop is like working until a red light flashes — "keep going until the stop signal." A do-while loop is like tasting a dish before deciding whether to add more seasoning — you always do it at least once, then check whether to repeat.
In Python you used for i in range(10) or while condition. Java added a for-each syntax. In C, loops look similar to Java but have important differences: the for loop variable is not scoped to the loop in C89/C90 (though C99 and later do allow it), and C has no built-in for-each — you iterate over arrays manually with an index.
C's three loop types share one underlying rule: each loop has a condition expression. When that condition evaluates to zero (false), the loop exits. When it is non-zero (true), the body executes again. This is the same rule that governs if statements.
The three loops differ only in when the condition is checked and what happens on each cycle:
| Loop | Checks condition | Minimum executions | Best when you know... |
|---|---|---|---|
for |
Before each iteration | 0 (may never run) | ...the exact iteration count up front |
while |
Before each iteration | 0 (may never run) | ...you want to loop until a condition changes |
do-while |
After each iteration | 1 (always runs once) | ...the body must run at least once (e.g. menus) |
# Python for loop
for i in range(10):
print(i)
# Python while loop
n = 10
while n > 0:
print(n)
n -= 1
# Python has no do-while —
# simulate with while True + break
while True:
x = int(input("Enter > 0: "))
if x > 0:
break
/* C for loop */
for (int i = 0; i < 10; i++) {
printf("%d\n", i);
}
/* C while loop */
int n = 10;
while (n > 0) {
printf("%d\n", n);
n--;
}
/* C do-while — runs body first */
int x;
do {
printf("Enter > 0: ");
scanf("%d", &x);
} while (x <= 0);
// Java for-each (no C equivalent!)
int[] arr = {1, 2, 3};
for (int val : arr) {
System.out.println(val);
}
// Java for — same syntax as C
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
// Key difference: loop var always
// scoped to the loop in Java.
/* C has no for-each — use index */
int arr[] = {1, 2, 3};
int len = 3;
for (int i = 0; i < len; i++) {
printf("%d\n", arr[i]);
}
/* In C89, declare i BEFORE loop: */
int i;
for (i = 0; i < len; i++) {
printf("%d\n", arr[i]);
}
Should the condition be i < 10 or i <= 10? For an array of 10 elements, valid indices are 0 through 9. Use i < 10 (less than, not less-than-or-equal). i <= 10 would access arr[10] — one past the end — causing undefined behavior. This off-by-one error is so common it has its own name: fencepost error.
break exits the smallest enclosing loop immediately — execution jumps to the first statement after the loop. continue skips the rest of the current iteration and jumps to the loop's update step (for loops) or condition check (while/do-while). Neither break nor continue accept labels in C — they only affect the innermost loop.
A loop whose condition is always true (or never false) runs forever. while (1) { ... } and for (;;) { ... } are both valid intentional infinite loops — used in server event loops and embedded systems. An accidental infinite loop usually means you forgot to update the loop variable, or used the wrong condition. Check: does your loop variable get modified inside the body?
Anatomy of each loop type
The for loop
for ( int i = 0 ; i < 10 ; i++ ) { ^ ^^^^^^^^^^^ ^^^^^^^^^ ^^^^^^ | initializer condition update | runs once checked runs after keyword before loop each iter each body printf("%d\n", i); } /* All three parts are OPTIONAL: */ for (;;) { /* infinite loop — equivalent to while(1) */ } for (i=0; i<10;) { i++; } /* update in body instead */
The while loop
while ( condition ) { ^^^^^^^^^ evaluated BEFORE body runs if false on first check: body never runs /* body */ } /* Example: read until valid input */ int x = 0; while (x <= 0) { scanf("%d", &x); }
x were already positive before the loop, the body would never execute — the condition is false from the start.
The do-while loop
do { /* body ALWAYS runs at least once */ printf("Enter a positive number: "); scanf("%d", &x); } while (x <= 0); ^^^^^^^^^^^^^^^ Note the SEMICOLON after the while condition — this is required and easy to forget!
break and continue
/* break: exit the loop immediately */ for (int i = 0; i < 10; i++) { if (i == 5) break; // exits when i reaches 5 printf("%d ", i); // prints: 0 1 2 3 4 } /* continue: skip rest of THIS iteration */ for (int i = 0; i < 10; i++) { if (i % 2 == 0) continue; // skip even numbers printf("%d ", i); // prints: 1 3 5 7 9 } /* In NESTED loops: break/continue affect INNERMOST loop only */ for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (j == 1) break; // only breaks the INNER loop printf("(%d,%d) ", i, j); } } // prints: (0,0) (1,0) (2,0)
Complete programs you can compile and run
#include <stdio.h>
int main(void) {
int scores[] = {78, 92, 55, 88, 71, 95, 60};
int n = 7; /* number of elements */
/* --- Pattern 1: Summing with a for loop --- */
int sum = 0;
for (int i = 0; i < n; i++) {
sum += scores[i]; /* same as: sum = sum + scores[i] */
}
printf("Sum: %d\n", sum);
printf("Average: %.1f\n", (double)sum / n);
/* --- Pattern 2: Finding the maximum --- */
int max = scores[0]; /* assume first is max */
for (int i = 1; i < n; i++) {
if (scores[i] > max) {
max = scores[i];
}
}
printf("Maximum: %d\n", max);
/* --- Pattern 3: Linear search, using break --- */
int target = 88;
int found_at = -1;
for (int i = 0; i < n; i++) {
if (scores[i] == target) {
found_at = i;
break; /* stop as soon as we find it */
}
}
if (found_at != -1)
printf("Found %d at index %d\n", target, found_at);
else
printf("%d not found\n", target);
/* --- Pattern 4: Counting with continue --- */
int above_80 = 0;
for (int i = 0; i < n; i++) {
if (scores[i] <= 80) continue; /* skip scores <= 80 */
above_80++;
}
printf("Scores above 80: %d\n", above_80);
return 0;
}
Average: 77.0
Maximum: 95
Found 88 at index 3
Scores above 80: 3
#include <stdio.h>
int main(void) {
/* --- do-while: keep asking until valid input --- */
int age;
do {
printf("Enter your age (1-120): ");
scanf("%d", &age);
if (age < 1 || age > 120)
printf(" Invalid — try again.\n");
} while (age < 1 || age > 120);
printf("Age accepted: %d\n\n", age);
/* --- while: count digits in a number --- */
int n;
printf("Enter a positive integer: ");
scanf("%d", &n);
int original = n;
int digits = 0;
while (n > 0) {
n /= 10; /* remove the last digit */
digits++;
}
printf("%d has %d digit(s)\n\n", original, digits);
/* --- while with EOF: sum numbers until end of input --- */
printf("Enter numbers (Ctrl+D to stop):\n");
int val, total = 0, count = 0;
while (scanf("%d", &val) == 1) { /* returns 1 while reading succeeds */
total += val;
count++;
}
if (count > 0)
printf("Sum of %d numbers: %d, average: %.2f\n",
count, total, (double)total / count);
return 0;
}
Invalid — try again.
Enter your age (1-120): 21
Age accepted: 21
Enter a positive integer: 12345
12345 has 5 digit(s)
#include <stdio.h>
int main(void) {
/* --- Nested for loops: multiplication table --- */
int size = 5;
printf("Multiplication table:\n");
for (int i = 1; i <= size; i++) {
for (int j = 1; j <= size; j++) {
printf("%4d", i * j); /* %4d: right-align in 4-char field */
}
printf("\n"); /* newline after each row */
}
printf("\n");
/* --- Nested loops with break in inner: right triangle --- */
printf("Triangle pattern:\n");
for (int row = 1; row <= 5; row++) {
for (int col = 1; col <= row; col++) {
printf("* ");
}
printf("\n");
}
/* --- Nested loops with continue: skip diagonal --- */
printf("\nOff-diagonal pairs (i != j), i,j in 1..3:\n");
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
if (i == j) continue; /* skip diagonal */
printf("(%d,%d) ", i, j);
}
printf("\n");
}
return 0;
}
1 2 3 4 5
2 4 6 8 10
3 6 9 12 15
4 8 12 16 20
5 10 15 20 25
Triangle pattern:
*
* *
* * *
* * * *
* * * * *
Practice problems with solutions
Without running the code, predict exactly what is printed. Pay careful attention to the loop conditions and whether < or <= is used.
#include <stdio.h>
int main(void) {
int i;
/* Loop A */
for (i = 0; i < 5; i++)
printf("A%d ", i);
printf("\n");
/* Loop B */
for (i = 1; i <= 5; i++)
printf("B%d ", i);
printf("\n");
/* Loop C */
for (i = 10; i > 0; i -= 3)
printf("C%d ", i);
printf("\n");
/* Loop D */
i = 0;
while (i++ < 3)
printf("D%d ", i);
printf("\n");
return 0;
}
A0 A1 A2 A3 A4
B1 B2 B3 B4 B5
C10 C7 C4 C1
D1 D2 D3
Loop B: i starts at 1, runs while i <= 5. Runs for i = 1,2,3,4,5 (also 5 iterations but starting from 1).
Loop C: Counts down by 3 from 10. i = 10, 7, 4, 1. When i becomes -2, condition 10>0 fails, stop.
Loop D: Post-increment
i++: condition checks old value, then increments. When i=0: check 0<3 (true), then i becomes 1, prints D1. When i=3: check 3<3 (false — note: was 2, incremented to 3 AFTER the check passed), so prints D3. The key: i++ returns the value BEFORE incrementing.
The code below is supposed to print all elements of a 5-element array. It has an off-by-one error. Find the bug, explain what goes wrong, and fix it.
#include <stdio.h>
int main(void) {
int arr[5] = {10, 20, 30, 40, 50};
for (int i = 0; i <= 5; i++) { /* BUG IS HERE */
printf("arr[%d] = %d\n", i, arr[i]);
}
return 0;
}
#include <stdio.h>
int main(void) {
int arr[5] = {10, 20, 30, 40, 50};
for (int i = 0; i < 5; i++) { /* FIXED: < not <= */
printf("arr[%d] = %d\n", i, arr[i]);
}
return 0;
}
i <= 5 allows i to reach the value 5. But for a 5-element array, valid indices are 0 through 4. arr[5] is one past the end of the array — accessing it is undefined behavior in C. On most systems this reads garbage memory; it could crash the program, print a random value, or seem to work fine (which is even more dangerous).The fix: Use
i < 5 (strict less-than). General rule: for an array of size N, loop with i < N. The indices 0, 1, 2, ..., N-1 give you exactly N iterations.
Print the integers 1 through 30. But for multiples of 3 print "Fizz" instead of the number, for multiples of 5 print "Buzz", and for multiples of both 3 and 5 print "FizzBuzz". Use a for loop and the % (modulo) operator.
#include <stdio.h>
int main(void) {
for (int i = 1; i <= 30; i++) {
/* Check divisible by BOTH first — order matters! */
if (i % 15 == 0) /* 15 = 3*5 */
printf("FizzBuzz\n");
else if (i % 3 == 0)
printf("Fizz\n");
else if (i % 5 == 0)
printf("Buzz\n");
else
printf("%d\n", i);
}
return 0;
}
% 3 first, a number like 15 would print "Fizz" and never reach the "Buzz" check. You need to handle the "both" case before the individual cases. Alternatively, you could build the output string conditionally, or use i % 3 == 0 && i % 5 == 0 — all equivalent.
The Collatz sequence starting from a positive integer n is defined as: if n is even, divide by 2; if n is odd, multiply by 3 and add 1. Repeat until n becomes 1. Write a program that reads n from the user and prints the Collatz sequence, then prints how many steps it took.
#include <stdio.h>
int main(void) {
int n;
printf("Enter a positive integer: ");
scanf("%d", &n);
if (n <= 0) {
printf("Error: must be positive.\n");
return 1;
}
int steps = 0;
printf("Sequence: %d", n);
while (n != 1) {
if (n % 2 == 0)
n = n / 2;
else
n = 3 * n + 1;
printf(" -> %d", n);
steps++;
}
printf("\nSteps: %d\n", steps);
return 0;
}
while is more natural than for. The loop terminates when n == 1.
Write a program that reads an odd number n from the user and prints a diamond of asterisks of "width" n. For n=5 the output should be: * *** ***** *** *
#include <stdio.h>
int main(void) {
int n;
printf("Enter an odd number: ");
scanf("%d", &n);
int half = n / 2;
/* Top half (including middle row) */
for (int row = 0; row <= half; row++) {
/* Print leading spaces */
for (int s = 0; s < half - row; s++) printf(" ");
/* Print stars */
for (int s = 0; s < 2*row + 1; s++) printf("*");
printf("\n");
}
/* Bottom half */
for (int row = half - 1; row >= 0; row--) {
for (int s = 0; s < half - row; s++) printf(" ");
for (int s = 0; s < 2*row + 1; s++) printf("*");
printf("\n");
}
return 0;
}
row from the top has half - row leading spaces and 2*row + 1 stars. The top half counts row from 0 to half (inclusive). The bottom half mirrors by counting row from half-1 back down to 0. This uses three nested loops per half — a common exam pattern for 2D output.
Write a simple menu-driven program. Show three options: (1) Print hello, (2) Print the current count, (3) Quit. Keep asking until the user picks 3. The program must always show the menu at least once. Use a do-while loop.
#include <stdio.h>
int main(void) {
int choice = 0;
int count = 0;
do {
printf("\n--- Menu ---\n");
printf("1. Say hello\n");
printf("2. Show count (%d)\n", count);
printf("3. Quit\n");
printf("Choice: ");
scanf("%d", &choice);
if (choice == 1) {
printf("Hello!\n");
count++;
} else if (choice == 2) {
printf("You have chosen an option %d time(s).\n", count);
} else if (choice != 3) {
printf("Invalid choice — please enter 1, 2, or 3.\n");
}
} while (choice != 3);
printf("Goodbye!\n");
return 0;
}
Key concepts to memorize
Test your understanding
for (int i = 0; i < 10; i++)LO1
do-while loop is guaranteed to execute its body at least once, even if the condition is false.LO1continue statement do inside a for loop?LO1for is for ( ___ ) — write the three semicolon-separated parts inside the parentheses (just two semicolons, no spaces).LO1int arr[5] = {1,2,3,4,5};
for (int i = 0; i <= 5; i++) {
printf("%d\n", arr[i]);
}
break statement is reached in the inner loop, what happens?LO1