← Open in the full interactive course (progress tracking, search & more)

A multidimensional array is a single grid — rows and columns baked into one rectangular block, addressed with one index per dimension.

Picture a spreadsheet, or a seating chart for a theater: rows and columns, every row exactly the same width. You don't think of it as "a list of lists" — you think of it as one grid, and you find a seat by saying "row 3, seat 5." In the previous lesson you learned that an array is a single row of boxes. This lesson extends that same idea into two (or more) dimensions.

In this lesson, you'll learn what a multidimensional array is, how C#'s rectangular arrays work, how they're laid out in memory, and when a grid-shaped array is exactly the tool you need.

What Is It?

The Simple Explanation

A multidimensional array is a grid. Instead of one index to find a value, you use two (for a grid), three (for a cube), or more. A 2D array is the most common — think rows and columns, like a spreadsheet or a chessboard.

The Technical Definition

In C#, this specific kind — where every row has the same length — is called a rectangular array, written with commas inside the brackets: T[,] for 2D, T[,,] for 3D, and so on. It's a single array object with multiple dimensions, not an array containing other arrays (that's a different structure — a jagged array, covered in the next lesson).

Rectangular Array = One Grid, Fixed Dimensions

Why Does It Exist?

The Problem

Some data is naturally grid-shaped: a spreadsheet, a tic-tac-toe board, a seating chart, pixel data in an image, a multiplication table. You could try to force this into a single 1D array — for a 3×3 board, you'd flatten it into 9 values and do the row/column math yourself every time:

int[] board = new int[9]; // flattened 3x3 board int row = 1, col = 2; int flatIndex = row * 3 + col; // you compute this yourself, every time board[flatIndex] = 5;

This works, but it's error-prone (get the multiplier wrong and everything shifts) and it hides the true shape of the data from anyone reading the code.

The Solution

A rectangular array lets the language do that row/column math for you, and lets your code say what it means:

int[,] board = new int[3, 3]; board[1, 2] = 5; // row 1, column 2 — reads exactly like "row 1, col 2"

Big Picture

A 3×4 GRID — int[3, 4]
[0,0]
[0,1]
[0,2]
[0,3]
[1,0]
[1,1]
[1,2]
[1,3]
[2,0]
[2,1]
[2,2]
[2,3]
3 rows × 4 columns = 12 cells total. The highlighted cell is grid[1, 2] — row 1, column 2. Every row has exactly 4 columns — that's what makes it "rectangular."

How It Works

USING A RECTANGULAR ARRAY, STEP BY STEP
1. DECLARE AND CREATE
int[,] grid = new int[3, 4];   // 3 rows, 4 columns, all default to 0
2. INITIALIZE WITH VALUES
int[,] grid =
{
    { 1, 2, 3 },
    { 4, 5, 6 },
};   // 2 rows, 3 columns
3. READ AND WRITE BY [ROW, COLUMN]
int value = grid[1, 2];   // read row 1, column 2 → 6
grid[0, 0] = 99;           // write row 0, column 0
4. CHECK THE DIMENSIONS AND ITERATE
int rows = grid.GetLength(0);   // 2
int cols = grid.GetLength(1);   // 3

for (int r = 0; r < rows; r++)
{
    for (int c = 0; c < cols; c++)
        Console.Write($"{grid[r, c]} ");
    Console.WriteLine();
}

Simple Example

// A 3x3 tic-tac-toe board: 0 = empty, 1 = X, 2 = O int[,] board = new int[3, 3]; board[0, 0] = 1; // X board[1, 1] = 2; // O board[2, 2] = 1; // X for (int row = 0; row < board.GetLength(0); row++) { for (int col = 0; col < board.GetLength(1); col++) { char symbol = board[row, col] switch { 1 => 'X', 2 => 'O', _ => '.' }; Console.Write($"{symbol} "); } Console.WriteLine(); } // X . . // . O . // . . X

Code → Meaning → Result:

Real-World Example

A small movie theater sells seats laid out in a fixed grid: 6 rows, 8 seats per row. Every row has exactly the same width, which makes this a perfect rectangular array — not every seating chart is this uniform (see the jagged array lesson next for when it isn't).

const int Rows = 6; const int SeatsPerRow = 8; bool[,] seatTaken = new bool[Rows, SeatsPerRow]; // all false = all available void BookSeat(int row, int seat) { if (row < 0 || row >= Rows || seat < 0 || seat >= SeatsPerRow) { Console.WriteLine("Invalid seat."); return; } if (seatTaken[row, seat]) { Console.WriteLine($"Row {row + 1}, Seat {seat + 1} is already taken."); return; } seatTaken[row, seat] = true; Console.WriteLine($"Booked Row {row + 1}, Seat {seat + 1}."); } void PrintChart() { for (int r = 0; r < Rows; r++) { for (int s = 0; s < SeatsPerRow; s++) Console.Write(seatTaken[r, s] ? "[X]" : "[ ]"); Console.WriteLine($" Row {r + 1}"); } } BookSeat(2, 4); BookSeat(2, 4); // already taken PrintChart(); // Booked Row 3, Seat 5. // Row 3, Seat 5 is already taken. // [ ][ ][ ][ ][ ][ ][ ][ ] Row 1 // [ ][ ][ ][ ][ ][ ][ ][ ] Row 2 // [ ][ ][ ][ ][X][ ][ ][ ] Row 3 // [ ][ ][ ][ ][ ][ ][ ][ ] Row 4 // [ ][ ][ ][ ][ ][ ][ ][ ] Row 5 // [ ][ ][ ][ ][ ][ ][ ][ ] Row 6

Analogy

A City Grid Map

A rectangular array is like a city built on a perfect grid — every street the same length, every block the same size. You find any building with two numbers: "5th Avenue and 3rd Street." You don't need to know how the city was constructed — the grid structure itself tells you exactly where to look.

A rectangular array works the same way: grid[row, column] is your "avenue and street" — two coordinates that pinpoint one cell in a perfectly uniform layout.

Under the Hood

HOW A RECTANGULAR ARRAY IS STORED
1. STILL ONE CONTIGUOUS BLOCK
2. WHY THIS MATTERS FOR PERFORMANCE
3. BOUNDS CHECKING PER DIMENSION

Common Confusion

1. int[,] vs int[][] — these are not the same type

int[,] (comma) is one rectangular array. int[][] (separate brackets) is an array of arrays — a jagged array, where each inner array can be a different length. The next lesson covers jagged arrays in depth; for now, just remember: comma = one uniform grid, separate brackets = a collection of independent rows.

2. .Length vs .GetLength(dimension)

On a multidimensional array, .Length gives you the total number of cells (rows × columns), not the row or column count individually. To get a specific dimension's size, use .GetLength(0) for rows, .GetLength(1) for columns.

Common Mistakes

Mistake 1 — Mixing up row and column order

It's easy to accidentally swap them, especially with non-square grids:

int[,] grid = new int[3, 8]; // 3 rows, 8 columns grid[5, 1] = 10; // IndexOutOfRangeException — there is no row 5, only rows 0-2

Always double-check which dimension is rows and which is columns for your specific grid, and stay consistent throughout your code.

Mistake 2 — Using foreach when you need row/column position

foreach visits every cell, but doesn't tell you which row and column you're on:

foreach (int cell in grid) Console.Write(cell); // you get the value, but not its [row, col] position

Use nested for loops when the position matters, as shown in "How It Works" above.

Mistake 3 — Assuming .Length gives the row count

grid.Length on a 3×4 grid returns 12 (total cells), not 3. Use grid.GetLength(0) for rows.

When Should I Use It?

Use a rectangular array when

Reach for something else when

Mental Model

Multidimensional array = a grid, not a list of lists
int[,] = one rectangular array (comma inside the brackets)
grid[row, col] = your two coordinates into the grid

Remember:
· Every row has the same number of columns — that's what makes it "rectangular."
· Under the hood it's still one contiguous block, just addressed with two numbers instead of one.
· Use GetLength(0)/GetLength(1) for row/column counts, not .Length.

Key Takeaway


Check Your Understanding

You've seen how rectangular arrays model grid-shaped data with one uniform block of memory. Let's test it.

1. Which declaration creates a genuine 2D rectangular array?

Show answer

Correct: B

Why B is correct: The comma inside the square brackets, [,], is C#'s syntax for a rectangular array — one array object with two dimensions.

Why A is incorrect: Separate brackets, [][], declare a jagged array — an array of arrays, which is a different structure covered in the next lesson.

Why C is incorrect: List<int> is a one-dimensional resizable list, not a grid.

Why D is incorrect: That syntax isn't valid C# — the type and brackets must appear together, as in int[,].

Reinforcement: A comma inside one set of brackets means one rectangular array; separate bracket pairs mean an array of arrays.

2. Given int[,] grid = new int[3, 5];, what does grid.Length return?

Show answer

Correct: C

Why C is correct: .Length on a multidimensional array returns the total number of elements across all dimensions — here, 3 rows × 5 columns = 15 cells.

Why A is incorrect: 3 is the row count, which you'd get from GetLength(0), not .Length.

Why B is incorrect: 5 is the column count, which you'd get from GetLength(1), not .Length.

Why D is incorrect: .Length works fine on multidimensional arrays — it just answers a different question (total cells) than beginners often expect.

Reinforcement: Use GetLength(0)/GetLength(1) for individual dimension sizes; use .Length only when you want the grand total.

3. Why is a rectangular array a good fit for a fixed 6-row, 8-seat theater seating chart, but not for an org chart where each manager has a different number of direct reports?

Show answer

Correct: B

Why B is correct: Rectangular arrays enforce a uniform shape — every row must be the same length. The theater's 8-seats-per-row layout satisfies that. An org chart's manager-to-reports structure does not, since team sizes vary — that irregular shape calls for a jagged array instead.

Why A is incorrect: Rectangular arrays work fine with bool, as shown in the seating chart example.

Why C is incorrect: Rectangular arrays are typically faster and more memory-compact than jagged arrays for uniform data — the issue here is shape, not speed.

Why D is incorrect: The structures genuinely differ — forcing an irregular org chart into a rectangular array would waste memory on unused "seats" or make illegal states representable.

Reinforcement: Choose a rectangular array only when every row is genuinely the same length.

4. What is the most likely cause of an IndexOutOfRangeException when working with int[,] grid = new int[4, 6];?

Show answer

Correct: C

Why C is correct: With 4 rows, valid row indexes are 0–3. Index 4 is out of range — the same off-by-one mistake that trips people up with 1D arrays, just on a second dimension too.

Why A is incorrect: [3, 5] is valid — row 3 is the last row (0–3), and column 5 is the last column (0–5).

Why B is incorrect: [0, 0] is always a valid position in any non-empty grid.

Why D is incorrect: GetLength(0) simply returns a number (4); it doesn't touch grid data and can't throw an out-of-range exception.

Reinforcement: With N rows, valid row indexes always run 0 through N-1 — the same rule as 1D arrays, applied per dimension.

You can now model true grid-shaped data with rectangular arrays. Next: what to do when the rows aren't all the same length.


dotnetmadeeasy.com — Learn C# and .NET, the right way.