Loops
Introduction
Loops are control structures that allow programs to repeat a block of code multiple times. They are essential for processing collections of data, implementing algorithms, and automating repetitive tasks. C provides three main types of loops: while, do-while, and for, each with specific use cases and characteristics.
Understanding loops is crucial for efficient programming, as they enable you to write concise code that can handle large amounts of data or perform complex calculations. This chapter will explore all loop types in detail, their syntax, best practices, and common applications.
The while Loop
The while loop repeatedly executes a block of code as long as a specified condition remains true. It’s a pre-test loop, meaning the condition is evaluated before each iteration.
Basic Syntax
while (condition) {
// Code to execute repeatedly
}Simple while Loop Example
#include <stdio.h>
int main() {
int count = 1;
while (count <= 5) {
printf("Count: %d\n", count);
count++; // Important: update the loop variable
}
return 0;
}while Loop with User Input
#include <stdio.h>
int main() {
int number;
printf("Enter positive numbers (0 to stop):\n");
scanf("%d", &number);
while (number > 0) {
printf("You entered: %d\n", number);
scanf("%d", &number);
}
printf("Loop ended.\n");
return 0;
}The do-while Loop
The do-while loop is a post-test loop, meaning the code block is executed at least once before the condition is evaluated. This guarantees that the loop body executes at least once.
Basic Syntax
do {
// Code to execute
} while (condition);Simple do-while Example
#include <stdio.h>
int main() {
int count = 1;
do {
printf("Count: %d\n", count);
count++;
} while (count <= 5);
return 0;
}The for Loop
The for loop is ideal when you know the exact number of iterations or have a clear initialization, condition, and update pattern. It combines all loop control elements in one line.
Basic Syntax
for (initialization; condition; update) {
// Code to execute repeatedly
}Simple for Loop Example
#include <stdio.h>
int main() {
for (int i = 1; i <= 5; i++) {
printf("Count: %d\n", i);
}
return 0;
}for Loop with Arrays
#include <stdio.h>
int main() {
int numbers[] = {10, 20, 30, 40, 50};
int size = sizeof(numbers) / sizeof(numbers[0]);
printf("Array elements:\n");
for (int i = 0; i < size; i++) {
printf("numbers[%d] = %d\n", i, numbers[i]);
}
return 0;
}Loop Control Statements
C provides two statements to control loop execution: break and continue.
break Statement
The break statement immediately terminates the loop, transferring control to the statement following the loop.
#include <stdio.h>
int main() {
for (int i = 1; i <= 10; i++) {
if (i == 5) {
break; // Exit the loop when i equals 5
}
printf("Count: %d\n", i);
}
printf("Loop ended.\n");
return 0;
}continue Statement
The continue statement skips the remaining code in the current iteration and proceeds to the next iteration.
#include <stdio.h>
int main() {
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) {
continue; // Skip even numbers
}
printf("Odd number: %d\n", i);
}
return 0;
}Nested Loops
Loops can be nested within other loops to handle multi-dimensional data structures or complex iterations.
Nested for Loops
#include <stdio.h>
int main() {
// Print multiplication table
for (int i = 1; i <= 5; i++) {
for (int j = 1; j <= 5; j++) {
printf("%d ", i * j);
}
printf("\n");
}
return 0;
}Nested Loops with break and continue
#include <stdio.h>
int main() {
for (int i = 1; i <= 3; i++) {
printf("Outer loop: %d\n", i);
for (int j = 1; j <= 5; j++) {
if (j == 3) {
continue; // Skip j = 3 in inner loop
}
if (i == 2 && j == 4) {
break; // Break inner loop when i=2 and j=4
}
printf(" Inner loop: %d\n", j);
}
}
return 0;
}Infinite Loops
Infinite loops run indefinitely unless interrupted by a break statement or external intervention.
Creating Infinite Loops
#include <stdio.h>
int main() {
// Method 1: while with true condition
int count = 0;
while (1) { // Always true
printf("Count: %d\n", count);
count++;
if (count >= 5) {
break; // Exit condition
}
}
// Method 2: for loop with no conditions
for (;;) {
printf("Infinite loop iteration\n");
break; // Prevent actual infinite execution
}
return 0;
}Loop Performance Considerations
Efficient Loop Writing
#include <stdio.h>
int main() {
int array[1000];
int size = 1000;
// Inefficient: calculating size in each iteration
for (int i = 0; i < sizeof(array) / sizeof(array[0]); i++) {
array[i] = i;
}
// Efficient: calculate size once
int array_size = sizeof(array) / sizeof(array[0]);
for (int i = 0; i < array_size; i++) {
array[i] = i;
}
return 0;
}Loop Unrolling (Manual Optimization)
#include <stdio.h>
int main() {
int array[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int sum = 0;
// Standard loop
for (int i = 0; i < 10; i++) {
sum += array[i];
}
printf("Sum (standard): %d\n", sum);
// Loop unrolling (manual optimization)
sum = 0;
sum += array[0] + array[1] + array[2] + array[3] + array[4];
sum += array[5] + array[6] + array[7] + array[8] + array[9];
printf("Sum (unrolled): %d\n", sum);
return 0;
}Best Practices for Loops
1. Initialize Loop Variables Properly
// Good: Clear initialization
for (int i = 0; i < 10; i++) {
// Loop body
}
// Avoid: Unclear initialization
int i;
for (i = 0; i < 10; i++) {
// Loop body
}2. Use Meaningful Loop Variable Names
// Good: Descriptive names
for (int student_index = 0; student_index < num_students; student_index++) {
process_student(student_index);
}
// Avoid: Generic names for complex loops
for (int i = 0; i < num_students; i++) {
process_student(i);
}3. Avoid Modifying Loop Variables Inside Loop
// Good: Clear loop control
for (int i = 0; i < 10; i++) {
if (some_condition) {
break; // Use break to exit
}
// Process data
}
// Avoid: Modifying loop variable inside loop
for (int i = 0; i < 10; i++) {
if (some_condition) {
i += 5; // Confusing control flow
}
// Process data
}4. Choose the Right Loop Type
// Use while when condition is complex or unknown
int input;
printf("Enter positive numbers (0 to stop): ");
scanf("%d", &input);
while (input > 0) {
process_number(input);
scanf("%d", &input);
}
// Use for when iterations are known
for (int i = 0; i < 10; i++) {
process_item(i);
}
// Use do-while when at least one execution is needed
char choice;
do {
display_menu();
scanf(" %c", &choice);
} while (choice != 'q' && choice != 'Q');Common Pitfalls and How to Avoid Them
1. Infinite Loops
#include <stdio.h>
int main() {
// Wrong: Loop variable not updated
int i = 0;
while (i < 10) {
printf("Count: %d\n", i);
// Missing i++; causes infinite loop
}
// Correct: Loop variable updated
i = 0;
while (i < 10) {
printf("Count: %d\n", i);
i++; // Loop variable updated
}
return 0;
}2. Off-by-One Errors
#include <stdio.h>
int main() {
int array[5] = {1, 2, 3, 4, 5};
// Wrong: Accesses array[5] which is out of bounds
for (int i = 0; i <= 5; i++) {
printf("array[%d] = %d\n", i, array[i]); // Error on last iteration
}
// Correct: Proper bounds checking
for (int i = 0; i < 5; i++) {
printf("array[%d] = %d\n", i, array[i]);
}
return 0;
}3. Floating-Point Loop Variables
#include <stdio.h>
int main() {
// Wrong: Floating-point loop variables can cause precision issues
for (float x = 0.1f; x != 1.0f; x += 0.1f) {
printf("x = %.20f\n", x);
}
// Correct: Use integer loop variables for counting
for (int i = 1; i <= 10; i++) {
float x = i * 0.1f;
printf("x = %.20f\n", x);
}
return 0;
}Practical Examples
Number Pattern Generator
#include <stdio.h>
int main() {
int rows = 5;
// Right-angled triangle pattern
printf("Right-angled triangle:\n");
for (int i = 1; i <= rows; i++) {
for (int j = 1; j <= i; j++) {
printf("* ");
}
printf("\n");
}
// Pyramid pattern
printf("\nPyramid:\n");
for (int i = 1; i <= rows; i++) {
// Print spaces
for (int j = 1; j <= rows - i; j++) {
printf(" ");
}
// Print stars
for (int k = 1; k <= 2 * i - 1; k++) {
printf("*");
}
printf("\n");
}
return 0;
}Prime Number Finder
#include <stdio.h>
#include <stdbool.h>
bool is_prime(int num) {
if (num <= 1) return false;
if (num <= 3) return true;
if (num % 2 == 0 || num % 3 == 0) return false;
for (int i = 5; i * i <= num; i += 6) {
if (num % i == 0 || num % (i + 2) == 0) {
return false;
}
}
return true;
}
int main() {
int limit = 50;
printf("Prime numbers up to %d:\n", limit);
// Using while loop
int num = 2;
while (num <= limit) {
if (is_prime(num)) {
printf("%d ", num);
}
num++;
}
printf("\n");
// Using for loop
printf("Prime numbers (for loop):\n");
for (int i = 2; i <= limit; i++) {
if (is_prime(i)) {
printf("%d ", i);
}
}
printf("\n");
return 0;
}Array Processing with Loops
#include <stdio.h>
int main() {
int numbers[] = {12, 7, 23, 8, 15, 3, 19, 11, 5, 17};
int size = sizeof(numbers) / sizeof(numbers[0]);
// Find maximum value
int max = numbers[0];
for (int i = 1; i < size; i++) {
if (numbers[i] > max) {
max = numbers[i];
}
}
printf("Maximum value: %d\n", max);
// Calculate average
int sum = 0;
for (int i = 0; i < size; i++) {
sum += numbers[i];
}
double average = (double)sum / size;
printf("Average: %.2f\n", average);
// Count even numbers
int even_count = 0;
for (int i = 0; i < size; i++) {
if (numbers[i] % 2 == 0) {
even_count++;
}
}
printf("Even numbers count: %d\n", even_count);
// Reverse array
printf("Original array: ");
for (int i = 0; i < size; i++) {
printf("%d ", numbers[i]);
}
printf("\n");
// Reverse using two pointers
for (int i = 0, j = size - 1; i < j; i++, j--) {
int temp = numbers[i];
numbers[i] = numbers[j];
numbers[j] = temp;
}
printf("Reversed array: ");
for (int i = 0; i < size; i++) {
printf("%d ", numbers[i]);
}
printf("\n");
return 0;
}Summary
In this chapter, you’ve learned about:
- while Loops: Pre-test loops for unknown iteration counts
- do-while Loops: Post-test loops that execute at least once
- for Loops: Count-controlled loops with initialization, condition, and update
- Loop Control: break and continue statements for flow control
- Nested Loops: Loops within loops for multi-dimensional processing
- Infinite Loops: Loops that run indefinitely
- Performance Considerations: Efficient loop writing practices
- Best Practices: Writing clean, maintainable loop code
- Common Pitfalls: Avoiding typical loop errors
Loops are fundamental to programming and enable efficient processing of data collections, implementation of algorithms, and automation of repetitive tasks. With this knowledge, you’re now ready to tackle more complex programming challenges in the next chapter on advanced control flow.