Hollow Square Border Number Pattern in C++

Beginner
⏱️ 10 min read
📚 Updated: Aug 2026
🎯 3 Code Examples
🚀 Live Preview
Nested Loops + Formatting

What You’ll Learn

Program 59 prints a hollow square border: a 5×5 grid where only the boundary shows consecutive numbers 1–16 and the inside stays blank — a shift from Program 58’s diagonal diamond to rectangular border logic. This tutorial covers border detection, fixed-width formatting, separate side counters, a live preview, worked C++ examples, edge cases, and complexity.

Shape Rule

Hollow border

Only cells on the border print numbers — top, right, bottom, and left sides use different counter sequences.

Nested Loops

i, j = 1..5

for (i = 1; i <= 5; i++) for (j = 1; j <= 5; j++) — visit every cell in the 5×5 grid.

Border Checks

if / else if

i == 1, j == 5, i == 5, j == 1 — detect which side of the border the cell belongs to.

Side Counters

k, l, m

k = 6 (right), l = 13 (bottom), m = 16 (left) — track values for non-top sides.

Fixed Width

setw(3)

cout << setw(3) << value and " " for inner cells — columns stay aligned.

O(n²)

Complexity

Every cell in the n×n grid is visited once — total work grows as O(n²).

Introduction

A hollow square border number pattern prints consecutive numbers only on the boundary of a square grid, leaving the interior blank. For a 5×5 square, the top row shows 1..5, the right column continues 6..9, the bottom row shows 13..9, and the left column finishes with 16..13.

In C++ use nested loops over rows and columns, then branch with if / else if to detect border sides. Use cout << setw(3) << value for numbers and three spaces for inner cells.

Why it matters?

It bridges Program 58’s diagonal symmetry to rectangular grids — combining border detection, multiple counters, and fixed-width formatting.

Key Highlights

Top row

i == 1 prints j (1..5).

Right column

j == 5 prints k++ (6..9).

vs Program 58

Program 58 uses diagonal mirror loops; Program 59 uses rectangular border checks.

Series Foundation

Follow Program 58; continue to Program 60 next.

In short: nested i, j loops, border if checks, counters k, l, m, fixed width 3, then cout << "\n" per row.

📝 Problem & Approach

Print a 5×5 hollow square where the border shows numbers 1–16 clockwise and inner cells are blank spaces of width 3.

C++
// 5×5 hollow border (numbers 1..16)
//1  2  3  4  5
//16          6
//15          7
//14          8
//13 12 11 10 9

Inputs & Outputs

ItemTypeDescription
Grid sizeint5×5 in the fixed demo — 25 cells total, 16 on the border.
i (outer)intRow index — runs 1 to 5.
j (inner)intColumn index — runs 1 to 5.
kintRight column counter — starts at 6, increments.
lintBottom row counter — starts at 13, decrements.
mintLeft column counter — starts at 16, decrements.

Minimal workflow

Pseudocode
init k, l, m for right, bottom, left sides
for i from 1 to n:
    for j from 1 to n:
        if top row: print j
        else if right column: print k++
        else if bottom row: print l--
        else if left column: print m--
        else: print three spaces
    print newline

Approach comparison

ApproachIdeaBest for
if / else if chainDetect top, right, bottom, left border per cellLearning and interviews
Separate countersk, l, m for non-top sidesClockwise numbering
Fixed-width formatsetw(3) for numbers, " " insideAligned columns
Configurable sizeRead n from inputFlexible grid size
Compact tracen = 3 on paper firstQuick dry-runs before 5×5 demo

⚡ Quick Reference

GoalPattern
Outer loopfor (i = 1; i <= 5; i++)
Inner loopfor (j = 1; j <= 5; j++)
Top rowif (i == 1) cout << setw(3) << j;
Right columnelse if (j == 5) cout << setw(3) << k++;
Bottom rowelse if (i == 5) cout << setw(3) << l--;
Left columnelse if (j == 1) cout << setw(3) << m--;
Inner cellelse cout << " ";
Program 58 contrastProgram 58 uses diagonal mirror; Program 59 uses rectangular border checks

📋 Fixed 5×5 vs Configurable vs Compact Trace

Same hollow border idea — three ways to set grid size and trace the logic.

Fixed 5×5
n = 5

Numbers 1–16 on border

User input
cin >> n

Read square size from console

Compact trace
n = 3

9-cell grid dry-run

Top side
i == 1

Print column index j

Inner
"   "

Three spaces, width 3

Context

When This Pattern Shows Up

Reach for this pattern when teaching 2D grids, border detection, fixed-width formatting, and multiple counters.

  1. Post Program 58 exercise

    Natural follow-up after Program 58’s diamond — introduces rectangular grids and border-only printing.

  2. Grid formatting drills

    Fixed-width setw(3) keeps columns aligned — essential for multi-digit borders.

  3. Multiple counters

    Separate k, l, m for right, bottom, left — concrete state-tracking practice.

  4. Gateway to Program 60

    Compare this hollow border with the next pattern in the series.

  5. Not a UI layout tool

    This is a console teaching pattern — not how you build modern app screens.

Key benefit: one small program that locks in border checks, formatting, and O(n²) grid thinking.

🔮 Live Preview

Choose row count between 3 and 9 and draw the centered hollow square border number pattern in the browser.

Try 4, 5, or 7. Max up to 7 in this preview.

Live result
Press "Draw pattern".

Examples Gallery

Three complete C programs — fixed 5×5 border, configurable size, and a compact 3×3 trace demo. Click View Output to reveal sample console results.

📚 Getting Started

Print a 5×5 hollow border with numbers 1–16 clockwise — top, right, bottom, and left sides with separate counters.

Example 1 — Fixed 5×5 Border

Hard-coded grid — use if / else if to detect border sides and setw(3) formatting for alignment.

C++
#include <iostream>
#include <iomanip>
using namespace std;

int main() {
    int i, j;
    int k = 6, l = 13, m = 16;

    for (i = 1; i <= 5; i++) {
        for (j = 1; j <= 5; j++) {
            if (i == 1)
                cout << setw(3) << j;
            else if (j == 5)
                cout << setw(3) << k++;
            else if (i == 5)
                cout << setw(3) << l--;
            else if (j == 1)
                cout << setw(3) << m--;
            else
                cout << "   ";
        }
        cout << "\n";
    }

    return 0;
}

How It Works

Row 1 prints j for every column. Rows 2–4 print m-- on the left, k++ on the right, and spaces inside. Row 5 prints l-- across the bottom.

📈 User Input

Read square size from the console with safe parsing.

Example 2 — Configurable Square Size

Read n with cin >> n (check cin.fail()) — print column index on border cells, spaces inside. Counter rules can be customized for larger grids.

C++
#include <iostream>
#include <iomanip>
using namespace std;

int main() {
    int n, i, j;

    cout << "Enter square size (n): ";
    cin >> n;
    if (cin.fail() || n < 2) {
        cout << "Please enter an integer >= 2.\n";
        return 1;
    }

    for (i = 1; i <= n; i++) {
        for (j = 1; j <= n; j++) {
            int isBorder = i == 1 || i == n || j == 1 || j == n;
            if (isBorder)
                cout << setw(3) << j;
            else
                cout << "   ";
        }
        cout << "\n";
    }

    return 0;
}

How It Works

Uses a simple isBorder flag instead of side-specific counters — good starting point before adding clockwise numbering for arbitrary n.

⚡ Compact Trace

Smaller 3×3 grid for quick tracing on paper or in interviews.

Example 3 — Compact 3×3 Border

Use n = 3 with scaled counter starts — trace all four sides before scaling to 5×5.

C++
#include <iostream>
#include <iomanip>
using namespace std;

int main() {
    int n = 3;
    int i, j;
    int k = n + 1, l = 3 * n - 2, m = 4 * (n - 1);

    for (i = 1; i <= n; i++) {
        for (j = 1; j <= n; j++) {
            if (i == 1)
                cout << setw(3) << j;
            else if (j == n)
                cout << setw(3) << k++;
            else if (i == n)
                cout << setw(3) << l--;
            else if (j == 1)
                cout << setw(3) << m--;
            else
                cout << "   ";
        }
        cout << "\n";
    }

    return 0;
}

How It Works

With only nine cells and one inner gap, you can trace every border branch on paper before running the full 5×5 demo.

🧠 How the Algorithm Fills the Grid

1

Init side counters

k = 6, l = 13, m = 16 — starting values for right, bottom, and left borders.

Setup
2

Loop over 5×5 grid

for (i = 1; i <= 5; i++) for (j = 1; j <= 5; j++) — visit every cell.

Grid
3

Detect border side

if (i==1) top, else if (j==5) right, else if (i==5) bottom, else if (j==1) left — else inner space.

Conditionals
4

Fixed-width output

cout << setw(3) << value for border digits, " " for inner cells — then cout << "\n".

Format
=

Hollow border square complete

25 cells visited — O(n²) time, O(1) extra memory.

🔎 Worked Walkthrough — Key Border Cells

Trace which branch runs for representative cells in the 5×5 grid.

(i, j)BranchPrintsNotes
(1, 3)i == 13Top row uses column index
(2, 5)j == 56First right-column value (k++)
(3, 3)else (inner)Three spaces — hollow interior
(4, 1)j == 115Left column (m--)
(5, 3)i == 511Bottom row (l--)

Check order matters: top row is tested first, then right column, then bottom, then left — corners belong to the first matching branch.

Use Cases

Where this tiny pattern (and its loop structure) shows up beyond the homework prompt.

1. Teaching 2D Grids

Nested i, j loops with per-cell decisions — foundation for matrix problems.

Example: trace cell (3,3) in the walkthrough — inner branch prints spaces.

2. Fixed-Width Formatting

setw(3) keeps columns aligned when border numbers have 1 or 2 digits.

Example: compare output with and without formatting — columns drift without width 3.

3. Multiple Counters

Separate k, l, m track different sides — state management in a small program.

Example: right column starts at 6 and increments through row 4.

4. Border vs Interior

Hollow patterns print only on the boundary — compare with filled square variants.

Example: replace inner spaces with * to fill the square.

5. Complexity Intuition

Every cell visited once — makes O(n²) concrete for n×n grids.

Example: 5×5 = 25 cell checks — see the walkthrough table.

6. Input Validation Labs

Pair the pattern with cin >> n return checks and minimum-size validation.

Example: reject n < 2 in Example 2.

Pro Tip: in grid patterns, consistent spacing matters as much as the numbers — use fixed-width formatting from the start.

Advantages

Why this pattern earns a permanent spot in beginner C courses.

  1. 1. Instant Visual Feedback

    The hollow border is instantly recognizable — numbers ring the square while the interior stays blank.

  2. 2. Real Math Connection

    Fixed-width setw(3) formatting teaches real console grid alignment — not abstract loop drill.

  3. 3. Easy to Extend

    Fill the interior with * for a solid square, or scale counter formulas for larger grids.

  4. 4. O(1) Extra Memory

    Streaming output needs no storage beyond loop counters.

Pro Tip: trace the 3×3 compact example on paper — only one inner cell to mark as spaces.

Usage Tips

Small habits that keep number-pattern code clean.

  1. 1. Left loop: j = rows..1

    Print the digit when i == j; otherwise print a single space.

  2. 2. Check cin.fail()

    Avoid using uninitialized n when the user types letters instead of a number.

  3. 3. Newline After Inner Loop

    Only call cout << "\n" after the inner loop finishes each row.

  4. 4. Right loop starts at k = 2

    Use for (k = 2; k <= rows; k++) so the center position is not duplicated.

  5. 5. Dry-Run rows = 5

    Trace five rows on paper before coding the full 10-row demo.

Pro Tip: if the output is a vertical list of single numbers, you almost certainly put cout << "\n" inside the inner loop.

Common Pitfalls

Mistakes that commonly break hollow square border number pattern patterns.

  1. 1. cout << "\n" Inside Inner Loop

    Each number lands on its own line — you get a column, not a square row.

    → Use cout << setw(3) << j or cout << " "; call cout << "\n" only after the inner loop.

  2. 2. Right Loop Starts at 1

    Starting at k = 1 can print a third digit at the center — row looks crowded.

    → Use for (k = 2; k <= rows; k++) — mirror from column 2 onward.

  3. 3. Wrong Condition Check

    Using j == rows instead of i == j places digits on the wrong diagonal.

    → Always compare the outer row index i with the inner loop variable j or k.

  4. 4. Forgetting Newline After Row

    All numbers print on one long line without row breaks.

    → Add cout << "\n" after both inner loops complete.

  5. 5. Unchecked cin

    Letters or empty input leave n uninitialized or wrong.

    → Check cin.fail() after cin >> n and re-prompt on failure.

Edge Cases

Check these inputs before calling the solution done.

rows = 1

Single row

Output is a single cell — for n = 1 every position is border; validate n >= 2 in user input.

rows = 0

Empty output

Outer loop never runs — print nothing or show a message.

Negative

rows < 0

Treat as invalid; re-prompt instead of silent empty output.

rows = 5

Compact trace

Center cell (3,3) is the only inner cell — good for tracing the else branch.

Bad input

Non-numeric input

Unchecked cin >> n fails silently — check the return value.

Large rows

Wide output

Row 9 scans 17 character positions (2×9-1) — total work grows as O(n²).

🎯 Practice Problems

Try these variations to lock in the pattern.

1. Compare with Program 58

  • Program 58 prints a diagonal mirror diamond
  • Program 59 prints a rectangular hollow border with k, l, m counters

2. Fill the interior

  • Replace inner " " with a digit or *
  • Compare hollow vs filled square output

3. Next in series

  • Continue with Program 60
  • Build on grid and border patterns

4. Scale to n = 7

  • Derive counter start values for a 7×7 border
  • Use width 4 if numbers exceed 99

Notes

  • Border checks. Top: i == 1. Right: j == n. Bottom: i == n. Left: j == 1. Else: three spaces.
  • cout stays on the line; cout << "\n" advances — call it only after the inner loop finishes each row.
  • Validate n >= 2 for interactive programs; n = 2 has no inner cells — all border.
  • An n×n grid visits n² cells — total work grows as O(n²) for square size n.

Quick Takeaway: nested i, j loops, border if chain, counters k, l, m, width 3, then cout << "\n".

⏱️ Time and Space Complexity

ProgramTimeExtra space
Nested loops (Examples 1–3)O(n²)O(1)
Digits on row i2i - 1No storage beyond loop counters
Wrap Up

🎉 Conclusion

The hollow square border number pattern is a natural follow-up to Program 58: rectangular grids with border detection and fixed-width formatting replace diagonal mirror loops. Master the fixed 5×5 version, then try user input and the compact 3×3 trace.

Practice the three examples above, then continue to Program 60 for the next pattern in the series.

Border shows numbers 1–16 clockwise on a 5×5 grid — inner cells stay blank with width-3 spacing.

💡 Best Practices

✅ Do

  • Left: for (j = rows; j >= 1; j--) with if (i == j)
  • Right: for (k = 2; k <= rows; k++) with if (i == k)
  • Print a single space for non-matching positions
  • Call cout << "\n" after the inner loop
  • Use cin >> n with return-value checks for user input

❌ Don’t

  • Start right loop at k = 1 — can triple-print at center
  • Use j == rows instead of i == j — wrong diagonal
  • Call cout << "\n" inside the inner loop
  • Ignore bad console input in user-facing demos
  • Skip the rows = 3 dry-run before coding rows = 5

Key Takeaways

Knowledge Unlocked

Five things to remember about this hollow border square

Print the hollow border square the beginner-friendly way.

5
Core concepts
02

Left

j = rows..1

Code
03

Right

k = 2..rows

Code
04

Check

i == j or i == k

Logic
O 05

Complexity

O(n²) time

Analysis

❓ Frequently Asked Questions

A cell is on the border if i == 1, i == n, j == 1, or j == n — inner cells print three spaces.
Fixed width of 3 keeps every column aligned even when border numbers have different digit counts (include <iomanip>).
A 5×5 grid where only the boundary shows numbers 1–16 clockwise; the inside stays blank.
Program 58 prints a diagonal mirror diamond. Program 59 prints a rectangular hollow border with separate counters per side.
k tracks the right column (6..9), l the bottom row descending (13..9), m the left column descending (16..13).
Read n from input and adjust counter start values — see Example 2 for a configurable border demo.
O(n²) for an n×n grid because every cell is visited once.
Yes. Replace the inner-cell branch that prints spaces with values for the interior.
Border numbers use width 3 — inner cells need three spaces to keep columns aligned.
A 2×2 grid has no inner cells — every position is on the border.

Did you Know? 🔊

This pattern is a hollow 5×5 border: top row 1..5, right side 6..9, bottom row 13..9, left side 16..13 — inner cells are blank spaces with fixed width 3.

Continue to Program 60

Move on to the next pattern in the C++ number-pattern series.

Program 60 tutorial →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

12 people found this page helpful