AP CSA · Unit 8

2D Arrays

Review

Arrays are Objects

  • Arrays have a public member variable: array.length
  • Array variables are references — they point to the actual data in memory, not the data itself
  • Java gives arrays a special operator unavailable to other objects: the [] subscript operator

▸ Memory layout

evenNums
(int[])
0
2
4
6
8
10
12
The question

Arrays are objects.

If you can have an array of objects...

...and arrays are objects...

Can you have an array
of arrays?

YES!

An array of arrays is called a 2D Array

Concept

What would it look like
in memory?

We know a regular array looks like this — a variable that references a block of data:

evenNums
(int[])
0
2
4
6
8
10
12

Think about it...

What if each element in that outer array held a reference to another array? Sketch what that structure would look like — then continue.

Then advance to the next slide ⟶

Real-world example

The Map Problem

Imagine building a game that needs a map. The natural way to represent it is as a grid of cells.

To store the elevation of each cell, you'd want something like this grid →

Elevation Grid

4
6
8
10
12
6
7
11
12
16
5
6
10
14
16
4
6
10
13
15
3
5
9
12
14
Step 1

Each row becomes its own array

To store grid data, make each row its own int[] array:

r0
4
6
8
10
12
int[] r0 = {4, 6, 8, 10, 12};
r1
6
7
11
12
16
int[] r1 = {6, 7, 11, 12, 16};
r2
5
6
10
14
16
int[] r2 = {5, 6, 10, 14, 16};
r3
4
6
10
13
15
int[] r3 = {4, 6, 10, 13, 15};
r4
3
5
9
12
14
int[] r4 = {3, 5, 9, 12, 14};
Step 2

Put the rows inside one array

Instead of 5 separate row variables, store them all in one outer array that holds references to each row:

elevation
(int[][])
4
6
8
10
12
6
7
11
12
16
5
6
10
14
16
4
6
10
13
15
3
5
9
12
14

→ An array of arrays = a 2D array, because it has both length and width.

Syntax

Declaring a 2D Array

1D Array (familiar)

Java
// Declares an array with 3 cells
int[] arr = new int[3];

2D Array (new!)

Java
// 3 rows, 5 columns
int[][] arr = new int[3][5];

The first index is the row, the second index is the column. Both are required to access a single element:

arr[1][3] = 99;  // row 1, col 3
arr[0][0] = 42;  // row 0, col 0  (top-left)
Memory

arr is an array of int arrays

int[][] arr = new int[3][5];
arr
(int[][])
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
arr.length == 3

The outer array holds 3 rows

arr[0].length == 5

Each row has 5 columns

Edge case

Ragged Arrays

Since a 2D array is an array of arrays, each row can have a different length.

Always use arr[row].length when iterating columns — it handles ragged arrays safely:

Ragged Array

4
6
8
10
12
6
7
5
6
10
14
4
6
10
13
3
5
9

arr[0].length = 5    arr[1].length = 2

Java
for (int row = 0; row < arr.length; row++) {
  for (int col = 0; col < arr[row].length; col++) {
    // Safe for ragged arrays!
  }
}

* Ragged arrays won't appear on the AP exam — but good to know!

Under the hood

Row-Major Order

Java stores 2D arrays in row-major order: elements of each row are stored consecutively in memory.

  • A1 is stored next to A2 next to A3
  • B1 may be adjacent to A3, but Java does not guarantee it — the next row could be elsewhere in memory
  • Elements of different rows may not be adjacent

This is why iterating row-by-row is more cache-friendly than column-by-column.

Logical grid

A1
A2
A3
B1
B2
B3
C1
C2
C3

In memory

A1
A2
A3
B1
B2
B3
C1
C2
C3
Initialization

Method 1: Literal Values

Declare and populate a 2D array in one statement using nested curly braces:

Java
int[][] matrix = {
    {0,  1,  2,  3 },  // row 0
    {10, 11, 12, 13},  // row 1
    {20, 21, 22, 23}   // row 2
};

Results in:

matrix
(int[][])
0
1
2
3
10
11
12
13
20
21
22
23
Initialization

Method 2: Nested For Loop

Java
int[][] matrix = new int[3][4];

for (int row = 0; row < matrix.length; row++) {
  for (int col = 0; col < matrix[row].length; col++) {
    matrix[row][col] = row * 10 + col;
  }
}

Formula: row * 10 + col

  • Row 0: 0×10+0=0, 0×10+1=1
  • Row 1: 1×10+0=10, 1×10+1=11

Results in:

matrix
(int[][])
0
1
2
3
10
11
12
13
20
21
22
23
Check your understanding

Will this work?

Java
int[][] matrix = new int[3][4];
for (int[] row : matrix) {
  for (int col = 0; col < row.length; col++) {
    row[col] = 10 * col;
  }
}

Yes, it works!

  • The enhanced for gives you each int[] row as a reference
  • Mutations through row do affect the original matrix
  • There is no numeric row index variable in this loop, just a reference to each row.

Result:

matrix
(int[][])
0
10
20
30
0
10
20
30
0
10
20
30
Check your understanding

Will this work?

Java
int[][] matrix = new int[3][4];
for (int[] row : matrix) {
  for (int val : row) {
    val = 10;
  }
}

No — it doesn't work!

  • int val is a copy of the value stored in the array cell
  • Assigning val = 10 updates only the local copy — matrix is never touched
  • This works for int[] rows because arrays are references; primitive ints are not

Result — matrix is unchanged (all zeros):

matrix
(int[][])
0
0
0
0
0
0
0
0
0
0
0
0
Check your understanding

Will this work?

Java
int[][] matrix = new int[3][3];
for (int r = 0, c = 0; r < matrix.length; r++, c++) {
  matrix[r][c] = 99;
}

Not quite!

  • The loop runs without errors, but only visits the main diagonal — 3 cells out of 9
  • r and c step together: (0,0) → (1,1) → (2,2)
  • To fill all cells you need nested loops, or derive r = k / cols and c = k % cols from a single counter

Two variables, one loop

  • Java's for allows multiple declarations in the init clause, separated by a comma:
    int r = 0, c = 0
  • The update clause also supports multiple expressions: r++, c++. Both step on every iteration.
  • This is intentionally useful for diagonals or parallel traversal. It's valid Java, just not a full-grid traversal.

Result — only the diagonal is set
(6 cells remain 0):

matrix
(int[][])
99
0
0
0
99
0
0
0
99