Loops in C practice — 3 real programs with for, while and do…while
In the previous article we covered C loops theory. Now it’s time to write real programs. In this article we build three programs from scratch using gedit and gcc in Fedora — a number guessing game, a data validator and a series calculator. Each one uses the loop that genuinely makes the most sense for that problem, showing why the choice between for, while and do...while isn’t arbitrary.
Set up your workspace:
cd ~/GCID/IC2/Labs mkdir Lab_loops cd Lab_loops
Table of Contents
Loops in C practice — Program 1: Number guessing game with while
This is the classic guessing game — the player has unlimited attempts to guess a secret number between 1 and 100. It’s a perfect while case because we don’t know how many guesses the player will need.
touch guessing.c gedit guessing.c &
#include <stdio.h>
#include <stdlib.h> /* rand(), srand() */
#include <time.h> /* time() */
int main() {
int secret, guess, attempts, low, high;
int found = 0;
/* Seed random number generator */
srand(time(NULL));
secret = (rand() % 100) + 1; /* 1 to 100 */
low = 1;
high = 100;
attempts = 0;
printf("=== GUESS THE NUMBER ===\n");
printf("I'm thinking of a number between 1 and 100\n\n");
while (!found) {
printf("Attempt %d [%d-%d]: ", attempts + 1, low, high);
scanf("%d", &guess);
/* Validate range */
if (guess < 1 || guess > 100) {
printf("Please guess between 1 and 100\n\n");
continue; /* don't count this attempt */
}
attempts++;
if (guess < secret) {
printf("Too low\n\n");
if (guess > low) low = guess; /* narrow the range */
} else if (guess > secret) {
printf("Too high\n\n");
if (guess < high) high = guess;
} else {
printf("\nCorrect! The number was %d\n", secret);
printf("You found it in %d attempt(s)\n\n", attempts);
found = 1;
}
}
/* Rating */
printf("Rating: ");
if (attempts == 1) {
printf("Psychic! One shot!\n");
} else if (attempts <= 3) {
printf("Incredible!\n");
} else if (attempts <= 6) {
printf("Great job!\n");
} else if (attempts <= 10) {
printf("Good — within normal range\n");
} else {
printf("Keep practising — optimal is 7 attempts\n");
}
/* Explain optimal strategy */
printf("\nFun fact: binary search finds any number in at most 7 attempts.\n");
printf("Always guess the midpoint of the remaining range.\n");
return 0;
}
gcc guessing.c -o guessing -Wall ./guessing
Output:
=== GUESS THE NUMBER === I'm thinking of a number between 1 and 100 Attempt 1 [1-100]: 50 Too high Attempt 2 [1-50]: 25 Too low Attempt 3 [25-50]: 37 Correct! The number was 37 You found it in 3 attempts Rating: Incredible! Fun fact: binary search finds any number in at most 7 attempts. Always guess the midpoint of the remaining range.
Why while and not for? Because found = 0 starts false and becomes true at an unknown point in the future. The loop doesn’t know how many iterations it will run — that depends entirely on the player’s guesses. A for needs a known iteration count.
Notice the continue for invalid guesses — it skips the rest of the loop body and goes straight back to the condition check, without incrementing attempts. The range narrowing (low and high updating) is a nice touch — the program shows the player what range is still valid after each guess.
Loops in C practice — Program 2: Data validator with do…while
This program reads a series of numbers from the user and calculates statistics. It uses do...while for the menu (must show at least once) and while for input validation (repeat until valid).
touch validator.c gedit validator.c &
#include <stdio.h>
#define MAX_VALUES 100
int main() {
double values[MAX_VALUES];
int count = 0;
int option;
printf("=== DATA VALIDATOR AND STATISTICS ===\n\n");
/* Input loop — do...while so menu always shows once */
do {
printf("--- Menu ---\n");
printf("1. Enter a value\n");
printf("2. See statistics\n");
printf("3. Show all values\n");
printf("4. Reset\n");
printf("0. Exit\n");
printf("Option: ");
scanf("%d", &option);
printf("\n");
switch (option) {
case 1: {
if (count >= MAX_VALUES) {
printf("Maximum capacity reached (%d values)\n\n", MAX_VALUES);
break;
}
double val;
int valid = 0;
/* Inner while — validate the value before accepting it */
while (!valid) {
printf("Enter value (must be between -1000 and 1000): ");
scanf("%lf", &val);
if (val < -1000 || val > 1000) {
printf("Error: value out of range. Try again.\n");
} else {
valid = 1;
}
}
values[count] = val;
count++;
printf("Value %.2f added. Total: %d value(s)\n\n", val, count);
break;
}
case 2: {
if (count == 0) {
printf("No values entered yet\n\n");
break;
}
double sum = 0, min = values[0], max = values[0];
int positives = 0, negatives = 0, zeros = 0;
for (int i = 0; i < count; i++) {
sum += values[i];
if (values[i] < min) min = values[i];
if (values[i] > max) max = values[i];
if (values[i] > 0) positives++;
else if (values[i] < 0) negatives++;
else zeros++;
}
double average = sum / count;
printf("--- Statistics (%d values) ---\n", count);
printf("Sum: %.2f\n", sum);
printf("Average: %.2f\n", average);
printf("Minimum: %.2f\n", min);
printf("Maximum: %.2f\n", max);
printf("Range: %.2f\n", max - min);
printf("Positives: %d\n", positives);
printf("Negatives: %d\n", negatives);
printf("Zeros: %d\n\n", zeros);
break;
}
case 3: {
if (count == 0) {
printf("No values entered yet\n\n");
break;
}
printf("--- All %d values ---\n", count);
for (int i = 0; i < count; i++) {
printf(" [%2d] %.2f\n", i + 1, values[i]);
}
printf("\n");
break;
}
case 4:
count = 0;
printf("Data reset. All values deleted.\n\n");
break;
case 0:
printf("Goodbye!\n");
break;
default:
printf("Invalid option — choose between 0 and 4\n\n");
}
} while (option != 0);
return 0;
}
gcc validator.c -o validator -Wall ./validator
Output after entering 3 values (5.5, -3.0, 8.0) and requesting statistics:
--- Statistics (3 values) --- Sum: 10.50 Average: 3.50 Minimum: -3.00 Maximum: 8.00 Range: 11.00 Positives: 2 Negatives: 1 Zeros: 0
This program uses do...while for the outer menu because you always need to show it at least once. The inner while for value validation repeats until the user enters a valid number — you don’t know how many invalid attempts they’ll make. The for inside case 2 iterates a known number of times (count values) to calculate statistics. Three loops, three different situations, three different choices.
#define MAX_VALUES 100 is a preprocessor constant — it defines the maximum size of the array at compile time. Using it instead of the literal 100 everywhere means if you want to change the limit later you only change it in one place.
Loops in C practice — Program 3: Series calculator with for
A series in mathematics is the sum of a sequence of terms following a pattern. This program calculates three classic series — each one a perfect use case for for because the number of terms is always known in advance.
touch series.c gedit series.c &
#include <stdio.h>
int main() {
int n, option;
printf("=== SERIES CALCULATOR ===\n\n");
printf("Series to calculate:\n");
printf("1. Sum of first N natural numbers (1+2+3+...+N)\n");
printf("2. Sum of squares (1²+2²+3²+...+N²)\n");
printf("3. Fibonacci series (first N terms)\n");
printf("4. Powers of 2 (2⁰+2¹+2²+...+2^N)\n");
printf("0. Exit\n\n");
do {
printf("Option: ");
scanf("%d", &option);
if (option == 0) {
printf("Goodbye!\n");
break;
}
if (option < 1 || option > 4) {
printf("Invalid option\n\n");
continue;
}
printf("Number of terms (N): ");
scanf("%d", &n);
if (n <= 0) {
printf("N must be positive\n\n");
continue;
}
printf("\n--- Result ---\n");
switch (option) {
case 1: {
/* Sum: 1 + 2 + 3 + ... + N */
long sum = 0;
printf("Sum 1 to %d: ", n);
for (int i = 1; i <= n; i++) {
sum += i;
if (i <= 5 || i == n) {
printf("%d", i);
if (i < n) printf("+");
} else if (i == 6) {
printf("...");
}
}
printf(" = %ld\n", sum);
/* Verify with formula: N*(N+1)/2 */
long formula = (long)n * (n + 1) / 2;
printf("Formula N*(N+1)/2 = %ld ✓\n\n", formula);
break;
}
case 2: {
/* Sum of squares: 1² + 2² + ... + N² */
long sum = 0;
printf("Sum of squares 1 to %d:\n", n);
for (int i = 1; i <= n; i++) {
sum += (long)i * i;
}
printf("Result: %ld\n", sum);
/* Show first few terms */
printf("Terms: ");
for (int i = 1; i <= n && i <= 6; i++) {
printf("%d²=%d", i, i*i);
if (i < n) printf(" + ");
}
if (n > 6) printf(" + ...");
printf("\n\n");
break;
}
case 3: {
/* Fibonacci: 0, 1, 1, 2, 3, 5, 8, ... */
printf("Fibonacci (%d terms): ", n);
long prev = 0, curr = 1, next;
if (n >= 1) printf("%ld", prev);
if (n >= 2) printf(", %ld", curr);
for (int i = 3; i <= n; i++) {
next = prev + curr;
printf(", %ld", next);
prev = curr;
curr = next;
}
/* Show last calculated value */
printf("\nTerm %d = %ld\n\n", n, (n == 1) ? prev : curr);
break;
}
case 4: {
/* Powers of 2: 2⁰ + 2¹ + 2² + ... + 2^N */
long sum = 0;
long power = 1;
printf("Powers of 2 (0 to %d):\n", n-1);
for (int i = 0; i < n; i++) {
printf(" 2^%d = %ld\n", i, power);
sum += power;
power *= 2;
}
printf("Sum = %ld\n", sum);
printf("Formula 2^N - 1 = %ld ✓\n\n", (long)power - 1);
break;
}
}
printf("--- New calculation ---\n");
} while (option != 0);
return 0;
}
gcc series.c -o series -Wall ./series
Output with option 1, N=10:
--- Result --- Sum 1 to 10: 1+2+3+4+5+...10 = 55 Formula N*(N+1)/2 = 55 ✓
Output with option 3 (Fibonacci), N=8:
--- Result --- Fibonacci (8 terms): 0, 1, 1, 2, 3, 5, 8, 13 Term 8 = 13
Why for for all series? Because N is always known before the loop starts — you know exactly how many terms you’ll calculate. The loop counter is the term number. This is the textbook case for for.
The long type for accumulation is important — sums of squares or powers of 2 grow quickly and overflow int with large N. long gives 64 bits of range, enough for serious series calculations. The cast (long)n * (n + 1) / 2 is also important — without it n * (n + 1) could overflow int before being divided.
The three loops — when each one showed up
Program 1 — while: unknown iterations (player's guesses) Program 2 — do...while: menu needs at least one execution Program 2 — while: input validation, unknown retries Program 2 — for: statistics over known count of values Program 3 — do...while: outer menu Program 3 — for: series with known number of terms
Visualise with Python Tutor
Select C from the dropdown and paste in pythontutor.com this to compare all three loops side by side:
#include <stdio.h>
int main() {
int sum_for = 0;
for (int i = 1; i <= 5; i++) {
sum_for += i;
}
printf("for sum: %d\n", sum_for);
int sum_while = 0, j = 1;
while (j <= 5) {
sum_while += j;
j++;
}
printf("while sum: %d\n", sum_while);
int sum_do = 0, k = 1;
do {
sum_do += k;
k++;
} while (k <= 5);
printf("do...while sum: %d\n", sum_do);
return 0;
}
Step through all three and compare. for manages the counter in one place — init, check and increment are all visible in the first line. while needs j = 1 before and j++ inside — more spread out. do...while executes the body once before any check — try changing k = 1 to k = 10 and watch it still add 10 to sum_do before the condition k <= 5 is evaluated and found false. That first unconditional execution is the key characteristic of do...while.
Summary and next step
In this article you practised C loops with three real programs. You used while for unknown-count loops, do...while for menus and validation, and for for series with known terms. You saw continue to skip invalid input without counting it, break to exit a loop on success, nested loops for statistics, and long to avoid integer overflow in accumulations.
In the next article you’ll find exercises to solve on your own in Fedora.

2 Comments