2D array. A two-dimensional array is used to store elements that are indexed by two coordinates. In C# we separate the indexes with a comma. We can create 2D arrays of any element type.
We can initialize 2D arrays with a single statement—all the memory is part of a single region. Also remember that jagged arrays can represent a 2D space.
2D example. Here we show a 2-dimensional string array. The program creates a 2x2 string array and then prints out all 4 elements with Console.WriteLine.
Part 1 Here we initialize the 2D array with an initializer expression. Each element in this array is a string.
Part 2 We use the indexing syntax to access elements. We use 2 indexes for a 2D array. Each dimension is indexed starting at zero.
Tip It makes no difference whether we think of the first index as a row or column, or the other way around.
using System;
// Part 1: create 2D array of strings.
string[,] array = new string[,]
{
{ "cat", "dog" },
{ "bird", "fish" },
};
// Part 2: access (and print) values.
Console.WriteLine(array[0, 0]);
Console.WriteLine(array[0, 1]);
Console.WriteLine(array[1, 0]);
Console.WriteLine(array[1, 1]);cat
dog
bird
fish
Rank. Every array has a rank: this is the number of dimensions in the array. A one-dimensional array has a rank of 1. We access the Rank property from the Array base class.
Here We design a method (Handle) that receives an array reference. It then tests the Rank of the parameter array.
And In Handle() we test both 1D and 2D arrays in the same method. This method uses GetValue to access the array elements.
using System;
class Program
{
static void Main()
{
// ... A one-dimensional array.
int[] one = new int[2];
one[0] = 1;
one[1] = 2;
Handle(one);
// ... A two-dimensional array.
int[,] two = new int[2, 2];
two[0, 0] = 0;
two[1, 0] = 1;
two[0, 1] = 2;
two[1, 1] = 3;
Handle(two);
}
static void Handle(Array array)
{
Console.WriteLine("Rank: " + array.Rank);
switch (array.Rank)
{
case 1:
for (int i = 0; i < array.Length; i++)
{
Console.WriteLine(array.GetValue(i));
}
break;
case 2:
for (int i = 0; i < array.GetLength(0); i++)
{
for (int x = 0; x < array.GetLength(1); x++)
{
Console.Write(array.GetValue(i, x));
}
Console.WriteLine();
}
break;
}
}
}Rank: 1
1
2
Rank: 2
02
13
Jagged array. A jagged array is a single-dimensional array of other arrays. Because each element is another array, it can be used like a 2D array.
Part 1 First we create a jagged array of int elements. The array has 3 rows—so it can have 3 subarrays once they are all assigned.
Part 2 We assign the indexes to new int arrays. We only have an array of empty references—new arrays must be created for the rows.
Part 3 We examine each item in the jagged array. We call Length first on the array of references, and iterate through the rows.
Part 4 We iterate over the inner arrays (the columns) and print all the element values to the screen.
using System;
// Part 1: declare local jagged array with 3 rows.
int[][] jagged = new int[3][];
// Part 2: create a new array in the jagged array.
jagged[0] = new int[2];
jagged[0][0] = 1;
jagged[0][1] = 2;
jagged[1] = new int[1];
jagged[2] = new int[3] { 3, 4, 5 };
// Part 3: iterate overall the elements.
for (int i = 0; i < jagged.Length; i++)
{
// Part 4: iterate over the inner array.// ... Print all its elements.
int[] innerArray = jagged[i];
for (int a = 0; a < innerArray.Length; a++)
{
Console.Write(innerArray[a] + " ");
}
Console.WriteLine();
}1 2
0
3 4 5
3D array. Here we see the use of a three-dimensional array. You can declare and initialize the multidimensional array using the comma syntax.
Info You can loop over any 3D array using this example code. Adding levels to the for-loop allows it to handle greater dimensions.
Here We use a three-dimensional integer array reference type. We specify the dimension lengths on the array creation expression.
Also We access elements in a 2D or 3D array using the comma syntax in the array index. We read and write elements using this syntax.
using System;
// Create a three-dimensional array.
int[, ,] threeDimensional = new int[3, 5, 4];
threeDimensional[0, 0, 0] = 1;
threeDimensional[0, 1, 0] = 2;
threeDimensional[0, 2, 0] = 3;
threeDimensional[0, 3, 0] = 4;
threeDimensional[0, 4, 0] = 5;
threeDimensional[1, 1, 1] = 2;
threeDimensional[2, 2, 2] = 3;
threeDimensional[2, 2, 3] = 4;
// Loop over each dimension's length.
for (int i = 0; i < threeDimensional.GetLength(2); i++)
{
for (int y = 0; y < threeDimensional.GetLength(1); y++)
{
for (int x = 0; x < threeDimensional.GetLength(0); x++)
{
Console.Write(threeDimensional[x, y, i]);
}
Console.WriteLine();
}
Console.WriteLine();
}100
200
300
400
500
000
020
000
000
000
000
000
003
000
000
000
000
004
000
000
GetUpperBound loop. GetUpperBound() receives the highest index of the specified rank. It returns an int. The word rank is the same concept as "dimension."
Tip A 2D array has 2 ranks, 0 and 1. On more complex arrays, GetUpperBound will work more reliably than other approaches.
using System;
string[,] codes = new string[,]
{
{ "AA", "BB" },
{ "CC", "DD" }
};
// Get the upper bound.// ... Use for-loop over rows.
for (int i = 0; i <= codes.GetUpperBound(0); i++)
{
string s1 = codes[i, 0];
string s2 = codes[i, 1];
Console.WriteLine("{0}, {1}", s1, s2);
}AA, BB
CC, DD
Length-based loop. The fastest method for a 2D array is to do some arithmetic. In this example, there are five rows. GetUpperBound(0) will return 4.
And If we take Length, which is 10, and divide by 2, we get 5. We can iterate until we reach 5.
using System;
string[,] words = new string[,]
{
{ "ONE", "TWO" },
{ "THREE", "FOUR" },
{ "FIVE", "SIX" }
};
// Loop based on length.// ... Assumes each subarray is two elements long.
for (int i = 0; i < words.Length / 2; i++)
{
string s1 = words[i, 0];
string s2 = words[i, 1];
Console.WriteLine("{0}, {1}", s1, s2);
}ONE, TWO
THREE, FOUR
FIVE, SIX
GetUpperBound, int example. Here we get the 2 dimensions of the array and iterate through them. We cache array bounds in locals for better performance and clarity.
Info The performance of GetUpperBound can make an impact. But often, using jagged arrays (or flattened arrays) is the best solution.
Tip Var is used to reference the 2D array. This makes the syntax for the program simpler—var is often used with 2D arrays.
using System;
var codes = new int[,]
{
{ 200, 400 },
{ 2000, 4000 },
{ 20000, 40000 }
};
// Get all bounds before looping.
int bound0 = codes.GetUpperBound(0);
int bound1 = codes.GetUpperBound(1);
// ... Loop over bounds.
for (int i = 0; i <= bound0; i++)
{
for (int x = 0; x <= bound1; x++)
{
// Display the element at these indexes.
Console.WriteLine("ELEMENT: {0}", codes[i, x]);
}
Console.WriteLine("--");
}ELEMENT: 200
ELEMENT: 400
--
ELEMENT: 2000
ELEMENT: 4000
--
ELEMENT: 20000
ELEMENT: 40000
--
No initializers. We can create an empty 2D array by specifying its dimensions. All elements have the default value (for ints this is 0).
Also We can use a 2D array reference to refer to any size of array, but the element type must match.
using System;
// A two-dimensional array reference.
int[,] array = new int[2, 2];
array[0, 0] = 1;
Console.WriteLine(array[0, 0]);
// The same reference can hold a different size of array.
array = new int[3, 3];
array[2, 2] = 1;
Console.WriteLine(array[2, 2]);1
1
Arguments. A method may receive a 2D array by specifying the type of the elements. The dimensions are not used in the argument list—any 2D array of the correct element may be passed.
Tip Changes to elements in the argument will also affect the original version. Only the reference is copied to the new method.
Here The PrintFirstElement() method receives a 2D bool array. It then prints the value of the bool in the first row and first column.
using System;
class Program
{
static void PrintFirstElement(bool[,] values)
{
// Display value of first element in first row.
Console.WriteLine(values[0, 0]);
}
static void Main()
{
// Any array size of the right element type can be used.
bool[,] values = new bool[100, 100];
values[0, 0] = true;
PrintFirstElement(values);
}
}True
Loops. 2D array loops are complicated. It is easy to cause errors related to invalid indexes. Here our 2D array is a four-element box, composed of two pairs.
Next To begin our for-loop, we acquire the upper bound of the zero dimension, and the upper bound of the first dimension of the array.
Warning The loop will not continue to work correctly if the array reference itself is modified or the array data is resized.
Note Nested loops are not always needed. In an array with 2 elements in each row, you can access positions 0 and 1 from a single for-loop.
using System;
// Instantiate a new 2D string array.
string[,] array = new string[2, 2];
array[0, 0] = "top left";
array[0, 1] = "top right";
array[1, 0] = "bottom left";
array[1, 1] = "bottom right";
// Get upper bounds for the array
int bound0 = array.GetUpperBound(0);
int bound1 = array.GetUpperBound(1);
// Use for-loops to iterate over the array elements.
for (int variable1 = 0; variable1 <= bound0; variable1++)
{
for (int variable2 = 0; variable2 <= bound1; variable2++)
{
string value = array[variable1, variable2];
Console.WriteLine(value);
}
Console.WriteLine();
}top left
top right
bottom left
bottom right
Add row, add column. You cannot add a new row or column to a 2D array—the array is fixed in size and a new array must be created to add elements. Here we introduce AddRow and AddColumn.
Info AddRow allocates a new 2D int array and copies the current array into the new one. It then copies a separate int array as a new row.
Next AddColumn allocates a new array with an extra column and copies the previous array. It copies an int array into a new column.
Note These methods do not "add rows or columns" to a 2D array. Instead they create a new array and add to that.
Tip For optimal performance, consider using a List and adding int arrays to that. Or add Lists of ints to a List in a 2D list.
using System;
class Program
{
static int[,] AddRow(int[,] original, int[] added)
{
int lastRow = original.GetUpperBound(0);
int lastColumn = original.GetUpperBound(1);
// Create new array.
int[,] result = new int[lastRow + 2, lastColumn + 1];
// Copy existing array into the new array.
for (int i = 0; i <= lastRow; i++)
{
for (int x = 0; x <= lastColumn; x++)
{
result[i, x] = original[i, x];
}
}
// Add the new row.
for (int i = 0; i < added.Length; i++)
{
result[lastRow + 1, i] = added[i];
}
return result;
}
static int[,] AddColumn(int[,] original, int[] added)
{
int lastRow = original.GetUpperBound(0);
int lastColumn = original.GetUpperBound(1);
// Create new array.
int[,] result = new int[lastRow + 1, lastColumn + 2];
// Copy the array.
for (int i = 0; i <= lastRow; i++)
{
for (int x = 0; x <= lastColumn; x++)
{
result[i, x] = original[i, x];
}
}
// Add the new column.
for (int i = 0; i < added.Length; i++)
{
result[i, lastColumn + 1] = added[i];
}
return result;
}
static void Display(int[,] array)
{
// Loop over 2D int array and display it.
for (int i = 0; i <= array.GetUpperBound(0); i++)
{
for (int x = 0; x <= array.GetUpperBound(1); x++)
{
Console.Write(array[i, x]);
Console.Write(" ");
}
Console.WriteLine();
}
}
static void Main()
{
int[,] values = { { 10, 20 }, { 30, 40 } };
Console.WriteLine("CURRENT");
Display(values);
// Add row and display the new array.
int[,] valuesRowAdded = AddRow(values, new int[] { 50, 60 });
Console.WriteLine("ADD ROW");
Display(valuesRowAdded);
// Add column and display the new array.
int[,] valuesColumnAdded = AddColumn(valuesRowAdded, new int[] { -1, -2, -3 });
Console.WriteLine("ADD COLUMN");
Display(valuesColumnAdded);
}
}CURRENT
10 20
30 40
ADD ROW
10 20
30 40
50 60
ADD COLUMN
10 20 -1
30 40 -2
50 60 -3
Error, cannot convert. A 2D array is not compatible with a 1D array—the types are different. So we cannot pass a 2D array to a method that accepts a 1D array (or the opposite case).
class Program
{
static void Main()
{
string[,] array = new string[10, 10];
Test(array);
}
static void Test(string[] example)
{
}
}error CS1503: Argument 1: cannot convert from 'string[*,*]' to 'string[]'
Benchmark, GetUpperBound. GetUpperBound is slow. Its result should be stored in a local variable. This benchmark shows the performance decrease with GetUpperBound.
Version 1 This code uses GetUpperBound 0 to loop over the rows in a 2D array. It stores the result of GetUpperBound in a local.
Version 2 This version uses the fact that each row has 2 elements, so it can derive the total row count from the Length divided by 2.
Result On .NET 5 in 2021, using the Length property for a loop boundary is faster than using GetUpperBound.
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
const int _max = 10000000;
int[,] weights = new int[,]
{
{ 100, 20 },
{ 0, 0 },
{ 5, 10 },
};
// Version 1: sum 2D array with GetUpperBound loop.
var s1 = Stopwatch.StartNew();
for (int i = 0; i < _max; i++)
{
int sum = 0;
int top = weights.GetUpperBound(0);
for (int z = 0; z <= top; z++)
{
sum += weights[z, 0] + weights[z, 1];
}
if (sum != 135)
{
return;
}
}
s1.Stop();
// Version 2: sum 2D array with Length-based loop.
var s2 = Stopwatch.StartNew();
for (int i = 0; i < _max; i++)
{
int sum = 0;
int count = weights.Length / 2;
for (int z = 0; z < count; z++)
{
sum += weights[z, 0] + weights[z, 1];
}
if (sum != 135)
{
return;
}
}
s2.Stop();
Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000000) / _max).ToString("0.00 ns"));
Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000000) / _max).ToString("0.00 ns"));9.34 ns GetUpperBound
6.98 ns Length / 2
With initializer syntax, we can create 2D arrays. And then with nested for-loops we can iterate over them—it is easiest to use Length, but GetUpperBound is sometimes needed.
Dot Net Perls is a collection of tested code examples. Pages are continually updated to stay current, with code correctness a top priority.
Sam Allen is passionate about computer languages. In the past, his work has been recommended by Apple and Microsoft and he has studied computers at a selective university in the United States.
This page was last updated on Nov 29, 2023 (new example).