ITSE 1330 | C#

ACC

Arrays

Foreward

An array is a fixed-sized data structure for organizing and accessing elements of the same type. The Array class in C# is in the System namespace. Arrays are similar to classes like Queue and Stack in the System.Collection namespace. And, Arrays are considered collections since the class inherits the IList interface (more on interfaces later). Unlike in C and C++, arrays are not simply sections of contiguous memory but are objects and therefore have properties and methods. See here for a complete listing of properties and methods of the .NET Array class. If we only needed to work with a few variables at a time, like num1, num2, and num3, then arrays would be of minimal value. However, if we have seven, 70, 7000, or more elements, then working with arrays is extremely beneficial. For example, suppose we are recording population data for each of the 50 U.S. states. If we were limited to primitive types, then we would have 50 variables named something like popState1 through popState50. With an array, we can contain all 50 elements within one array named popState[].

Working with Arrays

R-click on the solution name "ITSE1330Solution-1" in the Solution Explorer and select Add | New project and name the new project Arrays. Again, we don't have to use the same solution to contain multiple projects but are doing so for concept coverage. Code Program.cs like shown. Since the solution has more than one project now, when we are ready to run a project we need to identify the startup project. By the default, that is the first project (MakingDecisions) added to the solution. The startup project can easily be changed by R-clicking on the project name Arrays in Solution Explorer | Set as StartUp Project. However, you might prefer R-clicking the solution name in Solution Explorer | Properties and setting the startup to be the currently selected project. This is convenient when moving between a number of projects. Keep in mind that this approach requires a little processing overhead each time the focus is moved to another project.

one-Dimensional Arrays

The one-dimensional array is the simplest and most common type. It provides convenient ways to declare, define, and initialize multiple data items. Note: the terms declare and define are quite similar and are often used interchangeably. However, for the purposes of this tutorial, I will employ classical definitions. That is, declare means to name a variable and define means to allocate memory. Recall that for primitive types, the declaration and definition occurs at the same time. This is usually the case for arrays. With arrays, the declaration and definition can occur separately but the size of the array must be supplied before the array can be used. After an array is declared, before it can be used it must be defined either explicitly using the keyword "new" with a size declarator or implicitly via an initialization list.

On line 14 a one-dimensional array capable of holding three integers is created named oneDimArray1. The square bracket symbols [] are the array operators. The "new" keyword is used to create an object of the specified type. In the case of line 14, we are requesting that an object of type array be created with memory for three integers. We can separate the operations occurring on line 14. Lines 37 and 38 separate the declaration and definition operations. Line 37 names the array and line 38 allocates three integers for the size.

Lines 16-18 show the array elements (each array member) being assigned values. Arrays are "zero-based" which means that the first member is accessed with a "0" index, the second member is accessed with an index of "1", etc. Indexes are also known as subscripts. In the image below, three locations in memory are created for the array named oneDimArray1. The sample address numbers are presented as hexadecimal (16-base) numbers. Notice how the address values are incremented by 4 (from 1 to 5 to 9). Recall that 4 is the byte size of an integer. After lines 16-18 the values stored in those addresses are 1, 2, and 3. Also note the highlighted index values of 0, 1, and 2 which are used to access the memory locations.

Lines 27 and 34 provide alternative ways of creating and initializing an array. On both lines 27 and 34 an array of three integers is created and initialized with the values 1, 2, and 3. The size of oneDimArray3 is "implicitly" obtained from the number of arguments in the initialization list. When an array is implicitly sized, a size declarator is not required but there is a benefit to including it.

The highlighted "2" in the code segment below is called the size declarator. While not required if an initialization list is supplied, the "2" does provide an extra check. It ensures that the size declarator and the number of arguments in the initialization list agree. For example, the sizeCheckerArray has an expected length of two but the initialization list contains three elements. A compile time (first-level compilation) error is generated if the size declarator does not agree with the number of arguments in the initialization list.

Line 34 not only declares and defines the array it also initializes the array contents. So, lines 27 and 34 each do the work of lines 14-18. Line 34 is the most compact version. To obtain the extra check and to make the code more readable, a size declarator can be supplied along with an initialization list. That would be like line 27 but including a size declarator.

Multi-Dimensional Arrays

C# arrays can also be multi-dimensional. Two-dimensional (two-dim) arrays are the most common multi-dimensional arrays. It is natural to view a two-dim array as a table as shown. Notice the indexes that are used to access each element. There are two rows (Row 0 and Row 1) and three columns ( Col 0, Col 1, Col 2).

The elements in the table correspond to those shown on lines 43-48. On line 41 a two-dim array of doubles is created with two rows and three columns. Lines 43-48 assign the values of the array on the right to the indexes on the left. Lines 59 and 60 accomplish the same thing as lines 41-48. Lines 59 and 60 could be combined into one line but are often written across multiple lines to provide a visual representation of the data. Notice how the initialization list emulates the data values in the table.

Jagged Arrays

The last form of array we will consider is a jagged array which is called that for its uneven construction. The table below depicts the jagged array that is first created on line 63. That line of code only creates two arrays within the jagged array but does not size them. The two arrays are sized and populated with data on lines 66 and 67. The first of the two arrays contains three elements and the second array contains five elements. This uneven characteristic is why the array is referred to as "jagged". If both arrays within the jagged array were the same size then they could be represented as a multi-dimensional array.

Line 63 creates a jagged array. Note that unlike the multi-dimensional array with a comma in the array operators [], the jagged array has two sets of array operators side-by-side. On line 63 a jagged array is created which can be read as, "Create two arrays of integers within the jagged array and the size of both to be specified later." Line 66 and 67 specify the sizes of each array and data values.

Unlike C and C++, C# includes a feature known as array bounds checking. That is, if the program attempts to access an element that is out-of-range of the array, an exception (runtime error) is produced. To demonstrate this particular type of error, the "2" index on line 72 was changed to a "3". The program compiled but produced a runtime IndexOutOfRangeException when it was executed. The code attempted to access Element 3 of Array 0 which does not exist per the table above.

We will learn how to handle exceptions with try-catch-finally blocks in an upcoming chapter. However, it should be noted that errors like IndexOutOfRangeExceptions are known as "unchecked errors" and should not be handled with a try-catch-finally block. Rather, unchecked errors should be prevented by checks in the code. For instance, in the code segment below, the value of arrayIndex is checked to ensure it is within the appropriate range before being used subsequently in the array.

Array Methods

The Array class has a variety of properties and methods (here). Since each array we create inherits from the Array class, our arrays have multiple properties and methods available. For example, on line 83 we use the Length property to return the length of the mixedArray. And, on line 86 we use the Array.Sort() method to sort the contents of the mixedArray. The original content is randomly arranged but after calling Array.Sort(), mixedArray is sorted.

Some of the other useful methods of the Array class are: BinarySearch(), Clone(), Copy(), IndexOf(), Reverse(), and ToString().

Output of Program.cs is shown.

The array is a common and very useful data structure in computing. We use arrays a number of times in upcoming chapters. Students should practice working with arrays to obtain a substantial level of familiarity.

What's Next?

Recall that the three primary constructs in all of programming are: sequence, decision, iteration. In the next chapter, we will begin using iteration in our code.