C# Arrays Tutorial
In this tutorial we learn about more complex data containers called arrays, which can hold many values in a single container.
We cover flat arrays, multi-dimensional arrays, jagged arrays and how to pass an array to a function. We also cover a list of properties and functions available to the array class.
- What is an array
- How to declare an array
- How to initialize an array in memory
- How to assign a value to an array with the indexer
- How to assign multiple values to an array at once
- How to access array values with the indexer
- How to access array values with a loop
- Multi-dimensional arrays
- Jagged arrays
- How to pass an array to a function
- The Array class, properties and methods
- Other collections
- Summary
What is an array
An array is used to store a collection of data elements of the same type. Think of it as a variable that can hold multiple values.
Instead of declaring multiple variables, we declare an array with multiple elements. We can think of it as a table with a single row and many columns.
As an example, let’s consider a table with characters that form the word “Hello”. The array would have each character in their own cell.
H | e | l | l | o |
Each cell of the table is an element in our array. The array has an index to identify the location of each element.
0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|
H | e | l | l | o |
Numerical indexes always start at 0 and not 1.
When we want to access an array element, we use this index number to refer to the element.
If we’re working with a larger number of values, it’s better to store them in an array instead of declaring many variables. Arrays are stored together, in sequence, in memory and are accessed faster.
How to declare an array
To tell the compiler that we want a data container to be declared as an array, we specify open and close square brackets after the type.
type[] identifier;
Declaring an array does not initialize the array in the memory.
namespace Arrays
{
class Program
{
static void Main(string[] args)
{
int[] num;
}
}
}
How to initialize an array in memory
An array is a reference type, so we need to use the new keyword to create an instance of the array.
We also need to specify the amount of elements we want to store inside the array.
type[] identifier = new type[numOfElements];
namespace Arrays
{
class Program
{
static void Main(string[] args)
{
int[] num = new int[10];
}
}
}
We initialize the array num to be able to hold 10 integer values.
How to assign a value to an array with the indexer
To assign a value to an array we specify the array name, followed by its index in square brackets and then the value we want to assign with the assignment operator.
identifier[index] = value;
namespace Arrays
{
class Program
{
static void Main(string[] args)
{
string[] message = new string[2];
message[0] = "Hello";
message[1] = "World";
}
}
}
In the example above we initialized a new string array with two elements. Then, we assigned the words “Hello” and “World” into the first and second elements.
How to assign multiple values to an array at once
We don’t have to assign values to our array one by one. A much easier method of assigning values is array initialization.
When we initialize an array we specify multiple, comma separated, values between curly braces.
identifier[numElements] = { value1, value2 };
Array initialization syntax is one of the few times that we terminate a code execution block with a semicolon.
namespace Arrays
{
class Program
{
static void Main(string[] args)
{
string[] message1 = new string[2]
{
"Hello",
"World"
};
// or we could do it inline
string[] message2 = new string[2] { "Hello", "there" };
}
}
}
In the example above, we initialize two string arrays with some values. It’s much easier to assign values to an array with initialization syntax instead of the indexer.
How to access array values with the indexer
To access single elements in an array we specify its index between open and close square brackets.
identifier[index];
using System;
namespace Arrays
{
class Program
{
static void Main(string[] args)
{
string[] message = new string[2] { "Hello", "World" };
Console.WriteLine("{0} {1}", message[0], message[1]);
Console.ReadLine();
}
}
}
In the example above we initialize our array with the words “Hello” and “World”. Then, we print them both to the console as a single string.
How to access array values with a loop
With a collection type like an array, it makes much more sense to use loops to access its values, specially when there are many.
We can use any loop we want, but the easiest would definitely be the foreach loop, which we covered in our lesson on iteration control.
Before we continue, let’s recap on a foreach loop’s syntax.
foreach (type tempVar in collection)
{
// do something with tempVar
}
We will use an array as the collection to loop through.
using System;
namespace Arrays
{
class Program
{
static void Main(string[] args)
{
string[] message = new string[2]
{
"Hello",
"World"
};
foreach (var element in message)
{
Console.WriteLine(element);
}
Console.ReadLine();
}
}
}
In the example above, we initialize a simple string array with two words. Then we loop through the array with a foreach loop and print out each element of the array.
The loop statement would read as follows: foreach word in massage array, print the word
As mentioned earlier, we can use any loop we want. For example, if we want to use a for loop, we can. But, because a for loop needs to know the number of times it will loop, we have to specify the amount of items in the array.
Before we move on, let’s recap on a for loop’s syntax.
for(index; condition; incrementIndex)
{
array[index];
}
We can use the index number of our for loop as the index of the element in the array to iterate over the elements.
We also get the amount of elements in an array by using the Length property of the array. To use the Length property, we specify the array name, followed by a dot and then the Length keyword.
using System;
namespace Arrays
{
class Program
{
static void Main(string[] args)
{
string[] message = new string[2] { "Hello ", "World" };
for(int i = 0; i < message.Length; i++)
{
Console.WriteLine(message[i]);
}
Console.ReadLine();
}
}
}
In the example above we set our index as i, we then check if i is less than the number of elements in the array (message.Length).
Finally, we loop through each element, printing the value to the console, until we get to the last element in the array.
Multi-dimensional arrays
In C# we’re allowed to create multi-dimensional arrays, also known as rectangular arrays. We can think of a multi-dimensional array as a table with multiple rows and multiple columns.
How to declare a multi-dimensional array
To declare a multi-dimensional array, we add a comma in between the brackets to indicate a second dimension.
type[,] identifier;
namespace Arrays
{
class Program
{
static void Main(string[] args)
{
int[,] num;
}
}
}
How to initialize a multi-dimensional array
To initialize a multi-dimensional array, we specify the row number and column number between brackets.
type[,] identifier = new type[rowNum, columnNum];
namespace Arrays
{
class Program
{
static void Main(string[] args)
{
string[,] message = new string[2, 3];
}
}
}
In the example above we initialize the multi-dimensional array with 2 rows and 3 columns. That is, each dimension of our array can each hold 3 values.
How to assign values to a multi-dimensional array
To assign a single value to a multi-dimensional array with the indexer, we first specify the row number, then the column number that we want to assign the value to.
identifier[rowNum, columnNum] = value;
To initialize an array with multiple values we first specify the row number and column number we creating a new array. Then, in the code block we specify the row value and column value inside another pair of curly braces.
If we initialize the multi-dimensional array with multiple sets of values, we separate each set with a comma.
type[,] ideintifier = new type[rowNum, columnNum]
{
{ row1_column1_value, row1_column2_value } , // one set
{ row2_column1_value, row2_column2_value } // another set
};
namespace Arrays
{
class Program
{
static void Main(string[] args)
{
string[,] message = new string[2, 3]
{
{ "Row 1, Column 1", "Row 1, Column 2", "Row 1, Column 3" }, // set 1
{ "Row 2, Column 1", "Row 2, Column 2", "Row 2, Column 3" } // set 2
};
}
}
}
In the example above, we initialize a multi-dimensional array with 2 rows and 3 columns. Both sets (rows) are enclosed within curly braces and separated by a comma.
The multi-dimensional array would look like this:
Row 1, Column 1 | Row 1, Column 2 | Row 1, Column 3 |
Row 2, Column 1 | Row 2, Column 2 | Row 2, Column 3 |
How to access multi-dimensional array values with the indexer
When accessing values in a multi-dimensional array with the indexer, we specify the row number first, followed by a comma and the column number.
identifier[rownNum, columnNum];
using System;
namespace Arrays
{
class Program
{
static void Main(string[] args)
{
string[,] message = new string[2, 3]
{
{ "Row 1, Column 1", "Row 1, Column 2", "Row 1, Column 3" }, // set 1
{ "Row 2, Column 1", "Row 2, Column 2", "Row 2, Column 3" } // set 2
};
Console.WriteLine( message[1,1] );
Console.ReadLine();
}
}
}
In the example above we access the value of row 2, column 2 and print it out to the console directly.
How to access multi-dimensional array values with a loop
To access the values of a multi-dimensional array in a loop, we nest one loop inside another.
The compiler will go into the first row in the outer loop and access all of its columns in the inner loop. Then, it will go back to the outer loop for the next iteration.
The second array in a multi-dimensional array doesn’t lend itself well to a foreach loop. But, we can use a foreach loop to iterate over all the elements as if it was a flat array.
type[,] identifier = new type[rows,cols]
{
{ values... },
{ values... }
};
foreach (var element in identifier)
{
// do something with element
}
using System;
namespace Arrays
{
class Program
{
static void Main(string[] args)
{
string[,] message = new string[2, 3]
{
{ "Row 1, Column 1", "Row 1, Column 2", "Row 1, Column 3" },
{ "Row 2, Column 1", "Row 2, Column 2", "Row 2, Column 3" }
};
foreach (var element in message)
{
Console.WriteLine(element);
}
Console.ReadLine();
}
}
}
In the example above, we treat the array as a flat array and iterate through all the elements in sequence.
It’s not that it can’t be done, but there are easier solutions. We can convert the multi-dimensional array into a jagged array, or use a for loop to iterate over the elements.
It would be a much better solution to use a for loop to iterate through a multi-dimensional array.
for (rowIndex; condition; rowIndexIncrement)
{
for (columnIndex; condition; columnIndexIncrement)
{
// array[rowIndex, columnIndex]
}
}
This time, we can’t use the .Length property to find the size of the array because the array is not flat. We have to use an array function called GetLength().
The GetLength() function will find the length of the first dimension (the row) that we specify between parentheses.
type[,] identifier = new type[rows,cols]
{
{ values... },
{ values... }
};
message.GetLength(rowNum);
If we had two rows in the multi-dimensional array, we would get each one’s length with .GetLength(0) and .GetLength(1).
using System;
namespace Arrays
{
class Program
{
static void Main(string[] args)
{
int[,] num;
// Create the multi-dimensional array
// and assign values to it
string[,] message = new string[2, 3]
{
{ "Row 1, Column 1", "Row 1, Column 2", "Row 1, Column 3" },
{ "Row 2, Column 1", "Row 2, Column 2", "Row 2, Column 3" }
};
// Loop through the array and print
// the values to the console
for (int i = 0; i < message.GetLength(0); i++)
{
for (int j = 0; j < message.GetLength(1); j++)
{
Console.WriteLine(message[i, j]);
}
}
Console.ReadLine();
}
}
}
In the example above we use a nested for loop to access the array. We get the first dimension size with the .GetLength() function.
- First, the loop goes into row 1 (i 0), then column 1 at row 1 (i 0, j 0), then column 2 at row 1 (i 0, j 1), then column 3 at row 1 (i 0, j 2).
- Then, the loop goes into row 2 (i 1), then column 1 at row 2 (i 1, j 0), then column 2 at row 2 (i 1, j 1), then column 3 at row 2 (i 1, j 2).
You can play around with the conditions in both the outer and inner loops to see more clearly how the array is accessed.
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
Console.WriteLine( message[i,j] );
}
}
Jagged arrays
A jagged array is an array inside of an array. Jagged arrays are often confused with multi-dimensional arrays, but they’re different.
- A multi-dimensional array has dimensions, like rows and columns.
- A jagged array has a single row and each element in the row has a separate array inside of it.
A jagged array is also known as an array of arrays.
How to declare a jagged array
To declare a jagged array, we specify two sets of square brackets after the name.
type[][] identifier;
namespace Arrays
{
class Program
{
static void Main(string[] args)
{
int[][] num;
}
}
}
We should be mindful of the difference when declaring jagged and multi-dimensional arrays.
- A multi-dimensional array has a comma inside one pair of square brackets.
- A jagged array has no comma but two sets of square brackets.
How to initialize a jagged array
To initialize a jagged array we specify how many inner arrays we want in the first set of square brackets. In the execution block we have to declare new flat arrays, separated by a comma.
type[][] identifier = new type[numInnerArrays][]
{
new type[numElements],
new type[numElements]
};
namespace Arrays
{
class Program
{
static void Main(string[] args)
{
int[][] num = new int[2][]
{
new int[3],
new int[2]
};
}
}
}
In the example above we first specify that we want 2 inner arrays. Then, we create two new arrays in the code block, specifying how many elements each sub array is going to have.
How to initialize a jagged array with multiple sub array values
Initializing a jagged array with multiple values is similar to initializing a multi-dimensional array. The only difference is that we create a new flat array each time instead of just adding values to a dimension.
type[][] identifier = new type[numInnerArrays][]
{
new type[numElements] { value1, value2 },
new type[numElements] { value1, value2 }
};
namespace Arrays
{
class Program
{
static void Main(string[] args)
{
string[][] message = new string[2][]
{
new string[2] { "Hello", "World" },
new string[3] { "Lovely", "weather", "today" }
};
}
}
}
In the example above, we create a jagged array with 2 sub arrays. The first sub array contains the words “Hello” and “World” as its elements, and the second sub array contains “Lovely”, “weather” and “today”.
How to assign a value to a jagged array element with the indexer
To assign or change the value of a jagged array element, we first specify the inner array we want to access and then the element index inside the inner array.
identifier[numInnerArray][innerArrayElement] = value;
namespace Arrays
{
class Program
{
static void Main(string[] args)
{
string[][] message = new string[2][]
{
new string[2] { "Hello", "World" },
new string[3] { "Lovely", "weather", "today" }
};
message[0][1] = "there";
}
}
}
In the example above, we change the word “World” in the second element of the first array into the word “there”.
How to access a jagged array value with the indexer
To access a single value from the inner array of a jagged array, we first specify the inner array we want to access and then the element index inside the inner array.
identifier[numInnerArray][innerArrayElement];
using System;
namespace Arrays
{
class Program
{
static void Main(string[] args)
{
string[][] message = new string[2][]
{
new string[2] { "Hello", "World" },
new string[3] { "Lovely", "weather", "today" }
};
Console.WriteLine(message[0][0]);
Console.ReadLine();
}
}
}
In the example above, we print the first element in the first array to the console.
How to access jagged array values in a loop
Jagged array elements are much easier to access with a foreach loop than a multi-dimensional array. This is because each element is its own array, so we can nest our foreach loops.
type[][] identifier = new type[numInnerArrays][]
{
new type[numElements] { value1, value2 },
new type[numElements] { value1, value2 }
};
foreach (var innerArray in identifier)
{
// we are now inside the inner array
foreach (var innerArrayElement in innerArray)
{
// do something with the inner array element
}
}
The nested foreach loop uses the temporary variable of the inner array as its array to loop through.
using System;
namespace Arrays
{
class Program
{
static void Main(string[] args)
{
string[][] message = new string[2][]
{
new string[2] { "Hello", "World" },
new string[3] { "Lovely", "weather", "today" }
};
foreach (var innerArray in message)
{
foreach (var innerArrayElement in innerArray)
{
Console.WriteLine(innerArrayElement);
}
}
Console.ReadLine();
}
}
}
In the example above, we go into the first inner array and print both of its values to the console. Then we move on to the second inner array and print both of its values.
We can do the same thing in a for loop.
for (innerArrayIndex; condition; innerArrayIndexIncrement)
{
for (innerArrayElementIndex; condition; innerArrayElementIndexIncrement)
{
// array[rowIndex, columnIndex]
}
}
In a for loop we can use the .Length property because the array doesn’t have dimensions. The inner and outer arrays are by themselves flat. The GetLength() function will only search in arrays with dimensions.
using System;
namespace Arrays
{
class Program
{
static void Main(string[] args)
{
string[][] message = new string[2][]
{
new string[2] { "Array 1, element 1", "Array 1, element 2" },
new string[2] { "Array 2, element 1", "Array 2, element 2" }
};
for (int i = 0; i < message.Length; i++)
{
for (int j = 0; j < message.Length; j++)
{
Console.WriteLine(message[i][j]);
}
}
Console.ReadLine();
}
}
}
In the example above we use a nested for loop to access the array.
- First, we go into inner array 1 (i 0), then we go into its first element (i 0, j 0), then we go into its second element (i 0, j 1).
- Then we go into inner array 2 (i 1), then we go into its first element (i 1, j 0), then we go into its second element (i 1, j 1).
Play around with the conditions in both the outer and inner loops to see more clearly how the array is accessed.
for(int i = 0; i < 1; i++)
{
for (int j = 0; j < 2; j++)
{
Console.WriteLine(message[i][j]);
}
}
How to pass an array to a function
We can pass an array to a function as an argument in the parameter list.
We don’t have to loop through anything, the whole array is passed at once. However, when working with the array inside the function we may need to loop.
We have to mark a parameter’s type with square brackets to indicate to the compiler that the parameter will be an array.
returnType identifier(arrayType[] arrayIdentifier)
{
// functionality
}
We can then access the array through the arrayIdentifier inside the function.
using System;
namespace Arrays
{
class Program
{
static void Main(string[] args)
{
// init array with 5 numbers
int[] num = new int[5] { 1, 2, 3, 4, 5 };
// call array inside function Avg
Console.WriteLine("Average: ", Avg(num));
Console.ReadLine();
}
static double Avg(int[] arr)
{
int sum = 0;
// add all numbers in array
for(int i = 0; i < arr.Length; i++)
sum += arr[i];
// divide the sum by the amount of
// numbers to get the average and
// return the value as a double
return (double)sum / arr.Length;
}
}
}
The job of the function in the example above is to calculate the average of all numbers inside an array. It will add all the numbers together, then divide the total by the number of elements in the array.
We marked the arr parameter in the function as an int[] array, which allowed it to use the num array in the Main() function as an argument.
Because our for loop only has a single statement, we don’t enclose it in curly braces.
The Array class, properties and methods
The Array class is the base class for all the arrays in C# and is defined in the System namespace. The Array class provides us with various properties and functions to work with arrays.
We’ve already seen some examples of this throughout the tutorial when we used properties like .Length and functions like .GetLength().
Array class properties
The following table shows some of the most commonly used properties of the Array class:
Property | Description |
---|---|
IsFixedSize | Gets a value indicating whether the Array has a fixed size. |
IsReadOnly | Gets a value indicating whether the Array is read-only. |
Length | Gets a 32-bit integer that represents the total number of elements in all the dimensions of the Array. |
LongLength | Gets a 64-bit integer that represents the total number of elements in all the dimensions of the Array. |
Rank | Gets the number of dimensions of the Array. |
Array class methods
The following table describes some of the most commonly used methods of the Array class:
Function | Description |
---|---|
Clear | Sets a range of elements in the Array to zero, to false, or to null, depending on the element type. |
Copy(Array, Array, Int32) | Copies a range of elements from an Array starting at the first element and pastes them into another Array starting at the first element. |
CopyTo(Array, Int32) | Copies all the elements of the current one-dimensional Array to the specified one-dimensional Array starting at the specified destination Array index. |
GetLength | Gets a 32-bit integer that represents the number of elements in the specified dimension of the Array. |
GetLongLength | Gets a 64-bit integer that represents the number of elements in the specified dimension of the Array. |
GetType | Gets the Type of the current instance (Inherited from Object). |
GetValue(Int32) | Gets the value at the specified position in the one-dimensional Array. The index is specified as a 32-bit integer. |
IndexOf(Array, Object) | Searches for the specified object and returns the index of the first occurrence within the entire one-dimensional Array. |
Reverse(Array) | Reverses the sequence of the elements in the entire one-dimensional Array. |
SetValue(Object, Int32) | Sets a value to the element at the specified position in the one-dimensional Array. The index is specified as a 32-bit integer. |
Sort(Array) | Sorts the elements in an entire one-dimensional Array using the IComparable implementation of each element of the Array. |
Other collections
While arrays can be useful to manage fixed-size sets of data, there will be other times where we need a more flexible structure.
For this purpose C# has Collections and Generic Collections.
The table below lists the non-generic collections available to us in C#:
Collection | Description |
---|---|
ArrayList | ArrayList is similar to an array. It's dynamically-sized, which means we can add and remove items from it and the ArrayList will resize itself automatically. |
Hashtable | A Hashtable is a collection of keys and values, where we access a value with its corresponding key. |
SortedList | A SortedList is like a Hashtable and ArrayList combined. We can access values with either a key or an index. |
Stack | A Stack is a LIFO (last in, first out) style collection. Values are pushed into a stack, and popped out of the stack at the end. |
Queue | A Queue is a FIFO (first in, first out) style collection. Values are enqueued at the end of the queue and dequeued at the start of the queue. |
Summary: Points to remember
- An array is a collection of items. We can think of it as a variable that can hold many values.
- An array stores its value in sequence in memory. A CPU will be able to fetch blocks of this sequence making arrays more performant than multiple variables when working with larger amounts of individual data elements.
- We can assign a value to an array either through the indexer or through initialization.
- We can access single array values in an array through the indexer or with a loop.
- We can create multi-dimensional arrays with multiple dimensions of storage. We can think of it in terms of rows and columns.
- Multi-dimensional arrays are defined with a comma inside one set of square brackets [,].
- A foreach loop is not the best solution when looping through multi-dimensional arrays. It’s better to either use a for loop with the GetLength() function or convert the array into a jagged array.
- We can create jagged arrays (array of arrays) that allow individual arrays as elements.
- Jagged arrays are defined with multple sets of square brackets [][].
- A foreach loop will be the easiest option when loop accessing a jagged array.
- We can pass arrays to a function as a parameter. In that case we have to define the parameter as an array (square brackets after the type).
- Arrays have properties and methods to help us work with them, like the Length property or the GetLength() function.