Previous section   Next section

9.1 Arrays

An array is an indexed collection of objects, all of the same type. In this chapter, you will learn to work with three types of arrays: one-dimensional arrays, multidimensional rectangular arrays, and multidimensional jagged arrays.

To picture a one-dimensional array, imagine a series of mailboxes, all lined up one after the other. Each mailbox can hold exactly one object (one letter, one box, etc.). It turns out that all the mailboxes must hold the same kind of object; you declare the type of object the mailboxes will hold when you declare the array.

A multidimensional array allows you to create rows of mailboxes, one above the other. If all the rows are the same length, you have a rectangular array. If each row of mailboxes is a different length, you have a jagged array.

You can think of a multidimensional array as being like a grid of rows and columns in which each slot (mailbox) contains information. For example, each column might contain information pertinent to an employee. Each row would contain all the information for a single employee.

Most often you will deal with one-dimensional arrays, and if you do create multi-dimension arrays they will be two-dimensional—but larger multidimensional arrays (3D, 4D, etc.) are also possible.

A jagged array is a type of two-dimensional array in which each row can have a different number of columns. A jagged array is less of a grid, and more of an array of arrays—that is, an array in which the elements in one array are other arrays. This allows you to group a few arrays of varying sizes into a single array. For example, you might have an array of ten buttons, and a second array of five listboxes, and a third array of seven checkboxes. You can group all three into a jagged array of controls.

9.1.1 Declaring Arrays

In order to declare an array, you must use a constructor, but you are free to use it in a variety of ways. For example, you can use either an implicit or an explicit constructor, as in the following:

Dim myIntArray( ) As Integer  ' implicit constructor
Dim myIntArray As Integer = New Integer( ) {}' explicit constructor

Which type of constructor you use is a matter of personal preference.

Alternatively, you can specify the initial size of the array (that is, how many elements it will hold):

Dim myIntArray(6) As Integer  ' implicit constructor 6 members
Dim myIntArray As Integer = new Integer(6) ' explicit, 6 members

In all of these examples, the parentheses tell the VB.NET compiler that you are declaring an array, and the type specifies the type of the elements it will contain. In all of the arrays we have declared so far, myIntArray is an array of Integers. It is important to distinguish between the array itself (which is a collection of elements) and the component elements within the array. myIntArray is the array; its elements are the six integers it holds.

While VB.NET arrays are reference types, created on the heap, the elements of an array are allocated based on their type. Thus, myIntArray is a reference type allocated on the heap, and the integer elements in myIntArray are value types, allocated on the stack. (While you can box a value type so that it can be treated like a reference type, as explained in Chapter 6, it is not necessary or desirable to box the integers in an array.) By contrast, an array that contains reference types, such as Employee or Button, will contain nothing but references to the elements, which are themselves created on the heap.

9.1.2 The Size of the Array

Arrays are zero-based,[1] which means that the index of the first element is always zero, as in myArray(0). The second element is element 1. Index 3 indicates the element that is offset from the beginning of the array by 3 elements—that is, the fourth element in the array. You access element 3 by writing:

[1] It is possible to create arrays that are not zero-based, but only with multidimensional arrays, and it is rarely a good idea. To do so you must use the CreateInstance( ) method of the Array class, and the resulting arrays are not compliant with the Common Language Specification.

myArray(3) ' return the 4th element (at offset 3)

You declare the initial size of the array (that is, how many elements it will hold) by specifying the upper bounds of the array. Both of the following declarations specify an array with seven elements; the first uses an implicit constructor for this purpose, the second an explicit constructor:

Dim myIntArray(6) As Integer  ' implicit constructor, 7 members
Dim myIntArray As Integer = New Integer(6) {}' explicit, 7 members

Note that these arrays have seven elements (not six) because with an upper bound of 6, the element indices are 0,1,2,3,4,5,6 for a total of 7 elements.

9.1.3 The ReDim Keyword

You can change the size of an array at any time using the ReDim keyword. Changing the size is commonly referred to as redimensioning the array.[2]

[2] "Redimensioning" is a terribly misleading term. It suggests you are changing the dimensions of the array (which is described later in this chapter); in fact you are changing the array's size. Redimensioning should more properly be called resizing the array, but the terminology was established early in the history of Visual Basic, and it's too late now; we're stuck with the term redimensioning.

There are two ways to redimension an array. If you use the Preserve keyword, the data in the array is preserved; otherwise, all the data in the array is lost when it is resized using ReDim.

You can resize an array named myArray from its current size to 50 by writing:

ReDim myArray(50)

You can make the same change to myArray, but preserve the existing data in the array by writing:

ReDim preserve myArray(50)

At times, you will not want to resize an array to a particular size but rather to expand the array by a particular increment. For example, if you are adding items to an array, and you find you're about to run out of room, you might add 50 to the current size of the array. You can use the UBound property of the array which returns the current upper bound of the array. The following line resizes myArray to 50 elements larger than its current size:

ReDim Preserve myArray(UBound(myArray) + 50)

9.1.4 Understanding Default Values

When you create an array of value types, each element initially contains the default value for the type stored in the array. (See Table 5-2.) The following declaration creates an array (myIntArray) of six integers, each of whose value is initialized to 0, the default value for Integer types:

'six Integers with default values 
Dim myIntArray As Integer = New Integer(6) {}

With an array of reference types, the elements are not initialized to their default values. Instead, they are initialized to Nothing. If you attempt to access any of the elements in an array of reference types before you have specifically initialized them, you will generate an exception (exceptions are covered in Chapter 11).

Assume you have created a Button class. You declare an array of Button objects (thus reference types) with the following statement:

Dim myButtonArray As Button( )

and you instantiate the actual array, to hold four Buttons, like this:

myButtonArray = New Button(3){}

Note that you can combine the two steps and write:

Dim myButtonArray As Button( ) = New Button(3) {}

In either case, unlike with the earlier integer example, this statement does not create an array with references to four Button objects. Since Button objects are reference types, this creates the array myButtonArray with four Nothing, or null, references. To use this array, you must first construct and assign a Button object for each reference in the array. This is called populating the array. You can construct the objects in a loop that adds them one by one to the array. Example 9-1 illustrates creating an array of value types (integers) and of reference types (Employee objects).

Example 9-1. Creating an array
Option Strict On
Imports System

'a simple class to store in the array
Public Class Employee
    Private empID As Integer
    'constructor
    Public Sub New(ByVal empID As Integer)
        Me.empID = empID
    End Sub
End Class

Class Tester
    Public Sub Run( )
        Dim intArray As Integer( )
        Dim empArray As Employee( )
        intArray = New Integer(5) {}
        empArray = New Employee(3) {}

        'populate the array
        Dim i As Integer

        'for indices 0 through 3
        For i = 0 To empArray.Length - 1
            empArray(i) = New Employee(i + 5)
            i = i + 1
        Next
    End Sub

    Shared Sub Main( )
        Dim t As New Tester( )
        t.Run( )
    End Sub
End Class

Example 9-1 begins by creating a simple Employee class to add to the array. When Run( ) begins, two arrays are declared, one of type Integer, the other of type Employee:

Dim intArray As Integer( )
Dim empArray As Employee( )

The Integer array is populated with Integers set to zero. The Employee array is initialized with Nothing references.

empArray does not have Employee objects whose member fields are set to Nothing; it does not have Employee objects at all. What is in the cubby holes of the array is just nulls. Nothing. Nada. When you create the Employee objects, you can then store them in the array.

You must populate the Employee array before you can refer to its elements:

For i = 0 To empArray.Length - 1
    empArray(i) = New Employee(i + 5)
    i = i + 1
Next

The exercise has no output. You've added the elements to the array, but how do you use them? How do you refer to them?

9.1.5 Accessing Array Elements

You access a particular element within an array using parentheses and a numeric value knows as an index, or offset. You access element 3 by writing:

myArray(3) ' return the 4th element (at offset 3)

Because arrays are objects, they have properties. One of the more useful properties of the Array class is Length, which tells you how many objects are in an array. Array objects can be indexed from 0 to Length-1. That is, if there are five elements in an array, their indices are 0,1,2,3,4.

In Example 9-2, you create an array of Employees and an array of integers, populate the Employee array, and then you print the values in each array.

Example 9-2. Accessing two simple arrays
Option Strict On
Imports System

Namespace ArrayDemo

    'a simple class to store in the array
    Public Class Employee

        Private empID As Integer

        'constructor
        Public Sub New(ByVal empID As Integer)
            Me.empID = empID
        End Sub 'New

        Public Overrides Function ToString( ) As String
            Return empID.ToString( )
        End Function 'ToString
    End Class 'Employee

    Class Tester

        Public Sub Run( )
            Dim intArray( ) As Integer
            Dim empArray( ) As Employee
            
            intArray = New Integer(5) {}
            empArray = New Employee(3) {}

            'populate the array
            Dim i As Integer
            For i = 0 To empArray.Length - 1
                empArray(i) = New Employee(i + 5)
            Next i

            Console.WriteLine("The Integer array...")
            For i = 0 To intArray.Length - 1
                Console.WriteLine(intArray(i).ToString( ))
            Next i

            Console.WriteLine(ControlChars.Lf + "The Employee array...")
            For i = 0 To empArray.Length - 1
                Console.WriteLine(empArray(i).ToString( ))
            Next i
        End Sub 'Run

        Shared Sub Main( )
            Dim t As New Tester( )
            t.Run( )
        End Sub 'Main
    End Class 'Tester

End Namespace 'ArrayDemo

Output:
The Integer array...
0
0
0
0
0

The Employee array...
5
6
7

Example 9-2 starts with the definition of an Employee class that implements a constructor that takes a single integer parameter. The ToString( ) method inherited from Object is overridden to print the value of the Employee object's employee ID.

The Run( ) method declares and then instantiates a pair of arrays. The Integer array is automatically filled with Integers whose value is set to zero. The Employee array contents must be constructed by hand (or will contain values set to Nothing). To populate the array by hand, you construct each Employee object in turn, adding them to the Array as they are created:

Dim i As Integer
For i = 0 To empArray.Length - 1
    empArray(i) = New Employee(i + 5)
Next i

In this For loop, each Employee is created with a value equal to five more than its index in the array. These are arbitrary values used here to illustrate how to add Employee objects to the array.

Finally, the contents of the arrays are printed to ensure that they are filled as intended. The five Integers print their value first, followed by the three Employee objects.

If you comment out the code in which the Employee objects are created, you'll generate an exception when you try to display the contents of the Employee array. This demonstrates that arrays of reference types are initialized with Nothing references.

Unhandled Exception: System.NullReferenceException: Object
reference not set to an instance of an object. at 
InterfaceDemo.ArrayDemo.Tester.Run( ) in C:\...\InterfaceDemo\
Module1.vb:line 40   at InterfaceDemo.ArrayDemo.Tester.Main( ) 
in C:\...InterfaceDemo\Module1.vb:line 47

9.1.6 The For Each Statement

The For Each looping statement allows you to iterate through all the items in an array (or other collection), examining each item in turn. The syntax for the For Each statement is:

For Each identifier In collection
   statement
Next

The For Each statement creates a new object that will hold a reference to each of the objects in the collection, in turn, as you loop through the collection. For example, you might write:

Dim intValue As Integer
For Each intValue In intArray

Each time through the loop, the next member of intArray will be assigned to the integer variable intValue. You can then use that object to display the value, as in:

Console.WriteLine(intValue.ToString( ))

Similarly, you might iterate through the Employee array:

Dim e As Employee
For Each e In empArray
    Console.WriteLine(e)
Next

In the case shown here, e is an object of type Employee. For each turn through the loop, e will refer to the next Employee in the array.

Example 9-3 rewrites the Run( ) method of Example 9-2 to use a For Each loop, but is otherwise unchanged.

Example 9-3. For Each loop
Option Strict On
Imports System

Public Sub Run( )
    Dim intArray( ) As Integer
    Dim empArray( ) As Employee

    intArray = New Integer(5) {}
    empArray = New Employee(3) {}

    'populate the array
    Dim i As Integer
    For i = 0 To empArray.Length - 1
        empArray(i) = New Employee(i + 5)
    Next i

    Console.WriteLine("The Integer array...")

    Dim intValue As Integer
    For Each intValue In intArray
        Console.WriteLine(intValue.ToString( ))
    Next
    Console.WriteLine("The Employee array...")
    Dim e As Employee
    For Each e In empArray
        Console.WriteLine(e)
    Next

End Sub 'Run

Output:
The Integer array...
0
0
0
0
0
The Employee array...
5
6
7

The output for Example 9-3 is identical to Example 9-2. However, rather than creating a For statement that measures the size of the array and uses a temporary counting variable as an index into the array:

For i = 0 To empArray.Length - 1
    Console.WriteLine(empArray(i).ToString( ))
Next i

you now iterate over the array with the For Each loop which automatically extracts the next item from within the array and assigns it to a temporary object you've created in the head of the statement. In the following case, the temporary object is of type Employee (it is a reference to an Employee object) and is named e:

Dim e As Employee
For Each e In empArray
    Console.WriteLine(e)
Next

Since the object extracted from the array is of the appropriate type (i.e., e is a reference to an Employee), you can call any public method of Employee.

It is generally a good idea for the length of the variable name to be proportional to its lifetime. Because i and e in the previous examples exist only momentarily, their names can be quite short. A variable that will last the life of a method deserves a larger name (e.g., temperature or weight), and a variable that will last the lifetime of an object might deserve an even longer name (estimatedGrossWeight).

9.1.7 Initializing Array Elements

Rather than assigning elements to the array as we have done so far, it is possible to initialize the contents of an array at the time it is instantiated. You do so by providing a list of values delimited by curly braces ({}). VB.NET provides two different syntaxes to accomplish the same task:

Dim myIntArray1( ) As Integer = { 2, 4, 5, 8, 10}
Dim myIntArray2( ) As Integer  = New Integer(4) { 2, 4, 6, 8, 10 }

There is no practical difference between these two statements, and most programmers will use the shorter syntax because we are, by nature, lazy. We are so lazy, we'll work all day to save a few minutes doing a task—which isn't so crazy if we're going to do that task hundreds of times! Example 9-4 again rewrites the Run( ) method of Example 9-4, this time demonstrating initialization of both arrays.

Example 9-4. Initializing array elements
Option Strict On
Imports System

Public Sub Run( )
    Dim intArray As Integer( ) = {2, 4, 6, 8, 10}
    Dim empArray As Employee( ) = _
      {New Employee(5), New Employee(7), New Employee(9)}

    Console.WriteLine("The Integer array...")
    Dim theInt As Integer
    For Each theInt In intArray
        Console.WriteLine(theInt.ToString( ))
    Next theInt

    Console.WriteLine("The Employee array...")
    Dim e As Employee
    For Each e In empArray
        Console.WriteLine(e.ToString( ))
    Next e
End Sub 'Run

Output:
The Integer array...
2
4
6
8
10

The Employee array...
5
7
9

9.1.8 The ParamArray Keyword

What do you do if you need to pass parameters to a method but you don't know how many parameters you'll want to pass? It is possible that the decision on how many parameters you'll pass in won't be made until runtime.

VB.NET provides the ParamArray keyword to allow you to pass in a variable number of parameters. As far as the client (the calling method) is concerned, you pass in a variable number of parameters. As far as the implementing method is concerned, it has been passed an array, and so it can just iterate through the array to find each parameter!

For example, you can create a method called DisplayVals( ) that takes integers as parameters and displays them to the console:

Public Sub DisplayVals(ByVal ParamArray intVals( ) As Integer)
    Dim i As Integer
    For Each i In intVals
        Console.WriteLine("DisplayVals {0}", i)
    Next i
End Sub 'DisplayVals

The ParamArray keyword indicates that you can pass in any number of integers, and the method will treat them as if you had passed in an array of integers. Thus you can call this method from Run( ) with:

DisplayVals(5, 6, 7, 8)

And the DisplayVals( ) method will treat this exactly as if you had written:

Dim explicitArray( ) As Integer = {5, 6, 7, 8}
DisplayVals(explicitArray)

And in fact, you are free to create such an array and send it in as the parameter, as demonstrated in Example 9-5.

Example 9-5. The ParamArray keyword
Option Strict On
Imports System

Namespace ArrayDemo

    Class Tester

        Public Sub Run( )
            Dim a As Integer = 5
            Dim b As Integer = 6
            Dim c As Integer = 7
            Console.WriteLine("Calling with three Integers")
            DisplayVals(a, b, c)

            Console.WriteLine("Calling with four Integers")
            DisplayVals(5, 6, 7, 8)

            Console.WriteLine("Calling with an array of four Integers")
            Dim explicitArray( ) As Integer = {5, 6, 7, 8}
            DisplayVals(explicitArray)
End Sub 'Run

        'takes a variable number of Integers
        Public Sub DisplayVals(ByVal ParamArray intVals( ) As Integer)
            Dim i As Integer
            For Each i In intVals
                Console.WriteLine("DisplayVals {0}", i)
            Next i
        End Sub 'DisplayVals

        Shared Sub Main( )
            Dim t As New Tester( )
            t.Run( )
        End Sub 'Main
    End Class 'Tester
End Namespace 'ArrayDemo

Output:
Calling with three Integers
DisplayVals 5
DisplayVals 6
DisplayVals 7

Calling with four Integers
DisplayVals 5
DisplayVals 6
DisplayVals 7
DisplayVals 8

Calling with an array of four Integers
DisplayVals 5
DisplayVals 6
DisplayVals 7
DisplayVals 8

In Example 9-5, the first time you call DisplayVals( ) you pass in three integer variables:

Dim a As Integer = 5
Dim b As Integer = 6
Dim c As Integer = 7
DisplayVals(a, b, c)

The second time you call DisplayVals( ) you use four literal constants:

DisplayVals(5, 6, 7, 8)

In both cases, DisplayVals( ) treats the parameters as if they were declared in an array. In the final invocation, you explicitly create an array and pass that as the parameter to the method:

Dim explicitArray( ) As Integer = {5, 6, 7, 8}
DisplayVals(explicitArray)

  Previous section   Next section
Top