Nested Loops
Loops inside loops — patterns, tables, and 2D traversal
After this lesson, you will be able to:
- Explain how a nested loop executes: the inner loop completes all iterations for each single iteration of the outer
- Trace nested loop execution using a table
- Print rectangular and triangular patterns using nested
forloops - Use
System.out.printvsSystem.out.printlnto control row-based output - Identify and fix common nested loop mistakes
The Clock on the Wall
Think about a clock. The minute hand goes around 60 times for every single revolution of the hour hand. That is a nested loop. The hour hand is the outer loop (12 iterations per cycle), and the minute hand is the inner loop (60 iterations per cycle). For each hour, the minute hand completes a full sweep before the hour hand advances. In total, the minute hand ticks 12 x 60 = 720 times per full cycle.
Nested loops work exactly the same way. When you place one loop inside another, the inner loop runs to completion for every single iteration of the outer loop. This is the mechanism behind printing patterns, building tables, and processing two-dimensional data.
A Loop Inside a Loop
Here is the basic structure:
for (int outer = 0; outer < n; outer++) {
// runs n times
for (int inner = 0; inner < m; inner++) {
// runs n * m times total
}
// also runs n times (after the inner loop finishes)
}
The execution order:
- Outer loop starts:
outer = 0. - Inner loop runs completely:
inner = 0, 1, 2, ..., m-1. - Outer loop advances:
outer = 1. - Inner loop runs completely again from scratch:
inner = 0, 1, 2, ..., m-1. - This repeats until the outer loop finishes.
Key Insight: The inner loop completely resets for each iteration of the outer loop. It does not remember where it left off. Every time the outer loop advances, the inner loop starts over from its initialization.
The mental model that makes this click: outer loop = rows, inner loop = columns. For each row, process every column.
From Python to Java
From CSCD 110: You may have used nested loops in Python to print patterns. Java’s nested loop structure is identical in logic — just more braces and explicit loop syntax:
Python Java for i in range(3):for (int i = 0; i < 3; i++) {for j in range(4):for (int j = 0; j < 4; j++) {print("*", end="")System.out.print("*");}print()System.out.println();}Both print a 3-row, 4-column rectangle of stars. Python’s
end=""to suppress the newline becomes Java’sSystem.out.print(noln). Python’s bareprint()for a newline becomesSystem.out.println().
Tracing Nested Loops
Tracing is even more critical for nested loops than for single loops. You must track both loop variables simultaneously. Here is a small example:
for (int i = 1; i <= 2; i++) {
for (int j = 1; j <= 3; j++) {
System.out.print(i + "," + j + " ");
}
System.out.println();
}
Trace it step by step:
i |
j |
Output | Notes |
|---|---|---|---|
| 1 | 1 | 1,1 |
Inner loop starts |
| 1 | 2 | 1,2 |
|
| 1 | 3 | 1,3 |
Inner loop ends |
| 1 | — | (newline) | println() after inner loop |
| 2 | 1 | 2,1 |
Inner loop restarts from 1 |
| 2 | 2 | 2,2 |
|
| 2 | 3 | 2,3 |
Inner loop ends |
| 2 | — | (newline) | println() after inner loop |
Output:
1,1 1,2 1,3
2,1 2,2 2,3
When i = 1, j cycles through 1, 2, 3 and then resets. When i advances to 2, j starts over at 1 again. The inner loop runs 3 iterations for each of the 2 outer iterations, giving 2 x 3 = 6 total prints.
The Trick: Always trace nested loops with small values first. Use n = 2 or n = 3. Write out every single step in a table. Once the pattern clicks with small values, it scales to any size.
System.out.print execute in the code above?Printing Rectangular Patterns
The simplest nested loop application: print a rectangle of characters. The outer loop controls rows, and the inner loop controls columns.
void main() {
int rows = 4;
int cols = 5;
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
System.out.print("*");
}
System.out.println(); // newline after each row
}
}
Output:
*****
*****
*****
*****
The outer loop runs 4 times (one per row). For each row, the inner loop prints 5 stars using System.out.print (no newline). After the inner loop finishes one row, System.out.println() moves the cursor to the next line.
print vs println — The Key to Row-Based Output
This is worth emphasizing because it trips people up:
| Method | What it does | When to use it |
|---|---|---|
System.out.print("*") |
Prints without a newline | Inside the inner loop (building a row) |
System.out.println() |
Prints a newline only | After the inner loop (ending a row) |
If you use println inside the inner loop, every star lands on its own line. If you forget println after the inner loop, all rows merge into one long line.
Common Pitfall: Forgetting the
System.out.println()after the inner loop. Without it, all 20 stars print on a single line:********************. The newline must be inside the outer loop but after the inner loop.
The Multiplication Table
Nested loops are the natural tool for building tables. Each row-column combination produces one cell value. Here is a complete multiplication table:
void main() {
int size = 5;
// Print header row
System.out.print(" x |");
for (int col = 1; col <= size; col++) {
System.out.printf("%4d", col);
}
System.out.println();
// Print separator
System.out.print("----+");
for (int col = 1; col <= size; col++) {
System.out.print("----");
}
System.out.println();
// Print table body (nested loop)
for (int row = 1; row <= size; row++) {
System.out.printf("%3d |", row);
for (int col = 1; col <= size; col++) {
System.out.printf("%4d", row * col);
}
System.out.println();
}
}
Output:
x | 1 2 3 4 5
----+--------------------
1 | 1 2 3 4 5
2 | 2 4 6 8 10
3 | 3 6 9 12 15
4 | 4 8 12 16 20
5 | 5 10 15 20 25
Notice the use of System.out.printf("%4d", value) to format each number in a 4-character-wide column. This keeps the table aligned even when numbers have different digit counts. The nested loop in the table body runs 5 x 5 = 25 times — once for each cell.
row * col produce when row = 3 and col = 4?Triangle Patterns: Varying the Inner Loop Bound
A rectangle has a constant number of columns per row. A triangle changes the number of columns based on which row you are on. The key technique: make the inner loop’s condition depend on the outer loop variable.
Right Triangle
int n = 5;
for (int row = 1; row <= n; row++) {
for (int col = 0; col < row; col++) { // col < row, not col < n
System.out.print("*");
}
System.out.println();
}
Output:
*
**
***
****
*****
Trace the inner loop’s behavior:
row |
Inner loop runs… | Stars printed |
|---|---|---|
| 1 | col: 0 |
1 star |
| 2 | col: 0, 1 |
2 stars |
| 3 | col: 0, 1, 2 |
3 stars |
| 4 | col: 0, 1, 2, 3 |
4 stars |
| 5 | col: 0, 1, 2, 3, 4 |
5 stars |
Total stars: 1 + 2 + 3 + 4 + 5 = 15.
Key Insight: When the inner loop’s bound depends on the outer loop variable (
col < row), each row gets a different number of iterations. This is how you create triangular patterns instead of rectangular ones.
Inverted Triangle
Flip the triangle by reversing the relationship:
int n = 5;
for (int row = 1; row <= n; row++) {
for (int col = 0; col < n - row + 1; col++) {
System.out.print("*");
}
System.out.println();
}
Output:
*****
****
***
**
*
When row = 1, the inner loop runs 5 - 1 + 1 = 5 times. When row = 5, it runs 5 - 5 + 1 = 1 time. The formula n - row + 1 counts down as row counts up.
Number Triangle
Instead of printing the same character, use the column variable as the output:
int n = 5;
for (int row = 1; row <= n; row++) {
for (int col = 1; col <= row; col++) {
System.out.print(col + " ");
}
System.out.println();
}
Output:
1
1 2
1 2 3
1 2 3 4
1 2 3 4 5
The inner loop variable col does double duty: it controls how many numbers to print and provides the value to print.
Total Iterations: Counting the Work
Understanding how many times the inner body runs helps you reason about your program’s behavior:
| Pattern | Total iterations | Example |
|---|---|---|
| Rectangle (n x m) | n x m | 4 rows x 5 cols = 20 |
| Square (n x n) | n^2 | n = 10: 100 |
| Right triangle | n(n+1)/2 | n = 5: 15 |
When both loops run n times, the total is n^2. Doubling n quadruples the work. This is the origin of O(n^2) time complexity that you will study in CSCD 300 (Data Structures), where sorting algorithms like bubble sort and selection sort use nested loops.
Common Mistakes
1. Reusing the Same Loop Variable
for (int i = 0; i < 5; i++) {
for (int i = 0; i < 3; i++) { // ERROR: i already defined
System.out.print("*");
}
}
Java will not compile this. Each loop needs its own variable name. Use i and j, or better yet, row and col.
2. Using the Wrong Variable
for (int row = 1; row <= n; row++) {
for (int col = 0; col < row; col++) {
System.out.print(row); // Bug: prints the row number, not the column
}
System.out.println();
}
If you wanted to print 1 2 3 4 on row 4, you need col (or col + 1), not row. Mixing up which variable controls what is one of the most frequent nested loop bugs.
3. Mismatched Bounds
// Intended: triangle where row i has i stars
for (int row = 1; row <= n; row++) {
for (int col = 0; col < n; col++) { // Bug: col < n instead of col < row
System.out.print("*");
}
System.out.println();
}
This prints a rectangle, not a triangle. The inner loop’s bound is n (constant) when it should be row (varying). Always ask: should the inner loop run the same number of times every row, or a different number?
4. Misplaced println
for (int row = 0; row < 3; row++) {
for (int col = 0; col < 4; col++) {
System.out.print("*");
System.out.println(); // Bug: newline after EVERY star
}
}
This prints each star on its own line instead of 4 stars per row. The println() belongs after the inner loop, not inside it.
for (int row = 1; row <= 3; row++) {
for (int col = 1; col <= row; col++) {
System.out.print(row);
}
System.out.println();
}
row (not col) inside the inner loop. Row 1 prints "1" once. Row 2 prints "2" twice: "22". Row 3 prints "3" three times: "333". If you wanted the number triangle from option A, you would print col instead of row.
Variable Naming Conventions
Clear variable names prevent confusion when loops are nested:
| Convention | Best for |
|---|---|
i, j |
Generic nested loops, math-heavy code |
row, col |
Pattern printing, tables, grids |
outer, inner |
When the relationship between loops matters more than the data |
For this course, prefer row and col when printing patterns. They make the code self-documenting: you never have to wonder which variable controls rows and which controls columns.
Big Picture
Big Picture: Nested loops are everywhere in computing. In CSCD 211 (Programming Principles II), you will use nested loops to traverse 2D arrays. In CSCD 300 (Data Structures), sorting algorithms like bubble sort and selection sort use nested loops, and their O(n^2) runtime comes directly from the n x n iteration count. In CSCD 305 (Intro to Database Systems), a nested-loop join processes every combination of rows from two tables. The two-loop pattern you learn here scales to every domain.
Summary
Nested loops give you the power of two-dimensional repetition. The outer loop controls rows; the inner loop controls columns. The inner loop resets and runs to completion for every single iteration of the outer.
Rectangle: the inner loop bound is constant (same iterations every row).
Triangle: the inner loop bound depends on the outer variable (col < row), giving each row a different width.
Total work: outer iterations times inner iterations. For an n x n grid, that is n^2. For a triangle of height n, it is n(n+1)/2.
Output control: use System.out.print to build a row piece by piece, then System.out.println() after the inner loop to end the row.
Next up: Methods — how to package loops and logic into reusable, named blocks of code. Once you can write a pattern-printing nested loop, wrapping it in a method is the next natural step.