Arrays

An array represents a fixed number of elements of a particular type. The elements in an array are always stored in a contiguous block of memory, providing highly efficient access.

An array is denoted with square brackets after the element type. The following declares an array of 5 characters:

char[] vowels = new char[5];

Square brackets also index the array, accessing a particular element by position:

vowels[0] = 'a'; vowels[1] = 'e'; vowels[2] = 'i';
vowels[3] = 'o'; vowels[4] = 'u';

Console.WriteLine (vowels [1]);      // e

This prints “e” because array indexes start at 0. We can use a for loop statement to iterate through each element in the array. The for loop in this example cycles the integer i from 0 to 4:

for (int i = 0; i < vowels.Length; i++)
  Console.Write (vowels [i]);            // aeiou

Arrays also implement IEnumerable<T> (see Enumeration and Iterators), so you can also enumerate members with the foreach statement:

foreach (char c in vowels) Console.Write (c);  // aeiou

All array indexing is bounds-checked by the runtime. An IndexOutOfRangeException is thrown if you use an invalid index:

vowels[5] = 'y';   // Runtime error

The Length property of an array returns the number of elements in the array. Once an array has been created, its length cannot be changed. The System.Collection namespace and subnamespaces provide higher-level data structures, such as dynamically sized arrays and dictionaries.

An array initialization expression lets you declare and populate an array in a single step:

char[] vowels = new char[] {'a','e','i','o','u'};

or simply:

char[] vowels = {'a','e','i','o','u'};

All arrays inherit from the System.Array class, which defines common methods and properties for all arrays. This includes instance properties such as Length and Rank, and static methods to:

Creating an array always pre-initializes the elements with default values. The default value for a type is the result of a bitwise zeroing of memory. For example, consider creating an array of integers. Since int is a value type, this allocates 1,000 integers in one contiguous block of memory. The default value for each element will be 0:

int[] a = new int[1000];
Console.Write (a[123]);            // 0

With reference-type elements, the default value is null.

An array itself is always a reference type object, regardless of element type. For instance, the following is legal:

int[] a = null;

Multidimensional arrays come in two varieties: rectangular and jagged. Rectangular arrays represent an n-dimensional block of memory, and jagged arrays are arrays of arrays.

We’ve already seen how to simplify array initialization expressions by omitting the new keyword and type declaration:

char[] vowels = new char[] {'a','e','i','o','u'};
char[] vowels =            {'a','e','i','o','u'};

Another approach is to omit the type name after the new keyword, and have the compiler infer the array type. This is a useful shortcut when passing arrays as arguments. For example, consider the following method:

void Foo (char[] data) { ... }

We can call this method with an array that we create on the fly, as follows:

Foo ( new char[] {'a','e','i','o','u'} );   // Longhand
Foo ( new[]      {'a','e','i','o','u'} );   // Shortcut

This shortcut is essential in creating arrays of anonymous types, as we’ll see later.