C# Multidimensional Arrays
Multidimensional arrays in C# store data that naturally has more than one index, such as rows and columns in a table, cells on a game board, or values in a matrix. They matter because many real programs work with grid-shaped data instead of a simple one-dimensional list.
C# gives you two main choices: rectangular arrays such as int[,], where every row has the same number of columns, and jagged arrays such as int[][], where each row is a separate array and can have its own length.
Overview: How Multidimensional Arrays Work
A multidimensional array is an array whose elements are addressed with more than one index. The most common form is a two-dimensional rectangular array written with a comma in the brackets: type[,]. You access one element with array[row, column]. A three-dimensional array uses type[,,] and is accessed with three indexes, such as cube[layer, row, column].
Rectangular arrays are single array objects managed by the Common Language Runtime. A declaration such as int[,] seats = new int[3, 4]; creates one array with 3 rows and 4 columns, for 12 integer elements total. The shape is fixed. You cannot later add a fourth row or make row 1 shorter than row 2. The CLR stores the rank, which is the number of dimensions, and the length for each dimension. The Rank property reports the number of dimensions, while GetLength(0) reports the length of the first dimension and GetLength(1) reports the length of the second.
Like one-dimensional arrays, rectangular arrays are reference types. The variable stores a reference to an array object, not all the values directly inside the variable. Elements are initialized to the default value for the element type: 0 for numeric types, false for bool, and null for reference types. Indexes are zero-based in every dimension, so a 3-by-4 array has row indexes 0, 1, 2 and column indexes 0, 1, 2, 3.
A jagged array is different. int[][] means an array whose elements are int[] arrays. You access it with two bracket pairs: array[row][column]. Because each row is a separate array object, rows can have different lengths. That makes jagged arrays a good fit for triangular data, grouped results, schedules with varying numbers of entries, or any structure where each row is not the same width.
Choose a rectangular array when the data is truly rectangular: spreadsheets, chess boards, tic-tac-toe boards, image pixels, and mathematical matrices. Choose a jagged array when the data is a collection of rows and each row may be a different size.
Syntax
type[,] name = new type[rowCount, columnCount];
type[,] name = { { value00, value01 }, { value10, value11 } };
type[,,] cube = new type[depth, rows, columns];
type[][] jagged = new type[rowCount][];
jagged[0] = new type[columnCountForFirstRow];
| Syntax | Meaning |
|---|---|
type[,] |
A rectangular two-dimensional array. Every row has the same number of columns. |
new type[rows, columns] |
Creates one rectangular array object with the specified shape. |
array[row, column] |
Reads or writes one element in a rectangular array. |
array.GetLength(0) |
Returns the number of rows in a two-dimensional rectangular array. |
array.GetLength(1) |
Returns the number of columns in a two-dimensional rectangular array. |
type[][] |
A jagged array: an array of arrays. Rows can have different lengths. |
array[row][column] |
Reads or writes one element in a jagged array. |
Examples
Creating and Printing a Rectangular Array
using System;
class Program
{
static void Main()
{
int[,] scores =
{
{ 84, 91, 76 },
{ 88, 95, 90 }
};
for (int row = 0; row < scores.GetLength(0); row++)
{
for (int column = 0; column < scores.GetLength(1); column++)
{
Console.Write(scores[row, column] + " ");
}
Console.WriteLine();
}
}
}
Output:
84 91 76
88 95 90
This program creates a 2-by-3 rectangular array. The outer loop walks through rows, and the inner loop walks through columns in the current row. GetLength(0) is used for the row count and GetLength(1) is used for the column count, which avoids hard-coding the shape.
Finding Row Totals in a Grade Table
using System;
class Program
{
static void Main()
{
int[,] grades =
{
{ 90, 85, 92, 88 },
{ 76, 81, 79, 84 },
{ 100, 98, 95, 97 }
};
for (int student = 0; student < grades.GetLength(0); student++)
{
int total = 0;
for (int assignment = 0; assignment < grades.GetLength(1); assignment++)
{
total += grades[student, assignment];
}
double average = (double)total / grades.GetLength(1);
Console.WriteLine($"Student {student + 1}: {average:F1}");
}
}
}
Output:
Student 1: 88.8
Student 2: 80.0
Student 3: 97.5
A rectangular array is a natural fit because every student has the same number of assignment grades. The row index represents the student, and the column index represents the assignment. The cast to double prevents integer division, so the average keeps its decimal part.
Using a Jagged Array for Uneven Rows
using System;
class Program
{
static void Main()
{
string[][] dailyTasks = new string[3][];
dailyTasks[0] = new[] { "Email", "Build" };
dailyTasks[1] = new[] { "Plan", "Code", "Review" };
dailyTasks[2] = new[] { "Deploy" };
for (int day = 0; day < dailyTasks.Length; day++)
{
Console.WriteLine($"Day {day + 1}: {dailyTasks[day].Length} tasks");
for (int task = 0; task < dailyTasks[day].Length; task++)
{
Console.WriteLine($"- {dailyTasks[day][task]}");
}
}
}
}
Output:
Day 1: 2 tasks
- Email
- Build
Day 2: 3 tasks
- Plan
- Code
- Review
Day 3: 1 tasks
- Deploy
This is not rectangular data because each day has a different number of tasks. A jagged array lets each row be a separate string[]. Notice that the outer length comes from dailyTasks.Length, while each inner loop uses dailyTasks[day].Length.
Representing a 3D Coordinate Space
using System;
class Program
{
static void Main()
{
bool[,,] occupied = new bool[2, 2, 3];
occupied[0, 1, 2] = true;
occupied[1, 0, 1] = true;
Console.WriteLine($"Rank: {occupied.Rank}");
Console.WriteLine($"Depth: {occupied.GetLength(0)}");
Console.WriteLine($"Rows: {occupied.GetLength(1)}");
Console.WriteLine($"Columns: {occupied.GetLength(2)}");
Console.WriteLine($"Cell 0,1,2: {occupied[0, 1, 2]}");
}
}
Output:
Rank: 3
Depth: 2
Rows: 2
Columns: 3
Cell 0,1,2: True
Higher-rank rectangular arrays use the same rules with more indexes. Here the first dimension represents depth, the second rows, and the third columns. Three-dimensional arrays are useful in specialized situations, but many programs stay clearer when complex structures are modeled with classes or records instead.
How It Works Step by Step
- The compiler reads a type such as
int[,]and records that the variable can refer to a rectangular array with two dimensions. - The expression
new int[3, 4]asks the CLR to allocate one managed array object with enough space for 12 integers plus array metadata. - The CLR initializes each element to the default value for
int, which is0. - When code evaluates
grid[row, column], the runtime checks that each index is inside the correct dimension. - If both indexes are valid, the runtime calculates the element location and reads or writes the value. If either index is invalid, it throws
IndexOutOfRangeException. - For a jagged array, the outer array lookup happens first. Then the selected inner array is indexed. This is why
jagged[row][column]can fail if the row itself isnullor if the column is outside that row’s length.
Rectangular arrays expose Length, but it returns the total number of elements across all dimensions. For a 3-by-4 array, Length is 12, not 3 or 4. Use GetLength when looping by dimension.
Common Mistakes
Using Length as the Row Count
int[,] grid = new int[2, 3];
for (int row = 0; row < grid.Length; row++)
{
Console.WriteLine(grid[row, 0]);
}
This code compiles, but it is logically wrong. grid.Length is 6, because the array contains six total elements. Rows only go from 0 to 1, so the loop eventually tries an invalid row index. Use GetLength(0) for rows.
using System;
class Program
{
static void Main()
{
int[,] grid = new int[2, 3];
for (int row = 0; row < grid.GetLength(0); row++)
{
Console.WriteLine(grid[row, 0]);
}
}
}
Output:
0
0
Mixing Rectangular and Jagged Index Syntax
int[,] table = new int[2, 2];
table[0][1] = 5;
A rectangular array uses one bracket pair with comma-separated indexes. table[0][1] is jagged-array syntax and does not compile for int[,]. The corrected rectangular syntax is shown below.
using System;
class Program
{
static void Main()
{
int[,] table = new int[2, 2];
table[0, 1] = 5;
Console.WriteLine(table[0, 1]);
}
}
Output:
5
Forgetting to Create Inner Arrays
string[][] names = new string[2][];
names[0][0] = "Ada";
The outer jagged array has two slots, but each slot initially contains null. You must create each inner array before indexing into it.
using System;
class Program
{
static void Main()
{
string[][] names = new string[2][];
names[0] = new string[1];
names[0][0] = "Ada";
Console.WriteLine(names[0][0]);
}
}
Output:
Ada
Best Practices
- Use
GetLength(dimension)when looping through rectangular arrays. - Use clear index names such as
row,column,layer,student, orassignmentinstead of vague names when the meaning matters. - Prefer rectangular arrays for true grids with equal row lengths.
- Prefer jagged arrays when rows are uneven or when each row should be replaceable independently.
- Remember that
Lengthon a rectangular array is the total element count, not a single dimension. - Keep array rank reasonable. If you need many dimensions, a small class or record with named properties may be easier to understand.
- Avoid hard-coded row and column counts in loops. Let the array report its own dimensions.
- When using jagged arrays, initialize every row before reading or writing row elements.
Practice Exercises
- Create a 3-by-3
char[,]tic-tac-toe board, fill it with'.', then place'X'in the center and print the board. - Create a rectangular
int[,]with sales totals for 2 stores across 4 weeks. Print each store’s total sales. - Create a jagged
string[][]where each row contains the attendees for one meeting. Print each meeting number and its attendee count.
Summary
- Rectangular arrays use syntax such as
int[,]and store equal-length rows in one array object. - Jagged arrays use syntax such as
int[][]and store separate inner arrays that can have different lengths. - Use
array[row, column]for rectangular arrays andarray[row][column]for jagged arrays. - Use
GetLength(0),GetLength(1), and higher dimension numbers to loop safely through rectangular arrays. Lengthon a rectangular array returns the total number of elements.- Every dimension is zero-based, and the CLR checks bounds at runtime.
