A structured lesson workspace with readable content, hands-on examples, and a clean path to completion.
The for loop is a while loop with the bookkeeping crammed into the header. Initialization, condition, increment. Three expressions separated by semicolons. The compiler does not care what you put in those slots. You can declare variables, call functions, or leave them empty. That flexibility is powerful and also how people write unreadable one-liners that make code reviewers weep.
#include <stdio.h>int main(void) {for (int i = 0; i < 10; i++) {printf("i = %d\n", i);}printf("Loop finished. i is out of scope here.\n");return 0;}
Declaring i inside the for header requires C99 or later. In C89, you must declare i before the loop. The variable declared in the init clause is scoped to the loop body. Once the loop ends, i ceases to exist. If you need i after the loop, declare it outside.
Every programmer writes this bug. You want to process indices 0 through 9 of a 10-element array. You write i <= 10 instead of i < 10. You access element 10, which does not exist. You read or write one past the end of the buffer. In the best case, you get garbage. In the worst case, you overwrite the return address on the stack and create an exploitable vulnerability.
#include <stdio.h>int main(void) {int arr[5] = {10, 20, 30, 40, 50};printf("Correct bounds:\n");for (int i = 0; i < 5; i++) {printf(" arr[%d] = %d\n", i, arr[i]);}printf("\nOff-by-one (i <= 5):\n");for (int i = 0; i <= 5; i++) {printf(" arr[%d] = %d\n", i, arr[i]);}return 0;}
Compile with -fsanitize=address during development. AddressSanitizer catches buffer overflows, use-after-free, and stack corruption at runtime. It adds overhead so you do not ship with it enabled, but it turns silent memory corruption into an immediate, descriptive crash. Use it every time you write array or pointer code.
Any of the three expressions can be empty. for (;;) is an infinite loop, equivalent to while (1). You can put multiple expressions in the init and increment slots using the comma operator. You can call functions in the condition. Just because you can does not mean you should. Readability is a feature.
#include <stdio.h>int main(void) {int sum = 0;int arr[] = {1, 2, 3, 4, 5};int n = 5;for (int i = 0, j = n - 1; i < j; i++, j--) {printf("Swapping arr[%d]=%d with arr[%d]=%d\n", i, arr[i], j, arr[j]);int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}printf("Reversed: ");for (int i = 0; i < n; i++) {printf("%d ", arr[i]);}printf("\n");return 0;}
for loops dominate array processing, string traversal, and any counted iteration in C. The off-by-one error is so universal that it has its own Wikipedia article. You will write one. The goal is to catch it in five seconds with ASan rather than five hours with printf debugging. Next: break and continue, which let you escape or skip iterations mid-loop.
Finish the lesson once you have worked through the material. This awards ★ 20 XP.