Guaranteed Execution: A Complete Guide to the Do-While Loop in C

The do-while loop is a fundamental control structure in C that guarantees at least one execution of the loop body before checking the condition. Unlike the while loop that checks before execution, do-while is invaluable when you need to ensure a block of code runs at least once. This comprehensive guide explores every aspect of the do-while loop, from basic syntax to advanced patterns and optimization techniques.

Basic Syntax

#include <stdio.h>
int main() {
// Basic do-while syntax
int counter = 0;
do {
printf("Iteration: %d\n", counter);
counter++;
} while (counter < 5);
// Even if condition is false initially, body executes once
int x = 10;
do {
printf("This runs once even though condition is false\n");
} while (x < 5);
return 0;
}

Output:

Iteration: 0
Iteration: 1
Iteration: 2
Iteration: 3
Iteration: 4
This runs once even though condition is false

Anatomy of a Do-While Loop

#include <stdio.h>
int main() {
int i = 0;
// The structure
do {                    // 'do' keyword starts the loop
// Loop body
printf("i = %d\n", i);
i++;
} while (i < 5);        // Condition checked after body
// Semicolon is required!
// Break it down:
// 1. Execute loop body
// 2. Check condition
// 3. If true, go to step 1
// 4. If false, exit loop
return 0;
}

Simple Examples

1. Menu-Driven Programs

#include <stdio.h>
int main() {
int choice;
// Do-while is perfect for menus
do {
printf("\n=== Menu ===\n");
printf("1. Option 1\n");
printf("2. Option 2\n");
printf("3. Option 3\n");
printf("4. Exit\n");
printf("Enter choice: ");
scanf("%d", &choice);
if (choice == 1) {
printf("You selected Option 1\n");
} else if (choice == 2) {
printf("You selected Option 2\n");
} else if (choice == 3) {
printf("You selected Option 3\n");
} else if (choice != 4) {
printf("Invalid choice! Try again.\n");
}
} while (choice != 4);
printf("Goodbye!\n");
return 0;
}

2. Input Validation with Retry

#include <stdio.h>
#include <ctype.h>
int main() {
int age;
char response;
// Validate integer input
do {
printf("Enter your age (1-120): ");
if (scanf("%d", &age) != 1) {
// Clear invalid input
while (getchar() != '\n');
printf("Invalid input! Please enter a number.\n");
age = 0;  // Force retry
} else if (age < 1 || age > 120) {
printf("Age must be between 1 and 120.\n");
}
} while (age < 1 || age > 120);
printf("Age accepted: %d\n", age);
// Validate yes/no response
do {
printf("Continue? (y/n): ");
scanf(" %c", &response);
response = tolower(response);
if (response != 'y' && response != 'n') {
printf("Please enter 'y' or 'n'\n");
}
} while (response != 'y' && response != 'n');
if (response == 'y') {
printf("Continuing...\n");
} else {
printf("Exiting...\n");
}
return 0;
}

3. Number Guessing Game

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
int secret, guess;
int attempts = 0;
// Seed random number generator
srand(time(NULL));
secret = rand() % 100 + 1;  // 1-100
printf("Welcome to the Number Guessing Game!\n");
printf("I'm thinking of a number between 1 and 100.\n");
// Do-while ensures at least one guess
do {
printf("Enter your guess: ");
if (scanf("%d", &guess) != 1) {
while (getchar() != '\n');
printf("Please enter a valid number!\n");
continue;
}
attempts++;
if (guess < secret) {
printf("Too low! Try again.\n");
} else if (guess > secret) {
printf("Too high! Try again.\n");
} else {
printf("Congratulations! You guessed it in %d attempts!\n", attempts);
}
} while (guess != secret);
return 0;
}

While vs Do-While Comparison

#include <stdio.h>
int main() {
int count = 5;
// While loop - may execute zero times
printf("While loop:\n");
while (count < 5) {
printf("  This never prints\n");
count++;
}
// Do-while loop - executes at least once
count = 5;
printf("\nDo-while loop:\n");
do {
printf("  This prints once even though condition is false\n");
count++;
} while (count < 5);
// Practical difference: reading input
char c;
// While loop: need to initialize before
printf("\nWhile reading:\n");
c = getchar();
while (c != '\n' && c != EOF) {
putchar(c);
c = getchar();
}
// Do-while loop: cleaner for this pattern
printf("\nDo-while reading:\n");
do {
c = getchar();
if (c != '\n' && c != EOF) {
putchar(c);
}
} while (c != '\n' && c != EOF);
return 0;
}

Nested Do-While Loops

#include <stdio.h>
int main() {
int i = 1, j;
// Multiplication table with nested do-while
printf("Multiplication Table (1-5):\n\n");
do {
j = 1;
do {
printf("%2d ", i * j);
j++;
} while (j <= 5);
printf("\n");
i++;
} while (i <= 5);
// Triangle pattern
printf("\nTriangle Pattern:\n");
i = 1;
do {
j = 1;
do {
printf("* ");
j++;
} while (j <= i);
printf("\n");
i++;
} while (i <= 5);
return 0;
}

Output:

Multiplication Table (1-5):
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:
* 
* * 
* * * 
* * * * 
* * * * *

Advanced Patterns

1. Sentinels and Input Validation

#include <stdio.h>
#include <string.h>
int main() {
char input[100];
int numbers[100];
int count = 0;
int sum = 0;
printf("Enter numbers (enter 'done' to finish):\n");
// Sentinel-controlled loop
do {
printf("Number %d: ", count + 1);
scanf("%s", input);
if (strcmp(input, "done") == 0) {
break;
}
numbers[count] = atoi(input);
sum += numbers[count];
count++;
} while (count < 100);
printf("\nYou entered %d numbers\n", count);
if (count > 0) {
printf("Sum: %d\n", sum);
printf("Average: %.2f\n", (double)sum / count);
}
return 0;
}

2. Menu with Submenus

#include <stdio.h>
int main() {
int main_choice, sub_choice;
do {
printf("\n=== Main Menu ===\n");
printf("1. File Operations\n");
printf("2. Edit Operations\n");
printf("3. View Operations\n");
printf("4. Exit\n");
printf("Choose: ");
scanf("%d", &main_choice);
switch(main_choice) {
case 1:
do {
printf("\n--- File Menu ---\n");
printf("1. Open\n");
printf("2. Save\n");
printf("3. Save As\n");
printf("4. Back to Main\n");
printf("Choose: ");
scanf("%d", &sub_choice);
if (sub_choice == 1) printf("  Opening file...\n");
else if (sub_choice == 2) printf("  Saving file...\n");
else if (sub_choice == 3) printf("  Save As...\n");
else if (sub_choice != 4) printf("  Invalid choice!\n");
} while (sub_choice != 4);
break;
case 2:
do {
printf("\n--- Edit Menu ---\n");
printf("1. Cut\n");
printf("2. Copy\n");
printf("3. Paste\n");
printf("4. Back to Main\n");
printf("Choose: ");
scanf("%d", &sub_choice);
if (sub_choice == 1) printf("  Cut operation\n");
else if (sub_choice == 2) printf("  Copy operation\n");
else if (sub_choice == 3) printf("  Paste operation\n");
else if (sub_choice != 4) printf("  Invalid choice!\n");
} while (sub_choice != 4);
break;
case 3:
do {
printf("\n--- View Menu ---\n");
printf("1. Zoom In\n");
printf("2. Zoom Out\n");
printf("3. Full Screen\n");
printf("4. Back to Main\n");
printf("Choose: ");
scanf("%d", &sub_choice);
if (sub_choice == 1) printf("  Zooming in...\n");
else if (sub_choice == 2) printf("  Zooming out...\n");
else if (sub_choice == 3) printf("  Full screen mode\n");
else if (sub_choice != 4) printf("  Invalid choice!\n");
} while (sub_choice != 4);
break;
case 4:
printf("Goodbye!\n");
break;
default:
printf("Invalid choice! Please try again.\n");
}
} while (main_choice != 4);
return 0;
}

3. Fibonacci Sequence with Do-While

#include <stdio.h>
int main() {
int n, count = 0;
long long first = 0, second = 1, next;
printf("How many Fibonacci numbers? ");
scanf("%d", &n);
if (n <= 0) {
printf("Invalid number\n");
return 1;
}
printf("Fibonacci sequence: ");
do {
printf("%lld ", first);
next = first + second;
first = second;
second = next;
count++;
} while (count < n);
printf("\n");
return 0;
}

Error Handling with Do-While

#include <stdio.h>
#include <errno.h>
#include <string.h>
int main() {
FILE *file;
char filename[100];
int success = 0;
do {
printf("Enter filename: ");
scanf("%s", filename);
file = fopen(filename, "r");
if (file == NULL) {
printf("Error opening '%s': %s\n", filename, strerror(errno));
printf("Would you like to try again? (y/n): ");
char response;
scanf(" %c", &response);
if (response != 'y' && response != 'Y') {
break;
}
} else {
success = 1;
printf("File opened successfully!\n");
// Read and display file contents
char ch;
while ((ch = fgetc(file)) != EOF) {
putchar(ch);
}
fclose(file);
}
} while (!success);
return 0;
}

Performance Considerations

1. Loop Unrolling with Do-While

#include <stdio.h>
#include <time.h>
void process_standard(int *arr, int n) {
for (int i = 0; i < n; i++) {
arr[i] = arr[i] * 2;
}
}
void process_unrolled(int *arr, int n) {
int i = 0;
// Process 4 at a time
int limit = n - 3;
do {
arr[i] *= 2;
arr[i+1] *= 2;
arr[i+2] *= 2;
arr[i+3] *= 2;
i += 4;
} while (i < limit);
// Handle remaining elements
while (i < n) {
arr[i] *= 2;
i++;
}
}
int main() {
const int SIZE = 10000000;
int *arr1 = malloc(SIZE * sizeof(int));
int *arr2 = malloc(SIZE * sizeof(int));
// Initialize arrays
for (int i = 0; i < SIZE; i++) {
arr1[i] = arr2[i] = i;
}
clock_t start, end;
start = clock();
process_standard(arr1, SIZE);
end = clock();
printf("Standard loop: %.3f seconds\n", 
(double)(end - start) / CLOCKS_PER_SEC);
start = clock();
process_unrolled(arr2, SIZE);
end = clock();
printf("Unrolled do-while: %.3f seconds\n", 
(double)(end - start) / CLOCKS_PER_SEC);
free(arr1);
free(arr2);
return 0;
}

2. Loop Fusion

#include <stdio.h>
// Separate loops (more iterations)
void separate_loops(int *a, int *b, int n) {
int i = 0;
do {
a[i] = a[i] * 2;
i++;
} while (i < n);
i = 0;
do {
b[i] = b[i] + 10;
i++;
} while (i < n);
}
// Fused loop (better cache locality)
void fused_loop(int *a, int *b, int n) {
int i = 0;
do {
a[i] = a[i] * 2;
b[i] = b[i] + 10;
i++;
} while (i < n);
}

Common Pitfalls and Best Practices

1. Infinite Loops

#include <stdio.h>
int main() {
int i = 0;
// WRONG: Missing update - infinite loop
do {
printf("This prints forever\n");
// i never increments!
} while (i < 10);
// WRONG: Using = instead of ==
do {
// ...
} while (i = 0);  // Assignment, not comparison - always true
// RIGHT: Proper update
do {
printf("This runs 10 times\n");
i++;
} while (i < 10);
return 0;
}

2. Variable Scope

#include <stdio.h>
int main() {
// Variables declared in loop body are recreated each iteration
do {
int temp = 0;  // New variable each iteration
temp++;
printf("temp = %d\n", temp);  // Always prints 1
} while (0);
// Use outer scope if you need persistence
int persistent = 0;
do {
persistent++;
printf("persistent = %d\n", persistent);
} while (persistent < 3);
return 0;
}

3. Semicolon Placement

#include <stdio.h>
int main() {
int i = 0;
// WRONG: Semicolon after do
do; {  // Empty loop body!
printf("This is not in the loop\n");
} while (i < 5);
// WRONG: Missing semicolon after while
do {
printf("Compilation error!\n");
} while (i < 5)  // Missing semicolon
// RIGHT: Proper semicolon placement
do {
printf("Correct syntax\n");
} while (i < 5);
return 0;
}

4. Avoiding Complex Conditions

#include <stdio.h>
// BAD: Complex condition
int complex_loop_bad(int *arr, int n) {
int i = 0;
do {
if (arr[i] < 0 || arr[i] > 100 || i % 2 == 0 || (arr[i] * 2) > 200) {
// Complex logic
}
i++;
} while (i < n && arr[i-1] != -1);
}
// GOOD: Simplify with flags and helper functions
int is_valid(int value) {
return value >= 0 && value <= 100;
}
int is_special(int value) {
return value * 2 > 200;
}
int complex_loop_good(int *arr, int n) {
int i = 0;
do {
if (is_valid(arr[i]) && (i % 2 == 0 || is_special(arr[i]))) {
// Clear logic
}
i++;
} while (i < n && arr[i-1] != -1);
}

Complete Example: ATM Simulation

#include <stdio.h>
#include <string.h>
#define MAX_PIN 4
int main() {
int pin;
int attempts = 0;
int balance = 1000;
int amount;
int choice;
char transaction_history[100][100];
int transaction_count = 0;
// PIN validation
do {
printf("Enter PIN (4 digits): ");
scanf("%d", &pin);
attempts++;
if (pin != 1234) {
printf("Invalid PIN. %d attempts remaining.\n", 3 - attempts);
}
} while (pin != 1234 && attempts < 3);
if (pin != 1234) {
printf("Too many failed attempts. Card blocked.\n");
return 1;
}
printf("\n=== ATM Menu ===\n");
printf("Welcome! PIN accepted.\n\n");
// Main menu loop
do {
printf("\n1. Check Balance\n");
printf("2. Deposit\n");
printf("3. Withdraw\n");
printf("4. Transaction History\n");
printf("5. Exit\n");
printf("Choose: ");
scanf("%d", &choice);
if (choice == 1) {
printf("\nYour balance: $%d\n", balance);
sprintf(transaction_history[transaction_count++], 
"Balance check: $%d", balance);
} else if (choice == 2) {
do {
printf("Enter deposit amount: $");
scanf("%d", &amount);
if (amount <= 0) {
printf("Amount must be positive.\n");
} else {
balance += amount;
printf("Deposited $%d. New balance: $%d\n", amount, balance);
sprintf(transaction_history[transaction_count++], 
"Deposit: +$%d", amount);
}
} while (amount <= 0);
} else if (choice == 3) {
do {
printf("Enter withdrawal amount: $");
scanf("%d", &amount);
if (amount <= 0) {
printf("Amount must be positive.\n");
} else if (amount > balance) {
printf("Insufficient funds. Available: $%d\n", balance);
} else {
balance -= amount;
printf("Withdrew $%d. New balance: $%d\n", amount, balance);
sprintf(transaction_history[transaction_count++], 
"Withdrawal: -$%d", amount);
}
} while (amount <= 0 || amount > balance);
} else if (choice == 4) {
printf("\n--- Transaction History ---\n");
if (transaction_count == 0) {
printf("No transactions yet.\n");
} else {
for (int i = 0; i < transaction_count; i++) {
printf("%s\n", transaction_history[i]);
}
}
} else if (choice != 5) {
printf("Invalid choice. Please try again.\n");
}
} while (choice != 5);
printf("\nThank you for banking with us!\n");
printf("Final balance: $%d\n", balance);
return 0;
}

Do-While with Break and Continue

#include <stdio.h>
int main() {
int i = 0;
// Using continue
do {
i++;
if (i % 2 == 0) {
continue;  // Skip even numbers
}
printf("%d ", i);
} while (i < 10);
printf("\n");
// Using break
i = 0;
do {
i++;
if (i == 5) {
break;  // Exit loop when i reaches 5
}
printf("%d ", i);
} while (i < 10);
printf("\n");
// Nested loops with break
int found = 0;
int matrix[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
int target = 5;
int row = 0, col = 0;
do {
col = 0;
do {
if (matrix[row][col] == target) {
found = 1;
break;
}
col++;
} while (col < 3);
if (found) break;
row++;
} while (row < 3);
if (found) {
printf("Found %d at [%d][%d]\n", target, row, col);
}
return 0;
}

Summary: When to Use Do-While

ScenarioBest ChoiceReason
Menu displayDo-whileAlways show menu at least once
Input validationDo-whileNeed to get input before validation
Reading until sentinelDo-whileNeed to read first value before checking
Number guessing gameDo-whilePlayer must guess at least once
Initialization requiredWhileMight not need to execute at all
Simple counter loopsForClear initialization, condition, update

Best Practices Summary

  1. Always use braces: Even for single statements, braces improve readability
  2. Maintain loop invariants: Keep loop conditions clear and correct
  3. Update loop variables: Ensure loop termination condition is eventually met
  4. Avoid complex conditions: Use helper functions for readability
  5. Use appropriate loop type: Choose do-while when at least one iteration is required
  6. Handle infinite loops: Always ensure termination condition is reachable
  7. Keep loop bodies focused: One responsibility per loop
  8. Document complex logic: Comment non-obvious conditions

Conclusion

The do-while loop is an essential tool in the C programmer's arsenal, providing guaranteed execution for scenarios where code must run at least once. Its primary use cases include:

  • Menu systems: Always display the menu before processing choice
  • Input validation: Get input before validating it
  • Games: Player must take at least one turn
  • Sentinel loops: Process data until a termination condition is met

Unlike while and for loops, the do-while loop's post-test condition makes it uniquely suited for these patterns. Understanding when to use do-while versus other loop constructs leads to cleaner, more intuitive code that clearly expresses programmer intent.

With proper use of do-while, along with break, continue, and careful condition design, you can create robust, user-friendly programs that handle edge cases gracefully and provide a smooth user experience.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper