Row-major rectangular 2D arrays
Student can declare and construct a rectangular int[][] (or double[][], String[][], etc.) with new T[rows][cols] or with a literal initializer, access elements as grid[row][col], and report the number of rows (grid.length) and columns (grid[0].length).
A 2D array in Java is an array of arrays. The most common form is rectangular (every row has the same length) and accessed in row-major order (the first index selects the row; the second selects the column within that row).
int[][] grid = new int[3][4]; // 3 rows, 4 columns; all 12 slots initialised to 0
grid[0][0] = 1; // row 0, column 0
grid[2][3] = 99; // row 2, column 3 (the bottom-right corner)
System.out.println(grid.length); // 3 (number of rows)
System.out.println(grid[0].length); // 4 (length of row 0)
Three facts the language enforces:
1. grid.length is the number of rows. grid is an array of length 3; each element of that array is itself an int[] of length 4. 2. grid[i].length is the length of row i. For a rectangular array, this is the same for every i. The "number of columns" is grid[0].length by convention (any row works, but row 0 is the canonical one). 3. There is no grid.length[1] or grid.cols. Java does not store the dimensions as a separate property. The "number of columns" must be read from a row.
Constructing a rectangular grid
new int[rows][cols] allocates everything at once: the outer array of length rows, plus rows inner arrays each of length cols. All rows * cols int slots are initialized to 0. The same form works for any element type: String[][] board = new String[8][8]; allocates a chessboard's worth of null references.
Literal-initializer form:
final int[][] grid = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
Each inner {...} is a row. The number of inner literals is the row count; the length of each inner literal is the column count for that row. If the inner lengths differ, the result is a jagged array.
Row-major access
The convention grid[row][col] (row first, column second) is universal in Java code and matches mathematical notation (A[i][j] for matrices). Visualizing:
col 0 col 1 col 2 col 3
row 0: [ 1 , 2 , 3 , 4 ]
row 1: [ 5 , 6 , 7 , 8 ]
row 2: [ 9 , 10 , 11 , 12 ]
grid[1][2] is the value 7 (row 1, column 2). The memory layout is "first row stored consecutively, then second row, then third," but this layout detail rarely matters at the CSCD 210 level. The pedagogical commitment is "row first" in the indexing syntax.
In other languages
- C / C++:
int grid[3][4];allocates as a single block of 12 ints, row-major. Same indexing syntax. - Python:
numpy.array(...)andnumpy.zeros((3, 4))are the analog; tuples for shape, indexedgrid[i, j](single bracket pair with comma) orgrid[i][j]. - MATLAB: column-major by default;
A(i, j)is rowi, columnj. Beware when porting code. - JavaScript: no fixed-shape 2D arrays;
[[1,2],[3,4]]is an array of arrays, identical to Java's structure.
Nested for loops for 2D traversal
Student can produce a nested-for traversal of a 2D array that visits every slot exactly once in row-major order, using grid.length for the outer bound and grid[r].length for the inner bound, and predict what the loop body's grid[r][c] accesses at each iteration.
The canonical 2D-array traversal uses two nested for loops: the outer over rows, the inner over columns. Each iteration of the inner loop visits one slot; the inner loop completes one full row before the outer advances to the next.
for (int r = 0; r < grid.length; r++) { // outer: rows
for (int c = 0; c < grid[r].length; c++) { // inner: columns
System.out.print(grid[r][c] + " ");
}
System.out.println(); // newline after each row
}
Three commitments encoded in this shape:
1. Outer is row, inner is column. The convention r/c (or row/col) names the variables to match. The loop variable names i and j are also acceptable, but in CSCD 210 style, r/c removes ambiguity in a code review. 2. The inner loop's bound is grid[r].length, not grid[0].length. For a rectangular array, both are equal. For a jagged array, whose rows may have different lengths, they differ: grid[r].length correctly handles every row. The form generalizes; the form using [0].length does not. 3. A println after the inner loop produces a row-by-row visual layout. Without it, all values print on one line. The placement of the println (inside the outer loop, outside the inner) is what produces the grid-like output.
The 2 × outer.length × inner.length iteration count
For a rectangular rows × cols grid, the loop body runs rows cols times. For a 100×100 grid that is 10 000 iterations; for 1000×1000 it is a million. Quadratic growth (O(rows cols)) is the cost of touching every slot.
The enhanced-for form is also possible, when the index is not needed:
for (int[] row : grid) { // outer: each row is itself an int[]
for (int v : row) { // inner: each slot of that row
System.out.print(v + " ");
}
System.out.println();
}
This shape is more concise but loses the row and column indices. Use it for sums, counts, or any predicate that does not depend on position. For "print row labels" or "set the diagonal," use the indexed form.
Walking a column instead of a row
To visit column c of every row, swap the loop nesting:
for (int c = 0; c < grid[0].length; c++) { // outer: column index
for (int r = 0; r < grid.length; r++) { // inner: row index for that column
System.out.print(grid[r][c] + " ");
}
System.out.println();
}
The variable names still refer to row and column (the access is grid[r][c]), but the outer loop now iterates c while the inner loops over r. Column-major traversal is less common in CSCD 210; row-major is the default.
In other languages
- C / C++: identical nested-loop shape, same row-major convention.
- Python:
for row in grid: for v in row: print(v, end=' '); print(). Same shape; iteration is over the outer list, then over each inner list. - NumPy:
for v in grid.flat:flattens to a 1D iteration;grid.shapereports(rows, cols).
Jagged arrays
Student can declare a jagged 2D array using new T[rows][] + per-row allocation or the matching literal-initializer form, identify the consequence of accessing an unassigned row (NullPointerException), and traverse a jagged structure correctly with grid[r].length in the inner loop.
Status: STUB-INTENTIONAL: deferred from CSCD 210 to CSCD 211.
The current CSCD 210 curriculum stops at rectangular 2D arrays, with jagged-array semantics deferred to CSCD 211's collections coverage.
Jagged arrays are reference material for CSCD 210. The objective, pitfalls, and sources below sketch what a full CSCD 211 treatment would look like, and Lab 11-style file labs can point here if jagged data appears.
Concept overview (CSCD 211 territory)
A jagged array is a 2D array where rows have different lengths. Java's "array of arrays" memory model makes jagged arrays the natural case; rectangular is the constrained subcase.
final int[][] jagged = new int[3][]; // outer array allocated; rows are null
jagged[0] = new int[]{1, 2}; // row 0: length 2
jagged[1] = new int[]{3, 4, 5, 6}; // row 1: length 4
jagged[2] = new int[]{7}; // row 2: length 1
// Literal initialiser form:
final int[][] tri = {
{1},
{1, 1},
{1, 2, 1},
{1, 3, 3, 1}
}; // Pascal's triangle, jagged
The grid[r].length form used by the nested-loop traversal is exactly what makes jagged traversal work without modification: each row's bound is read from the row itself.
Why CSCD 210 defers it
The pedagogical decision is deliberate: rectangular 2D arrays are conceptually contained (one outer length, one inner length), while jagged arrays introduce a second axis of variability that students rarely use in the labs but easily confuse with the rectangular case. The deferral keeps lecture-time tight; CSCD 211's collections unit picks up the jagged case alongside List<List<E>> and other inhomogeneous structures.
In other languages
- C: jagged is the default:
int *array[10]is an array of 10 row pointers, each independently allocated. - Python: jagged is the default: a list of lists has no required-equal-length constraint.
- NumPy: jagged arrays are not supported in the core type; they require
object-dtype arrays or the separateragged tensorextensions. - Java rectangular convention: the
new T[rows][cols]form is the special "all rows equal length" case; the generalnew T[rows][]form supports jagged.