java-foundations 18 min read

Nested Loops and Rectangular Output

Loops inside loops — the multiplier that prints grids and builds triangles

Heads up for class day. The first 15 minutes of Thursday’s class period are the graded while-loop-tracing quiz (Quiz 4). This lesson is the material for the rest of the day — nested loops — which you read before class so class time can be spent on live examples.

A nested loop is a loop inside another loop’s body. Nothing special happens: the inner loop is just a statement, and the outer loop’s body contains a statement. But the combination multiplies. If the outer loop runs m times and the inner loop runs n times per outer iteration, the inner body executes m × n times in total.

This is how a program prints a grid of characters, a multiplication table, a triangle of stars, or an ASCII-art image.

In a nutshell

Each time the outer loop enters the inner loop, the inner counter starts fresh. That’s what for (int j = 0; ...) means in the inner header — j is declared anew every pass. Tracing a nested loop on paper is still the same idea as a single loop, just with two counters in the table.

Use different counter names. Convention: i for the outer, j for the inner. Using the same name in both causes a compile error (“variable i is already defined in the enclosing scope”) — the compiler catches it, but the error message is less obvious than most.

Rectangular output = print inside, println at the row boundary. The inner loop prints characters on one row; the println at the bottom of the outer body ends the row and moves to the next. Swap those two placements and the output shape collapses.

Quick reference

Execution count

For two nested for loops where the inner bound does not depend on the outer counter:

inner body runs m × n times total

For a triangular pattern where the inner bound depends on the outer counter (e.g. j <= i):

inner body runs 1 + 2 + ... + m = m(m + 1) / 2 times total

Rectangular skeleton

for (int i = 0; i < rows; i++) {
    for (int j = 0; j < cols; j++) {
        System.out.print("* ");        // character on this row
    }
    System.out.println();              // end of row
}

Bug-signature cheat sheet

Symptom Cause
One * per line instead of a row println inside the inner loop
All stars on one line println outside the outer loop
Extra column per row j <= cols where j < cols was meant
Compile error “i already defined” Both loops use i

Deep dive

1. A first worked example: a 2-by-3 trace

for (int i = 1; i <= 2; i++) {
    for (int j = 1; j <= 3; j++) {
        System.out.print(i + "-" + j + "  ");
    }
    System.out.println();
}

How many times does print run? The outer runs 2 times, the inner 3 times per outer iteration — so 2 × 3 = 6 prints total, plus 2 printlns at the row boundaries.

Outer pass i j Inner body prints
1 1 1 1-1
1 1 2 1-2
1 1 3 1-3 then println() ends row 1
2 2 1 2-1
2 2 2 2-2
2 2 3 2-3 then println() ends row 2

Output:

1-1  1-2  1-3
2-1  2-2  2-3

Notice j goes from 1 to 3 twice — once for i = 1 and once for i = 2. Each outer iteration restarts the inner counter. Total inner body executions: 6.

2. Rectangular print (the most common CS1 nested-loop task)

Plan. Print a 3-row by 4-column grid of *.

  • Decide rows = 3, cols = 4.
  • Outer loop: i from 0 to rows - 1 (runs 3 times).
  • Inner loop: j from 0 to cols - 1 (runs 4 times per outer pass).
  • Inside inner body: System.out.print("* ").
  • After inner loop, still inside outer body: System.out.println() to end the row.
int rows = 3;
int cols = 4;
for (int i = 0; i < rows; i++) {
    for (int j = 0; j < cols; j++) {
        System.out.print("* ");
    }
    System.out.println();
}

Output:

* * * *
* * * *
* * * *

Three rows, four stars per row. The print fires 12 times (3 × 4); the println fires 3 times (once per outer pass).

Debug the placement. If the output shows one * per line, the println is inside the inner loop — every * got its own line break. If all 12 stars appear on one line, the println is outside the outer loop — you only get a newline at the very end. Move the println to just after the inner loop’s closing brace, inside the outer loop’s body.

3. Triangular print — when the inner bound depends on the outer counter

The rectangular shape works because both loops run fixed counts. Now change one thing: let the inner loop’s upper bound depend on i. The inner loop does more work each time the outer counter advances, and the output forms a triangle.

int height = 3;
for (int i = 1; i <= height; i++) {
    for (int j = 1; j <= i; j++) {       // inner bound is i, not a fixed width
        System.out.print("* ");
    }
    System.out.println();
}

Row-by-row trace for height = 3:

Outer pass i Inner loop runs Row printed
1 1 1 time *
2 2 2 times * *
3 3 3 times * * *

Output:

*
* *
* * *

The inner body runs 1 + 2 + 3 = 6 times total — not 3 × 3 = 9. The multiplication rule does not apply when the inner bound depends on the outer counter. Count row by row.

Key insight. When the inner bound depends on the outer counter (j <= i), the total body count is 1 + 2 + ... + m = m(m+1)/2. For height 3 that’s 6; for height 4 that’s 10; for height 10 that’s 55. Useful when you are writing a triangle; necessary when a test asks how many * the loop prints.

4. A real application: the multiplication table

Rectangular nested loops print grids where each cell is a value, not a fixed character. The canonical example is the multiplication table. "\t" is the tab character — it keeps columns aligned without you having to manage widths.

for (int i = 1; i <= 5; i++) {
    for (int j = 1; j <= 5; j++) {
        System.out.print(i * j + "\t");
    }
    System.out.println();
}

Output:

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

The pattern is identical to the rectangular * grid: print inside, println at the row boundary. The only change is what you print.

Check Your Understanding
How many times does the body of the inner loop execute?
for (int i = 1; i <= 4; i++) {
    for (int j = 1; j <= i; j++) {
        System.out.print("*");
    }
    System.out.println();
}
A4 times
B8 times
C10 times
D16 times
Answer: C. The inner bound depends on i: it runs 1, 2, 3, 4 times on passes 1, 2, 3, 4 respectively. Total: 1 + 2 + 3 + 4 = 10. This is the triangular case — the rectangular multiplication rule m × n does not apply.

5. Reusing the counter name — a compile error

Using the same counter name in both loops:

for (int i = 0; i < 3; i++) {
    for (int i = 0; i < 4; i++) {     // ERROR: 'i' already declared
        System.out.print("* ");
    }
    System.out.println();
}

The compiler rejects this. The inner int i tries to re-declare a variable already in scope from the outer header. Fix: rename the inner counter. Convention is j for the inner loop, then k, then m or col/row if the meaning is clearer.

How to recognize it: a compile error that says the variable is already defined in the enclosing scope. Rename the inner counter and the error goes away.


Before you leave

A nested loop is one loop inside another’s body; the inner loop restarts every time the outer advances. Rectangular output uses print inside and println at the row boundary. When the inner bound depends on the outer counter, you get a triangle and the execution count is m(m+1)/2 instead of m × n. Use different counter names or the compiler rejects the code.

Tomorrow: do-while (the loop that guarantees one pass), the fencepost problem (why separators between items are trickier than they look), and a debugging playbook for every loop symptom you will see this quarter.

Want to practice? The Week 4 quiz-prep set on the practice platform has nested-loop grid and triangle problems mapped to this lesson.