Using Arrays in Microsoft® Visual C#® 2013

  • 11/15/2013

Populating and using an array

When you create an array instance, all the elements of the array are initialized to a default value depending on their type. For example, all numeric values default to 0, objects are initialized to null, DateTime values are set to the date and time “01/01/0001 00:00:00”, and strings are initialized to null. You can modify this behavior and initialize the elements of an array to specific values if you prefer. You achieve this by providing a comma-separated list of values between a pair of braces. For example, to initialize pins to an array of four int variables whose values are 9, 3, 7, and 2, you write this:

int[] pins = new int[4]{ 9, 3, 7, 2 };

The values between the braces do not have to be constants; they can be values calculated at run time, as shown in the following example, which populates the pins array with four random numbers:

Random r = new Random();
int[] pins = new int[4]{ r.Next() % 10, r.Next() % 10,
                         r.Next() % 10, r.Next() % 10 };

The number of values between the braces must exactly match the size of the array instance being created:

int[] pins = new int[3]{ 9, 3, 7, 2 }; // compile-time error
int[] pins = new int[4]{ 9, 3, 7 };    // compile-time error
int[] pins = new int[4]{ 9, 3, 7, 2 }; // OK

When you’re initializing an array variable in this way, you can actually omit the new expression and the size of the array. In this case, the compiler calculates the size from the number of initializers and generates code to create the array, such as in the following example:

int[] pins = { 9, 3, 7, 2 };

If you create an array of structures or objects, you can initialize each structure in the array by calling the structure or class constructor, as shown in this example:

Time[] schedule = { new Time(12,30), new Time(5,30) };

Creating an implicitly typed array

The element type when you declare an array must match the type of elements that you attempt to store in the array. For example, if you declare pins to be an array of int, as shown in the preceding examples, you cannot store a double, string, struct, or anything that is not an int in this array. If you specify a list of initializers when declaring an array, you can let the C# compiler infer the actual type of the elements in the array for you, like this:

var names = new[]{"John", "Diana", "James", "Francesca"};

In this example, the C# compiler determines that the names variable is an array of strings. It is worth pointing out a couple of syntactic quirks in this declaration. First, you omit the square brackets from the type; the names variable in this example is declared simply as var, not var[]. Second, you must specify the new operator and square brackets before the initializer list.

If you use this syntax, you must ensure that all the initializers have the same type. This next example causes the compile-time error “No best type found for implicitly typed array”:

var bad = new[]{"John", "Diana", 99, 100};

However, in some cases, the compiler will convert elements to a different type, if doing so makes sense. In the following code, the numbers array is an array of double because the constants 3.5 and 99.999 are both double, and the C# compiler can convert the integer values 1 and 2 to double values:

var numbers = new[]{1, 2, 3.5, 99.999};

Generally, it is best to avoid mixing types and hoping that the compiler will convert them for you.

Implicitly typed arrays are most useful when you are working with anonymous types, as described in Chapter 7. The following code creates an array of anonymous objects, each containing two fields specifying the name and age of the members of my family:

var names = new[] { new { Name = "John", Age = 47 },
                    new { Name = "Diana", Age = 46 },
                    new { Name = "James", Age = 20 },
                    new { Name = "Francesca", Age = 18 } };

The fields in the anonymous types must be the same for each element of the array.

Accessing an individual array element

To access an individual array element, you must provide an index indicating which element you require. Array indexes are zero-based; thus, the initial element of an array lives at index 0 and not index 1. An index value of 1 accesses the second element. For example, you can read the contents of element 2 of the pins array into an int variable by using the following code:

int myPin;
myPin = pins[2];

Similarly, you can change the contents of an array by assigning a value to an indexed element:

myPin = 1645;
pins[2] = myPin;

All array element access is bounds-checked. If you specify an index that is less than 0 or greater than or equal to the length of the array, the compiler throws an IndexOutOfRangeException exception, as in this example:

try
{
    int[] pins = { 9, 3, 7, 2 };
    Console.WriteLine(pins[4]); // error, the 4th and last element is at index 3
}
catch (IndexOutOfRangeException ex)
{
    ...
}

Iterating through an array

All arrays are actually instances of the System.Array class in the Microsoft .NET Framework, and this class defines a number of useful properties and methods. For example, you can query the Length property to discover how many elements an array contains and iterate through all the elements of an array by using a for statement. The following sample code writes the array element values of the pins array to the console:

int[] pins = { 9, 3, 7, 2 };
for (int index = 0; index < pins.Length; index++)
{
    int pin = pins[index];
    Console.WriteLine(pin);
}

It is common for new programmers to forget that arrays start at element 0 and that the last element is numbered Length – 1. C# provides the foreach statement with which you can iterate through the elements of an array without worrying about these issues. For example, here’s the preceding for statement rewritten as an equivalent foreach statement:

int[] pins = { 9, 3, 7, 2 };
foreach (int pin in pins)
{
    Console.WriteLine(pin);
}

The foreach statement declares an iteration variable (in this example, int pin) that automatically acquires the value of each element in the array. The type of this variable must match the type of the elements in the array. The foreach statement is the preferred way to iterate through an array; it expresses the intention of the code directly, and all of the for loop scaffolding drops away. However, in a few cases, you’ll find that you have to revert to a for statement:

  • A foreach statement always iterates through the entire array. If you want to iterate through only a known portion of an array (for example, the first half) or bypass certain elements (for example, every third element), it’s easier to use a for statement.

  • A foreach statement always iterates from index 0 through index Length – 1. If you want to iterate backward or in some other sequence, it’s easier to use a for statement.

  • If the body of the loop needs to know the index of the element rather than just the value of the element, you’ll have to use a for statement.

  • If you need to modify the elements of the array, you’ll have to use a for statement. This is because the iteration variable of the foreach statement is a read-only copy of each element of the array.

You can declare the iteration variable as a var and let the C# compiler work out the type of the variable from the type of the elements in the array. This is especially useful if you don’t actually know the type of the elements in the array, such as when the array contains anonymous objects. The following example demonstrates how you can iterate through the array of family members shown earlier:

var names = new[] { new { Name = "John", Age = 47 },
                    new { Name = "Diana", Age = 46 },
                    new { Name = "James", Age = 20 },
                    new { Name = "Francesca", Age = 18 } };
foreach (var familyMember in names)
{
    Console.WriteLine("Name: {0}, Age: {1}", familyMember.Name, familyMember.Age);
}

Passing arrays as parameters and return values for a method

You can define methods that take arrays as parameters or pass them back as return values.

The syntax for passing an array as a parameter is much the same as declaring an array. For example, the code sample that follows defines a method called ProcessData that takes an array of integers as a parameter. The body of the method iterates through the array and performs some unspecified processing on each element:

public void ProcessData(int[] data)
{
    foreach (int i in data)
    {
        ...
    }
}

It is important to remember that arrays are reference objects, so if you modify the contents of an array passed as a parameter inside a method such as ProcessData, the modification is visible through all references to the array, including the original argument passed as the parameter.

To return an array from a method, you specify the type of the array as the return type. In the method, you create and populate the array. The following example prompts the user for the size of an array, followed by the data for each element. The array created by the method is passed back as the return value:

public int[] ReadData()
{
    Console.WriteLine("How many elements?");
    string reply = Console.ReadLine();
    int numElements = int.Parse(reply);
    int[] data = new int[numElements];
    for (int i = 0; i < numElements; i++)
    {
        Console.WriteLine("Enter data for element {0}", i);
        reply = Console.ReadLine();
        int elementData = int.Parse(reply);
        data[i] = elementData;
    }
    return data;
}

You can call the ReadData method like this:

int[] data = ReadData();