One particular aspect of variable declaration that Chapter 1 didn't cover is array declaration. With array declaration, you can store multiple items of the same type using a single variable and still access them individually using the index when required. In C#, the array index starts at zero. Therefore, arrays in C# are zero based.
Declaring an Array
In C#, you declare arrays using square brackets. First, you specify the type of the items within the array, followed by open and closed square brackets; then you enter the name of the variable. Listing 2.28 declares a variable called languages to be an array of strings.
Listing 2.28. Declaring an Array
Obviously, the first part of the array identifies the data type of the elements within the array. The square brackets that are part of the declaration identify the rank, or the number of dimensions, for the array; in this case it is an array of rank one. These two pieces form the data type for the variable languages.
Listing 2.28 defines an array with a rank of one. Commas within the square brackets define additional dimensions. Listing 2.29, for example, defines a two-dimensional array of cells for a game of chess or tic-tac-toe.
Listing 2.29. Declaring a Two-Dimensional Array
In Listing 2.29, the array has a rank of two. The first dimension could correspond to cells going across and the second dimension represents cells going down. Additional dimensions are added, with additional commas, and the total rank is one more than the number of commas. Note that the number of items that occur for a particular dimension is not part of the variable declaration. This is specified when creating (instantiating) the array and allocating space for each element.
Instantiating and Assigning Arrays
Once an array is declared, you can immediately fill its values using a comma-delimited list of items enclosed within a pair of curly braces. Listing 2.30 declares an array of strings and then assigns the names of nine languages within curly braces.
Listing 2.30. Array Declaration with Assignment
The first item in the comma-delimited list becomes the first item in the array; the second item in the list becomes the second item in the array, and so on. The curly brackets are the notation for defining an array literal.
The assignment syntax shown in Listing 2.30 is available only if you declare and assign the value within one statement. To assign the value after declaration requires the use of the keyword new and the corresponding data type, as shown in Listing 2.31.
Listing 2.31. Array Assignment Following Declaration
C# also allows use of the new keyword as part of the declaration statement, so it allows the assignment and the declaration shown in Listing 2.32.
Listing 2.32. Array Assignment with new during Declaration
The use of the new keyword tells the runtime to allocate memory for the data type. It instructs the runtime to instantiate the data typein this case, an array.
Whenever you use the new keyword as part of an array assignment, you may also specify the size of the array within the square brackets. Listing 2.33 demonstrates this syntax.
Listing 2.33. Declaration and Assignment with the new Keyword
The array size in the initialization statement and the number of elements contained within the curly braces must match. Furthermore, it is possible to assign an array but not specify the initial values of the array, as demonstrated in Listing 2.34.
Listing 2.34. Assigning without Literal Values
Assigning an array but not initializing the initial values will still initialize each element. The runtime initializes elements to their default values, as follows.
As a result, it is not necessary to individually assign each element of an array before using it.
In C# 2.0, it is possible to use the default() operator to determine the default value of a data type. default() takes a data type as a parameter.default(int), for example, returns 0 and default(char) returns \0.
Because the array size is not included as part of the variable declaration, it is possible to specify the size at runtime. For example, Listing 2.35 creates an array based on the size specified in the Console.ReadLine() call.
Listing 2.35. Defining the Array Size at Runtime
C# initializes multidimensional arrays similarly. A comma separates the size of each rank. Listing 2.36 initializes a tic-tac-toe board with no moves.
Listing 2.36. Declaring a Two-Dimensional Array
Initializing a tic-tac-toe board with a specific position instead could be done as shown in Listing 2.37.
Listing 2.37. Initializing a Two-Dimensional Array of Integers
The initialization follows the pattern in which there is an array of three elements of type int, and each element has the same size; in this example, the size is three. Note that the dimension of each int element must be identical. The declaration shown in Listing 2.38, therefore, is not valid.
Listing 2.38. A Multidimensional Array with Inconsistent Size, Causing an Error
Representing tic-tac-toe does not require an integer in each position. One alternative is a separate virtual board for each player, with each board containing a bool that indicates which positions the players selected. Listing 2.39 corresponds to a three-dimensional board.
Listing 2.39. Initializing a Three-Dimensional Array
In this example, the board is initialized and the size of each rank is explicitly identified. In addition to identifying the size as part of the new expression, the literal values for the array are provided. The literal values of type bool[,,] are broken into two arrays of type bool[,], size 3x3. Each two-dimensional array is composed of three bool arrays, size 3.
As already mentioned, each dimension in a multidimensional array must be consistently sized. However, it is also possible to define a jagged array, which is an array of arrays. Jagged array syntax is slightly different from that of a multidimensional array, and furthermore, jagged arrays do not need to be consistently sized. Therefore, it is possible to initialize a jagged array as shown in Listing 2.40.
Listing 2.40. Initializing a Jagged Array
A jagged array doesn't use a comma to identify a new dimension. Rather, a jagged array defines an array of arrays. In Listing 2.40,  is placed after the data type int, thereby declaring an array of type int.
Notice that a jagged array requires an array instance for each internal array. In this example, you use new to instantiate the internal element of the jagged arrays. Leaving out the instantiation would cause a compile error.
Using an Array
You access a specific item in an array using the square bracket notation, known as the array accessor. To retrieve the first item from an array, you specify zero as the index. In Listing 2.41, the value of the fifth item (using the index 4 because the first item is index 0) in the languages variable is stored in the variable language.
Listing 2.41. Declaring and Accessing an Array
The square bracket notation is also used to store data into an array. Listing 2.42 switches the order of "C++" and "Java".
Listing 2.42. Swapping Data between Positions in an Array
For multidimensional arrays, an element is identified with an index for each dimension, as shown in Listing 2.43.
Listing 2.43. Initializing a Two-Dimensional Array of Integers
Jagged array element assignment is slightly different because it is consistent with the jagged array declaration. The first element is an array within the array of arrays. The second index specifies the item within the selected array element (see Listing 2.44).
Listing 2.44. Declaring a Jagged Array
You can obtain the length of an array, as shown in Listing 2.45.
Listing 2.45. Retrieving the Length of an Array
Arrays have a fixed length; they are bound such that the length cannot be changed without re-creating the array. Furthermore, overstepping the bounds (or length) of the array will cause the runtime to report an error. This can occur by accessing (either retrieving or assigning) the array with an index for which no element exists in the array. Such an error frequently occurs when you use the array length as an index into the array, as shown in Listing 2.46.
Listing 2.46. Accessing Outside the Bounds of an Array, Throwing an Exception
The Length member returns the number of items in the array, not the highest index. The Length member for the languages variable is 9, but the highest index for the languages variable is 8.
It is a good practice to use Length in place of the hardcoded array size. To use Length as an index, for example, it is necessary to subtract 1 to avoid an out-of-bounds error (see Listing 2.47).
Listing 2.47. Using Length- 1 in the Array Index
To avoid overstepping the bounds on an array use Length - 1, as demonstrated in Listing 2.47, in place of a hardcoded value accessing the last item in the array.
Length returns the total number of elements in an array. Therefore, if you had a multidimensional array such as boolcells[,,] of size 2·3·3, Length would return the total number of elements, 18.
More Array Methods
Arrays include additional methods for manipulating the elements within the array. These include Sort(), BinarySearch(), Reverse(), and Clear() (see Listing 2.48).
Listing 2.48. Additional Array Methods
The results of Listing 2.48 are shown in Output 2.19.
Access to these methods is on the System.Array class. For the most part, using these methods is self-explanatory, except for two noteworthy items.
Array Instance Methods
Like strings, arrays have instance members that are accessed not from the data type, but rather, directly from the variable. Length is an example of an instance member because access to Length is through the array variable, not the class. Other significant instance members are GetLength(), Rank, and Clone().
Retrieving the length of a particular dimension does not require the Length property. To retrieve the size of a particular rank, an array includes a GetLength() instance method. When calling this method, it is necessary to specify the rank whose length will be returned (see Listing 2.49).
Listing 2.49. Retrieving a Particular Dimension's Size
The results of Listing 2.49 appear in Output 2.20.
Listing 2.49 displays 2 because this is the number of elements in the first dimension.
It is also possible to retrieve the entire array's rank by accessing the array's Rank member. cells.Rank, for example, will return 3.
By default, assigning one array variable to another copies only the array reference, not the individual elements of the array. To make an entirely new copy of the array, use the array's Clone() method. The Clone() method will return a copy of the array; changing any of the members of this new array will not affect the members of the original array.
Strings as Arrays
Variables of type string are accessible like an array of characters. For example, to retrieve the fourth character of a string called palindrome you can call palindrome. Note, however, that because strings are immutable, it is not possible to assign particular characters within a string. C#, therefore, would not allow palindrome='a', where palindrome is declared as a string. Listing 2.50 uses the array accessor to determine whether an argument on the command line is an option, where an option is identified by a dash as the first character.
Listing 2.50. Looking for Command-Line Options
This snippet uses the if statement, which is covered in Chapter 3. In addition, it presents an interesting example because you use the array accessor to retrieve the first element in the array of strings, args. Following the first array accessor is a second one, this time to retrieve the first character of the string. The code, therefore, is equivalent to that shown in Listing 2.51.
Listing 2.51. Looking for Command-Line Options (Simplified)
Not only can string characters be accessed individually using the array accessor, it is also possible to retrieve the entire string as an array of characters using the string's ToCharArray() method. Using this method, you could reverse the string using the System.Array.Reverse() method, as demonstrated in Listing 2.52, which determines if a string is a palindrome.
Listing 2.52. Reversing a String
The results of Listing 2.52 appear in Output 2.21.
This example uses the new keyword; this time, it creates a new string from the reversed array of characters.
This section introduced the three different types of arrays: single-dimension, multidimensional, and jagged arrays. Several rules and idiosyncrasies govern array declaration and use. Table 2.7 points out some of the most common errors and helps solidify the rules. Readers should consider reviewing the code in the Common Mistake column first (without looking at the Error Description and Corrected Code columns) as a way of verifying their understanding of arrays and their syntax.