In some situations you cannot anticipate how large to make an array. For example, you might have a program that asks the user to enter the names of his or her friends . One user might want to enter four or five names, and another user might want to enter several dozen names . How can you, as the programmer, set the size of the array to accommodate the variation expected in the array size?
One approach is to simply estimate the maximum size that you might reasonably expect the array to have. For example, you might reason that no one is going to enter more than 100 names of friends into the program. This is an RDC approach to the problem, for several reasons.
First, Murphy's Law states that the minute you set the array size to 100, some user is going to try to enter 101 names. This would cause an error, and the program would die an ungraceful death right before the user's eyes. Not good.
Second, some users might have a very limited list of names to enter. If a user enters a list of five names and you've fixed the array size at 100, you've wasted the memory associated with the remaining 95 empty array elements. Although the program would run properly in this case, you should get a nagging feeling in the back of your mind, telling you that you're being wasteful .
The solution to this dilemma is to define a dynamic array. A dynamic array is an array that can have its element size set after the array is defined in a program. We can use our previous program to see how to use a dynamic array.
First, you remove the old Dim statement from the btnShowDay object's Click() event and replace it with the following line:
Dim DaysOfTheWeek() As String
Notice that the new line is almost the same, but you have removed the size (that is, the element count) of the array from the definition. How does Visual Basic .NET handle an array definition with no element size given? Actually, Visual Basic .NET does pretty much the same thing as when the element size is given: It creates an entry in the symbol table for the DaysOfTheWeek() string array, but instead of asking Windows for memory, Visual Basic .NET says to Windows: "Hey, Windows! I'm creating an entry for a string array named DaysOfTheWeek() , but I don't know exactly how big it is right now. I'll get back to you later." Visual Basic .NET then fills in the symbol table with what it does know about the array (that is, it's a string array and its name is DaysOfTheWeek ) and postpones the remaining details until later.
Now add the following line to the program's btnShowDay object's Click() event, immediately following the Dim statement you just entered:
This program statement is used to dimension the DaysOfTheWeek() array with elements through 6 . In other words, this statement redimensions the array that you defined earlier (hence the ReDim keyword). When Visual Basic .NET sees this program statement, it sends the following message to Windows: "Hey, Windows! Me again. Remember that string array we didn't know the size of? Well, the programmer finally got around to telling me about it, and I need enough memory for a string array with seven elements." The Windows memory manager then looks for enough memory for seven string elements and passes an lvalue back to Visual Basic .NET, to specify where the array will reside in memory. If there isn't enough free memory, Visual Basic .NET issues an error message.
The code in the btnShowDay object's Click() event should now look like this:
Dim DaysOfTheWeek() As String ReDim DaysOfTheWeek(6) DaysOfTheWeek(0) = "Monday" DaysOfTheWeek(1) = "Tuesday" DaysOfTheWeek(2) = "Wednesday" DaysOfTheWeek(3) = "Thursday" DaysOfTheWeek(4) = "Friday" DaysOfTheWeek(5) = "Saturday" DaysOfTheWeek(6) = "Sunday" txtDay.Text = DaysOfTheWeek(CInt(txtIndex.Text) - 1) Label2.Visible = True txtDay.Visible = True
Only the first two lines are different from the earlier version of the program, but the DaysOfTheWeek() array in this example uses a dynamic array.
A Subtle Feature of Runtime Use of ReDim
In the dynamic array example discussed here, you hard-code the ReDim statement to give seven elements in the DaysOfTheWeek() array. Obviously, if you know we want seven elements, as you do in this situation, you can just use the old Dim statement to define the DaysOfTheWeek() array. You really don't need to use a dynamic array.
Suppose, however, that you are working with a "list-your-friends" type of program. Further suppose that a text box, called txtSize , prompts the user to enter a number that tells the program how many names of friends he or she wants to enter. Now you could do something like this:
Dim MyFriends() As String ReDim MyFriends(CInt(txtSize.Text) - 1)
For example, if the user typed 12 in the txtSize text box, the code would be processed like this:
ReDim MyFriends(CInt(txtSize.Text) - 1) ReDim MyFriends(CInt(12) - 1) ReDim MyFriends(12 - 1) ReDim MyFriends(11)
This would define elements through 11 ”a total of 12 elements. You should be able to convince yourself that, no matter what number the user would type into the txtSize text box, the program would create enough elements in the MyFriends() array to hold the list of friends. Note that this method means you can get exactly the storage requirements you need, at runtime, for the MyFriends() array. There's no muss, no fuss, no wasted storage by trying to guess what the user might need.
The purpose, therefore, of the ReDim statement is to dynamically allocate array space when you do not know how much storage is needed at design time. Usually, you have a program determine how much storage is needed at runtime and then use the ReDim statement to set the array size. You will see additional examples of the proper use of the ReDim statement in later chapters.
Forcing an Error
Obviously, you can generate program errors if you do not use ReDim properly. Try changing the 6 for the element size in this ReDim :
statement to 5 , and then recompile the program. The program compiles without error. Now run the program. When the program gets to this line, it dies:
DaysOfTheWeek(6) = "Sunday"
The program dies because you are trying to index into an element of the array that does not exist.
Note that this error manifests itself while the program is running. Errors that go undetected before the program is run but show up while the program is running are called runtime errors. Visual Basic .NET does a good job of catching syntax errors before you even try to run the program. However, there are errors that Visual Basic .NET cannot detect until the program starts running. These runtime errors are usually evidence of semantic or logic errors in the program.
What would happen if you changed the 6 in the ReDim statement to 12 ? In that case, the program would run without error because you have defined enough elements for every element referenced in the program. The bad news is that you would waste some memory with elements you really don't need.
The Preserve Keyword
Suppose that you have written a program that asks the user to enter a list of friends. Further assume that you have done it correctly and used the ReDim statement to resize the array to the size actually needed by the user. For the sake of argument, assume that the user has five friends. Finally, assume that before the program ends, you write the list of five friends to a disk data file so you can retrieve it at a later time.
Now suppose that the user has met a new friend and wants to update the list stored in the disk data file. Through some programming magic that is covered in Chapter 23, "Disk Data Files," the program starts, discovers there are five names stored in the disk data file, and redimensions the name array to hold the five names. Uh-oh. The array can hold only five names, but you want to add a sixth to the list.
This shouldn't be a problem. All you need to do is use another ReDim but increase the ReDim size by 1 to include the new friend. Changing the ReDim from this:
provides another element for the user's new friend. However, like any other Dim statement, ReDim initializes the elements in the array. In the case of the String data type, Visual Basic .NET initializes each element in the array to be an empty string. This means that you will have lost the names of the original five friends. Not good.
Fortunately, the problem is easily solved with the Preserve keyword. Changing the ReDim statement to this:
ReDim Preserve MyFriends(5)
tells Visual Basic .NET to preserve whatever is currently stored in the array and add any new element(s) to the end of the array. Any new element(s) is initialized to an empty string, but the original five names remain intact.
You do not have to redimension an array one element at a time. That is, if the array currently holds 5 names and you think you might need 10 elements, a single ReDim for 10 elements does the job. This is true for ReDim statements with or without the Preserve keyword.
You can use the ReDim statement to decrease the size of an array. This requires two ReDim statements. The first ReDim statement is used to set the array's initial size, and the second ReDim is used to shrink its size. Although using the ReDim statement to shrink an array is a bit unusual, you might find a situation in which it makes sense to do so, perhaps if memory is at a premium.