Room 13 of 14 · about 20 minutes

Two-dimensional arrays

One index reaches a slot. This room is what happens when a slot needs two.

Tasks checked0 of 4 XP earned on this path0

What this room checks you can do

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).

Notes

Row-major rectangular 2D arrays

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(...) and numpy.zeros((3, 4)) are the analog; tuples for shape, indexed grid[i, j] (single bracket pair with comma) or grid[i][j].
  • MATLAB: column-major by default; A(i, j) is row i, column j. 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

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.shape reports (rows, cols).

What this room assumes you already have

Not in this room

Tasks

Do each one, then check the box. Checking a box is you saying you did it. You can uncheck a box if you check it by accident.

  1. trace
    Show the answer

    2, 3, 0.

  2. trace
    Show the answer

    1 2 \n 3 4 \n 5 6 \n (six numbers across three lines).

  3. trace
    Show the answer

    5.

  4. trace
    Show the answer

    0 (unrelated slot, still at default).

Self check

Type what you think the answer is. Getting it wrong costs nothing and you can try as many times as you want.

Write a method that prints a 2D int[][] grid in tabular form.

Practice, untimed

Open this whenever you want, before the tasks or after them. Nothing in this section is recorded and nothing here is timed.

  1. Construct a 5×5 grid of zeros, then set the diagonal to 1.write
    Show the answer

    int[][] g = new int[5][5]; for (int i = 0; i < 5; i++) g[i][i] = 1;.

  2. Write a method int rows(int[][] g) and int cols(int[][] g).write
    Show the answer

    return g.length; and return g[0].length; (rectangular precondition).

  3. Initialize a 3×3 chessboard pattern ('B' on light squares, 'W' on dark) using a literal initializer.write
    Show the answer

    a {{...}, {...}, {...}} form with the right char values.

  4. Given int[][] g = new int[3][4]; and a loop that increments g[r][c] by r + c, predict g[2][3].trace
    Show the answer

    5.

How this room finishes

This room is done when all 4 tasks are checked and the self check is answered.