Use of the while loop in C involves patterns like the "loop-and-a-half" (while(1)) for middle-exit conditions, using assignments with side effects in the condition for concise input processing, and for pointer-based traversal of data structures.
Uses of the while Loop in C ♾️
Beyond simple counter-based loops, the while loop's flexible condition makes it ideal for a variety of programming patterns where the number of iterations is not known in advance.
1. The "Loop and a Half" Idiom with while(1)
Standard while and for loops are "top-exit" loops. The "loop-and-a-half" pattern is for situations where the natural exit point is in the middle of the loop's body. This is achieved with an infinite loop (while(1)) and a break statement.
- Purpose: To read or acquire a resource first, then check for a termination condition, and finally process the resource.
Example: Reading from a file until the end
This is a standard, robust pattern for file processing.
C
#include <stdio.h>
int main() {
FILE *file = fopen("data.txt", "r");
if (file == NULL) {
perror("Error opening file");
return 1;
}
char line_buffer[256];
while (1) { // Start an infinite loop
// 1. Attempt to get the resource (read a line)
if (fgets(line_buffer, sizeof(line_buffer), file) == NULL) {
// 2. Check for the exit condition (end of file or error)
break;
}
// 3. Process the resource (the line is valid)
printf("Read line: %s", line_buffer);
}
fclose(file);
printf("\nFinished reading file.\n");
return 0;
}
2. Conditions with Side Effects
The condition expression in a while loop can itself perform an action, such as an assignment or a function call. The result of that action is then used as the condition.
- Purpose: To create highly compact and idiomatic C code, especially for input processing.
Example: The while((c = getchar()) != EOF) idiom
This single line reads a character, assigns it to a variable, and checks for the end-of-file marker.
C
#include <stdio.h>
// A simple program to count characters in its input
int main() {
long count = 0;
int c; // Use 'int' to hold the character and the special EOF value
// 1. getchar() is called.
// 2. Its return value is assigned to 'c'.
// 3. The value of the assignment (the character itself) is compared to EOF.
while ((c = getchar()) != EOF) {
count++;
}
printf("\nTotal characters: %ld\n", count);
return 0;
}
3. Pointer Traversal
while loops are the natural choice for iterating through data structures that are terminated by a NULL pointer or a null character (\0).
Example 1: Traversing a String with a Pointer
C
#include <stdio.h>
void print_string(const char *p) {
// The loop continues as long as the character the pointer 'p'
// points to is not the null terminator.
while (*p != '\0') {
putchar(*p);
p++; // Move the pointer to the next character
}
putchar('\n');
}
int main() {
print_string("Hello, Pointer!");
return 0;
}
Example 2: Traversing a Linked List
This is a fundamental pattern in data structures. The loop continues as long as the current node pointer is not NULL.
C
#include <stdio.h>
typedef struct Node {
int data;
struct Node* next;
} Node;
void print_list(Node *head) {
Node *current = head;
while (current != NULL) {
printf("%d -> ", current->data);
current = current->next; // Move to the next node
}
printf("NULL\n");
}
4. The continue Pitfall: A Cautionary Note
A critical detail for programmers is how continue behaves in a while loop. It jumps directly to the condition test at the top, skipping any code that comes after it in the loop body. This can easily lead to an infinite loop if you're not careful.
C
// DANGEROUS: Infinite loop
int i = 0;
while (i < 10) {
if (i == 5) {
continue; // Jumps to 'while(i < 10)'. 'i' is still 5. Loop is infinite.
}
i++; // This is skipped when i is 5
}
The Rule: In a while loop, always ensure the loop control variable is updated before any continue statement that could be triggered.