2-D arrays
An array of arrays, not a rectangle — and the FRQ that appears on every exam depends on knowing the difference.
By the end of this chapter you can
- Declare and traverse a 2-D array in row-major order
- Use the correct length for rows and columns
- Traverse by column when a problem requires it
- Explain why Java has no true 2-D array
One of the four free-response questions is about 2-D arrays, every year. It is the most predictable mark on the paper, and it turns on one structural fact.
Java has no 2-D array
int[][] grid is an array whose elements are arrays. That is not a pedantic
distinction — it is why grid.length and grid[0].length mean different things,
and why rows can have different lengths.
public class Main {
public static void main(String[] args) {
int[][] grid = {
{1, 2, 3},
{4, 5, 6}
};
System.out.println("rows: " + grid.length);
System.out.println("cols in row 0: " + grid[0].length);
System.out.println("grid[1][2]: " + grid[1][2]);
// Each row is a separate object.
System.out.println("row 0 is an int[]: " + (grid[0] instanceof int[]));
// And rows need not match in length — a "jagged" array.
int[][] jagged = new int[3][];
jagged[0] = new int[]{1};
jagged[1] = new int[]{1, 2};
jagged[2] = new int[]{1, 2, 3};
for (int[] row : jagged) System.out.print(row.length + " ");
System.out.println();
}
}The exam uses rectangular arrays almost exclusively, but the underlying model is
what makes grid[0].length the right way to ask for a column count — there is
no single “width” stored anywhere.
Row-major traversal
The standard nested loop, and the one an FRQ expects unless it says otherwise:
public class Main {
public static void main(String[] args) {
int[][] grid = {
{1, 2, 3},
{4, 5, 6}
};
int sum = 0;
StringBuilder order = new StringBuilder();
for (int r = 0; r < grid.length; r++) {
for (int c = 0; c < grid[r].length; c++) {
order.append(grid[r][c]).append(" ");
sum += grid[r][c];
}
}
System.out.println("visit order: " + order);
System.out.println("sum: " + sum);
}
}Note grid[r].length rather than grid[0].length in the inner loop. On a
rectangular array they are the same; on a jagged one only the first is correct,
and writing it that way costs nothing.
The enhanced form works too, when positions are not needed:
public class Main {
public static void main(String[] args) {
int[][] grid = {{1, 2, 3}, {4, 5, 6}};
int max = grid[0][0];
for (int[] row : grid) { // each element is a row
for (int value : row) { // each element is an int
if (value > max) max = value;
}
}
System.out.println("max: " + max);
}
}The outer variable is int[], not int. Declaring it int is a compile error,
and it is a common one on a written FRQ where no compiler is watching.
Column-major traversal
When a question asks about columns, the loops swap and the bounds come from different places:
public class Main {
public static void main(String[] args) {
int[][] grid = {
{1, 2, 3},
{4, 5, 6}
};
for (int c = 0; c < grid[0].length; c++) { // columns: width
int colSum = 0;
for (int r = 0; r < grid.length; r++) { // rows: height
colSum += grid[r][c];
}
System.out.println("column " + c + " sums to " + colSum);
}
}
}The indexing is still grid[row][column] — always row first. Only the loop
order changed. Writing grid[c][r] is the classic error, and on a
non-square grid it throws immediately.
A worked FRQ-style task
public class Main {
static boolean hasAllEvenRow(int[][] grid) {
for (int r = 0; r < grid.length; r++) {
boolean allEven = true;
for (int c = 0; c < grid[r].length; c++) {
if (grid[r][c] % 2 != 0) {
allEven = false;
break; // this row is settled
}
}
if (allEven) return true; // found one, done
}
return false;
}
public static void main(String[] args) {
System.out.println(hasAllEvenRow(new int[][]{{1,2},{4,6}})); // true
System.out.println(hasAllEvenRow(new int[][]{{1,2},{4,7}})); // false
System.out.println(hasAllEvenRow(new int[][]{{}})); // true — vacuous
}
}Two structural points that earn rubric marks:
- The flag is reset inside the outer loop. Declaring
allEvenoutside would let one bad row poison every later one. - The empty row returns true, because “all of nothing is even” is vacuously satisfied. That is what the code does, and it is worth noticing rather than discovering in testing.