pemrograman .net


Common Programming Error 5.5
When using the optional Case Else statement in a Select Case structure, failure to
place the Case Else as the last Case is a syntax error. 5.5
Testing and Debugging Tip 5.3
Provide a Case Else in Select Case structures. Cases not handled in a Select Case
structure are ignored unless a Case Else is provided. The inclusion of a Case Else statement
facilitates the processing of exceptional conditions. In some situations, no Case Else
processing is needed. 5.3
Case statements also can use relational operators to determine whether the controlling
expression satisfies a condition. For example
Case Is < 0
uses keyword Is along with the relational operator, <, to test for values less than 0.
Figure 5.11 flowcharts the Select Case structure.
Fig. 5.11 Select Case multiple-selection structure flowchart.
Case a Case a action(s)
.
.
.
Case b action(s)
Case z
Case Else action(s)
Case b
Case z action(s)
true
true
true
false
false
false
Chapter 5 Control Structures: Part 2 159
Again, note that (besides small circles and flowlines) the flowchart contains only rectangle
and diamond symbols. Imagine, as we did in the previous chapter, that the programmer
has access to a deep bin of empty structures. This time, the bin contains Select
Case structures, and the programmer can stack and nest as many as are necessary with
other control structures to form a structured implementation of an algorithm’s flow of control.
The programmer fills the rectangles and diamonds with actions and decisions appropriate
to the algorithm. Although nested control structures are common, it is rare to find
nested Select Case structures in a program.
In Chapter 10, Object-Oriented Programming: Part 2, we present a more elegant
method of implementing multiple selection logic. We use a technique called polymorphism
to create programs that are often clearer, more manageable, and easier to extend than programs
that use Select Case logic.
5.6 Do/Loop While Repetition Structure
The Do/Loop While repetition structure is similar to the While structure and Do
While/Loop structure. In the While and Do While/Loop structures, the loop-continuation
condition is tested at the beginning of the loop, before the body of the loop is performed.
The Do/Loop While structure tests the loop-continuation condition after the loop
body is performed. Therefore, in a Do/Loop While structure, the loop body is always executed
at least once. When a Do/Loop While structure terminates, execution continues
with the statement after the Loop While clause. The program in Fig. 5.12 uses a Do/Loop
While structure to output the values 1–5.
Testing and Debugging Tip 5.4
Infinite loops occur when the loop-continuation condition in a While, Do While/Loop or
Do/Loop While structure never becomes false. 5.4
1 ' Fig. 5.12: DoWhile.vb
2 ' Demonstrating the Do/Loop While repetition structure.
34
Module modDoWhile
Pemrograman Web/TI/ AK045216/2 sks
Contoh script ASP- 1
•VBScript adalah bahasa scripting standar untuk membuat halaman ASP.
Pada contoh-contoh script berikut digunakan VBScript:
•Contoh 1 :
– Langkah pembuatan :
• Masukkan text ‘Hello World’ pada variabel FirstVar
• Buat tag awal HTML
• Gunakan untuk menampilkan isi variabel FirstVar
• Akhiri tag HTML
– Script lengkap :

• Example 1





56

Sub Main()
7 Dim counter As Integer = 1
89
‘ print values 1 to 5
10 Do
11 Console.Write(counter & ” “)
12 counter += 1
13 Loop While counter 5
14
15 End Sub ‘ Main
16
17 End Module ‘ modLoopUntil
1 2 3 4 5
Fig. 5.14 Do/Loop Until repetition structure (part 2 of 2).
Fig. 5.15 Do/Loop Until repetition structure flowchart.
condition
action(s)
true
false
162 Control Structures: Part 2 Chapter 5
Testing and Debugging Tip 5.6
In a counter-controlled loop, make sure the control variable is incremented (or decremented)
appropriately in the body of the loop. 5.6
Testing and Debugging Tip 5.7
In a sentinel-controlled loop, make sure the sentinel value is eventually input. 5.7
Testing and Debugging Tip 5.8
Including a final value in the condition of a repetition structure (and choosing the appropriate
relational operator) can reduce the risk of off-by-one errors. For example, in a While
loop used to print the values 1–10, the loop-continuation condition should be counter <=
10, rather than counter < 10 (which is an off-by-one error) or counter 10
25
26 ‘ skip remaining code in loop only if counter = 5
27 If counter = 5 Then
28 Exit Do
29 End If
30
31 counter += 1
32 Loop
33
34 output &= “counter = ” & counter & _
35 ” after exiting Do Until/Loop structure” & vbCrLf
36
37 While counter <= 10
38
39 ' skip remaining code in loop only if counter = 7
40 If counter = 7 Then
41 Exit While
42 End If
43
44 counter += 1
45 End While
46
47 output &= "counter = " & counter & _
48 " after exiting While structure"
49
50 MessageBox.Show(output, "Exit Test", _
51 MessageBoxButtons.OK, MessageBoxIcon.Information)
52 End Sub ' Main
53
54 End Module ' modExitTest
Fig. 5.16 Exit keyword in repetition structures (part 2 of 2).
164 Control Structures: Part 2 Chapter 5
body of the If/Then structure (lines 27–29) does not execute, and counter is incremented
(line 31). However, when counter is 5, the Exit Do statement (line 28) executes,
terminating the loop. The assignment statement (lines 34–35) appends the value of
counter to output. Note that the program does not increment counter (line 31) after
the Exit Do statement executes.
The While structure (lines 37–45) behaves similarly to the Do While/Loop. In this
case, the value of counter is 5 when the loop begins executing. When counter is 7,
the Exit While statement (line 41) executes, terminating execution of the While structure.
Lines 47–48 append the final value of counter to String variable output, which
is displayed in a message dialog (lines 50–51).
Software Engineering Observation 5.1
Some programmers feel that Exit Do, Exit While and Exit For violate the principles
of structured programming. The effects of these statements can be achieved by structured
programming techniques that we discuss soon. 5.1
Software Engineering Observation 5.2
Debates abound regarding the relative importance of quality software engineering and program
performance. Often, one of these goals is accomplished at the expense of the other. For
all but the most performance-intensive situations, apply the following guidelines: First, make
your code simple and correct; then make it fast and small, but only if necessary. 5.2
5.9 Logical Operators
So far, we have studied only simple conditions, such as count 1000
and number sentinelValue. Each selection and repetition structure evaluated
only one condition with one of the operators >, =, <=, = and . To make a decision
that relied on the evaluation of multiple conditions, we performed these tests in separate
statements or in nested If/Then or If/Then/Else structures.
To handle multiple conditions more efficiently, Visual Basic provides logical operators
that can be used to form complex conditions by combining simple ones. The logical
operators are AndAlso, And, OrElse, Or, Xor and Not. We consider examples that use
each of these operators.
Suppose we wish to ensure that two conditions are both true in a program before a certain
path of execution is chosen. In such case, we can use the logical AndAlso operator as follows:
If gender = “F” AndAlso age >= 65 Then
seniorFemales += 1
End If
This If/Then statement contains two simple conditions. The condition gender = “F”
determines whether a person is female and the condition age >= 65 determines whether a
person is a senior citizen. The two simple conditions are evaluated first, because the precedences
of = and >= are both higher than the precedence of AndAlso. The If/Then statement
then considers the combined condition
gender = “F” AndAlso age >= 65
Chapter 5 Control Structures: Part 2 165
This condition evaluates to true if and only if both of the simple conditions are true. When this
combined condition is true, the count of seniorFemales is incremented by 1. However,
if either or both of the simple conditions are false, the program skips the increment and proceeds
to the statement following the If/Then structure. The readability of the preceding
combined condition can be improved by adding redundant (i.e., unnecessary) parentheses:
(gender = “F”) AndAlso (age >= 65)
Figure 5.17 illustrates the effect of using the AndAlso operator with two expressions.
The table lists all four possible combinations of true and false values for expression1 and
expression2. Such tables often are called truth tables. Visual Basic evaluates to true or false
expressions that include relational operators, equality operators and logical operators.
Now let us consider the OrElse operator. Suppose we wish to ensure that either or
both of two conditions are true before we choose a certain path of execution. We use the
OrElse operator in the following program segment:
If (semesterAverage >= 90 OrElse finalExam >= 90) Then
Console.WriteLine(“Student grade is A”)
End If
This statement also contains two simple conditions. The condition semesterAverage
>= 90 is evaluated to determine whether the student deserves an “A” in the course because
of an outstanding performance throughout the semester. The condition finalExam >=
90 is evaluated to determine if the student deserves an “A” in the course because of an outstanding
performance on the final exam. The If/Then statement then considers the combined
condition
(semesterAverage >= 90 OrElse finalExam >= 90)
and awards the student an “A” if either or both of the conditions are true. Note that the text
“Student grade is A” is always printed, unless both of the conditions are false.
Figure 5.18 provides a truth table for the OrElse operator.
The AndAlso operator has a higher precedence than the OrElse operator. An
expression containing AndAlso or OrElse operators is evaluated only until truth or falsity
is known. For example, evaluation of the expression
(gender = “F” AndAlso age >= 65)
expression1 expression2 expression1 AndAlso expression2
False False False
False True False
True False False
True True True
Fig. 5.17 Truth table for the AndAlso operator.
166 Control Structures: Part 2 Chapter 5
stops immediately if gender is not equal to “F” (i.e., the entire expression is false); the
evaluation of the second expression is irrelevant because the first condition is false. Evaluation
of the second condition occurs if and only if gender is equal to “F” (i.e., the entire
expression could still be true if the condition age >= 65 is true). This performance feature
for the evaluation of AndAlso and OrElse expressions is called short-circuit evaluation.
Performance Tip 5.2
In expressions using operator AndAlso, if the separate conditions are independent of one
another, place the condition most likely to be false as the leftmost condition. In expressions
using operator OrElse, make the condition most likely to be true the leftmost condition.
Each of these suggestions can reduce a program’s execution time. 5.2
The logical AND operator without short-circuit evaluation (And) and the logical
inclusive OR operator without short-circuit evaluation (Or) are similar to the AndAlso
and OrElse operators, with one exception—the And and Or logical operators always
evaluate both of their operands. No short-circuit evaluation occurs when And and Or are
employed. For example, the expression
(gender = “F” And age >= 65)
evaluates age >= 65, even if gender is not equal to “F”.
Normally, there is no compelling reason to use the And and Or operators instead of
AndAlso and OrElse. However, some programmers make use of them when the right
operand of a condition produces a side effect (such as a modification of a variable’s value) or
if the right operand includes a required method call, as in the following program segment:
Console.WriteLine(“How old are you?”)
If (gender = “F” And Console.ReadLine() >= 65) Then
Console.WriteLine(“You are a female senior citizen.”)
End If
Here, the And operator guarantees that the condition Console.ReadLine() >= 65 is
evaluated, so ReadLine is called regardless of whether the overall expression is true or
false. It would be better to write this code as two separate statements—the first would store
the result of Console.ReadLine() in a variable, then the second would use that variable
with the AndAlso operator in the condition.
Testing and Debugging Tip 5.9
Avoid expressions with side effects in conditions; these side effects often cause subtle errors.5.9
expression1 expression2 expression1 OrElse expression2
False False False
False True True
True False True
True True True
Fig. 5.18 Truth table for the OrElse operator.
Chapter 5 Control Structures: Part 2 167
A condition containing the logical exclusive OR (Xor) operator is true if and only if
one of its operands results in a true value and the other results in a false value. If both operands
are true or both are false, the entire condition is false. Figure 5.19 presents a truth table
for the logical exclusive OR operator (Xor). This operator always evaluates both of its
operands (i.e., there is no short-circuit evaluation).
Visual Basic’s Not (logical negation) operator enables a programmer to “reverse” the
meaning of a condition. Unlike the logical operators AndAlso, And, OrElse, Or and
Xor, that each combine two conditions (i.e., these are all binary operators), the logical
negation operator is a unary operator, requiring only one operand. The logical negation
operator is placed before a condition to choose a path of execution if the original condition
(without the logical negation operator) is false. The logical negation operator is demonstrated
by the following program segment:
If Not (grade = sentinelValue) Then
Console.WriteLine(“The next grade is ” & grade)
End If
The parentheses around the condition grade = sentinelValue are necessary,
because the logical negation operator (Not) has a higher precedence than the equality operator.
Figure 5.20 provides a truth table for the logical negation operator.
In most cases, the programmer can avoid using logical negation by expressing the condition
differently with relational or equality operators. For example, the preceding statement
can be written as follows:
If grade sentinelValue Then
Console.WriteLine(“The next grade is ” & grade)
End If
This flexibility aids programmers in expressing conditions more naturally.
expression1 expression2 expression1 Xor expression2
False False False
False True True
True False True
True True False
Fig. 5.19 Truth table for the logical exclusive OR (Xor) operator.
expression Not expression
False True
True False
Fig. 5.20 Truth table for operator Not (logical NOT).
168 Control Structures: Part 2 Chapter 5
The Windows application in Fig. 5.21 demonstrates the use of the logical operators by
displaying their truth tables in six labels.
1 ‘ Fig. 5.21: LogicalOperator.vb
2 ‘ Using logical operators.
34
Public Class FrmLogicalOperator
5 Inherits System.Windows.Forms.Form
67
‘ Visual Studio .NET generated code
89
Private Sub FrmLogicalOperator_Load( _
10 ByVal sender As System.Object, _
11 ByVal e As System.EventArgs) Handles MyBase.Load
12
13 lblAndAlso.Text = “AndAlso” & vbCrLf & vbCrLf & _
14 “False AndAlso False: ” & (False AndAlso False) & _
15 vbCrLf & “False AndAlso True: ” & _
16 (False AndAlso True) & vbCrLf & _
17 “True AndAlso False: ” & (True AndAlso False) & _
18 vbCrLf & “True AndAlso True: ” & (True AndAlso True)
19
20 lblOrElse.Text = “OrElse” & vbCrLf & vbCrLf & _
21 “False OrElse False: ” & (False OrElse False) & _
22 vbCrLf & “False OrElse True: ” & (False OrElse True) & _
23 vbCrLf & “True OrElse False: ” & (True OrElse False) & _
24 vbCrLf & “True OrElse True: ” & (True OrElse True)
25
26 lblAnd.Text = “And” & vbCrLf & vbCrLf & _
27 “False And False: ” & (False And False) & vbCrLf & _
28 “False And True: ” & (False And True) & vbCrLf & _
29 “True And False: ” & (True And False) & vbCrLf & _
30 “True And True: ” & (True And True)
31
32 lblOr.Text = “Or” & vbCrLf & _
33 vbCrLf & “False Or False: ” & (False Or False) & _
34 vbCrLf & “False Or True: ” & (False Or True) & _
35 vbCrLf & “True Or False: ” & (True Or False) & _
36 vbCrLf & “True Or True: ” & (True Or True)
37
38 lblXor.Text = “Xor” & vbCrLf & _
39 vbCrLf & “False Xor False: ” & (False Xor False) & _
40 vbCrLf & “False Xor True: ” & (False Xor True) & _
41 vbCrLf & “True Xor False: ” & (True Xor False) & _
42 vbCrLf & “True Xor True: ” & (True Xor True)
43
44 lblNot.Text = “Not” & vbCrLf & vbCrLf & _
45 “Not False: ” & (Not False) & vbCrLf & “Not True: ” & _
46 (Not True)
47
48 End Sub ‘ FrmLogicalOperator_Load
49
50 End Class ‘ FrmLogicalOperator
Fig. 5.21 Logical operator truth tables (part 1 of 2).
Chapter 5 Control Structures: Part 2 169
Line 4 begins class FrmLogicalOperator. Recall from our discussion in Chapter
4 that Visual Studio creates the initial code for a Windows application. Programmers then
enhance this code to create their own applications. Because the code created by Visual
Studio uses many concepts that have not been presented yet, we replace the Visual Studio
generated code with the comment in line 7. In Chapter 12, we carefully explain the Visual
Studio generated code line-by-line. Line 9 begins the definition of procedure
FrmLogicalOperator_Load. An empty procedure definition for a Windows application
can be obtained by double-clicking the form in the Design view. Procedures created
this way are executed when the program loads. In this case, the procedure creates Strings
representing the truth tables of the logical operators and displays them on six labels using
the Text property. Lines 13–18 demonstrate operator AndAlso; lines 20–24 demonstrate
operator OrElse. The remainder of procedure FrmLogicalOperator_Load demonstrates
the And, Or, Xor and Not operators. We use keywords True and False in the
program to specify values of the Boolean data type. Notice that when a Boolean value
is concatenated to a String, Visual Basic concatenates the string “False” or “True”
on the basis of the Boolean’s value.
The chart in Fig. 5.22 displays the precedence of the Visual Basic operators introduced
so far. The operators are shown from top to bottom in decreasing order of precedence.
Operators Type
() parentheses
^ exponentiation
+ – unary plus and minus
* / multiplicative
\ integer division
Mod modulus
Fig. 5.22 Precedence and associativity of the operators discussed so far
(part 1 of 2).
Fig. 5.21 Logical operator truth tables (part 2 of 2).
170 Control Structures: Part 2 Chapter 5
5.10 Structured Programming Summary
Just as architects design buildings by employing the collective wisdom of their profession,
so should programmers design programs. Our field is younger than architecture is, and our
collective wisdom is considerably sparser. We have learned that structured programming
produces programs that are easier to understand, test, debug, modify and prove correct in a
mathematical sense than unstructured programs. Visual Basic’s control structures are summarized
in Fig. 5.23 and Fig. 5.24.
+ – additive
& concatenation
< >= = relational and equality
Not logical NOT
And AndAlso logical AND
Or OrElse logical inclusive OR
Xor logical exclusive OR
Fig. 5.23 Visual Basic’s single-entry/single-exit sequence and selection structures.
Operators Type
Fig. 5.22 Precedence and associativity of the operators discussed so far
(part 2 of 2).
Sequence
If/Then structure
(single selection)
If/Then/Else structure
(double selection)
Select Case structure
(multiple selection)

Selection

F T
F
T
F
T
F
T
F
T
Chapter 5 Control Structures: Part 2 171
Small circles in the figures indicate the single entry point and the single exit point of
each structure. Connecting individual flowchart symbols arbitrarily can lead to unstructured
programs. Therefore, the programming profession has chosen to employ only a limited
set of control structures and to build structured programs by combining control
structures in only two simple ways.
Fig. 5.24 Visual Basic’s single-entry/single-exit repetition structures.
Do/Loop Until structure
While structure For/Next structure
Do/Loop While structure
Repetition
Do While/Loop structure Do Until/Loop structure
For Each/Next structure (introduced in Chapter 7)
F
T
F
T
F
F T
T
F
T F
T
F
T
172 Control Structures: Part 2 Chapter 5
For the sake of simplicity, only single-entry/single-exit control structures are used—
there is only one way to enter and only one way to exit each control structure. To connect
control structures in sequence to form structured programs, the exit point of one control
structure is connected to the entry point of the next control structure (i.e., the control structures
simply are placed one after another in a program). We call this process control structure
stacking. The rules for the formation of structured programs also allow control
structures to be nested, i.e., placed one inside the other. Figure 5.25 contains the rules for
the formation of properly structured programs. The rules assume that the rectangle flowchart
symbol can indicate any action, including input/output.
Applying the rules of Fig. 5.25 always results in a structured flowchart with a neat,
building-block appearance. For example, repeatedly applying rule 2 to the simplest flowchart
(Fig. 5.26) results in a structured flowchart that contains many rectangles in sequence
(Fig. 5.27). Notice that rule 2 generates a stack of control structures; therefore, we call rule
2 the stacking rule.
Rule 3 is the nesting rule. Repeatedly applying rule 3 to the simplest flowchart results
in a flowchart with neatly nested control structures. For example, in Fig. 5.28, the rectangle
in the simplest flowchart (in the top-left portion of the figure) is first replaced with a
double-selection (If/Then/Else) structure. Then, rule 3 is applied again to both rectangles
in the double-selection structure, replacing each of these rectangles with a doubleselection
structure. The dashed boxes around each of the double-selection structures represent
the rectangles that were replaced with these structures.
Good Programming Practice 5.4
Excessive levels of nesting can make a program difficult to understand. As a general rule, try
to avoid using more than three levels of nesting. 5.4
Rule 4 generates larger, more involved and deeply-nested structures. The flowcharts
that emerge from applying the rules in Fig. 5.25 constitute the set of all possible structured
flowcharts and the set of all possible structured programs.The structured approach has the
advantage of using only eleven simple single-entry/single-exit pieces and allowing us to
combine them in only two simple ways. Figure 5.29 depicts the kinds of correctly stacked
building blocks that emerge from applying rule 2 and the kinds of correctly nested building
blocks that emerge from applying rule 3. The figure also shows the kind of overlapped
building blocks that cannot appear in structured flowcharts.
Rules for Forming Structured Programs
1) Begin with the “simplest flowchart” (Fig. 5.26).
2) Any rectangle (action) can be replaced by two rectangles (actions) in sequence.
3) Any rectangle (action) can be replaced by any control structure (sequence, If/Then, If/
Then/Else, Select Case, While, Do/Loop While, Do While/Loop, Do Until/
Loop, Do/Loop Until, For/Next or the For Each/Next structure introduced in
Chapter 7, Arrays).
4) Rules 2 and 3 may be applied as often as you like and in any order.
Fig. 5.25 Structured programming rules.
Chapter 5 Control Structures: Part 2 173
If the rules in Fig. 5.25 are followed, an unstructured flowchart (such as that in
Fig. 5.30) cannot be created. If you are uncertain about whether a particular flowchart is
structured, apply the rules in Fig. 5.25 in reverse to try to reduce the flowchart to the simplest
flowchart. If the flowchart can be reduced to the simplest flowchart, the original flowchart
is structured; otherwise, it is not.
Structured programming promotes simplicity. Bohm and Jacopini have demonstrated
that only three forms of control are necessary:
• sequence
• selection
• repetition
Sequence is trivial. Selection is implemented in one of three ways:
• If/Then structure (single selection)
• If/Then/Else structure (double selection)
• Select Case structure (multiple selection)
It can be proven straightforwardly that the If/Then structure is sufficient to provide any
form of selection. Everything done with the If/Then/Else structure and the Select
Case structure can be implemented by combining multiple If/Then structures (although
perhaps not as elegantly).
Fig. 5.26 Simplest flowchart.
Fig. 5.27 Repeatedly applying rule 2 of Fig. 5.25 to the simplest flowchart.

Rule 2 Rule 2 Rule 2
174 Control Structures: Part 2 Chapter 5
Repetition is implemented in one of seven ways:
• While structure
• Do While/Loop structure
• Do/Loop While structure
• Do Until/Loop structure
• Do/Loop Until structure
• For/Next structure
• For Each/Next structure (introduced in Chapter 7)
It can be proven straightforwardly that the While structure is sufficient to provide any
form of repetition. Everything that can be done with the Do While/Loop, Do/Loop
While, Do Until/Loop, Do/Loop Until, For/Next and For Each/Next structures
can be done with the While structure (although perhaps not as elegantly).
Fig. 5.28 Applying rule 3 of Fig. 5.25 to the simplest flowchart.
Rule 3
Rule 3 Rule 3
Chapter 5 Control Structures: Part 2 175
The combination of these results illustrates that any form of control ever needed in a
Visual Basic program can be expressed in terms of:
• sequence
• If/Then structure (selection)
• While structure (repetition)
These control structures can be combined in only two ways—stacking and nesting. Indeed,
structured programming promotes simplicity.
In this chapter, we discussed the composition of programs from control structures that
contain actions and decisions. In Chapter 6, Procedures, we introduce another program
structuring unit called the procedure. We show how to construct large programs by combining
procedures that are composed of control structures. We also discuss the ways in
which procedures promote software reusability. In Chapter 8, Object-Based Programming,
we offer a detailed introduction to another Visual Basic program structuring unit, called the
class. We then create objects from classes (that are composed of procedures) and proceed
with our treatment of object-oriented programming—the key focus of this book.
Fig. 5.29 Stacked, nested and overlapped building blocks.
Fig. 5.30 Unstructured flowchart.
Overlapping building blocks
(Illegal in structured programs)
Stacked building blocks Nested building blocks
176 Control Structures: Part 2 Chapter 5
SUMMARY
• Counter-controlled repetition requires the name of a control variable (or loop counter), the initial
value of the control variable, the increment (or decrement) by which the control variable is modified
during each iteration of the loop and the condition that tests for the final value of the control
variable (i.e., whether looping should continue).
• Declarations that include initialization are executable statements.
• The For/Next repetition structure handles the details of counter-controlled repetition. The required
To keyword specifies the initial value and the final value of the control variable. The optional
Step keyword specifies the increment.
• Counting loops should not be controlled with floating-point variables. Floating-point values are
represented only approximately in the computer’s memory, often resulting in imprecise counter
values and inaccurate tests for termination.
• When supplying four arguments to method MessageBox.Show, the first two arguments are
strings displayed in the dialog and the dialog’s title bar. The third and fourth arguments are constants
representing buttons and icons, respectively.
• Method String.Format inserts values into a String using Visual Basic’s format codes.
• Visual Basic provides the Decimal data type, which is designed specifically for monetary calculations.
It is inappropriate to use Single or Double for dollar amounts.
• Visual Basic provides the Select Case multiple-selection structure to test a variable or expression
separately for each value that the variable or expression might assume. The Select Case
structure consists of a series of Case labels and an optional Case Else. Each Case contains
statements to be executed if that Case is selected.
• Each Case in a Select Case structure can test for a specific value, a range of values (using
keyword To) or a condition (using keyword Is and a relational operator). The comma can be used
to specify a list of values, ranges and conditions that satisfy a Case statement.
• The Do/Loop While and Do/Loop Until structures test the loop-continuation condition after
the loop body is performed; therefore, the loop body is always executed at least once.
• The Exit Do, Exit While and Exit For statements alter the flow of control by causing immediate
exit from a repetition structure.
• The logical operators are AndAlso (logical AND with short-circuit evaluation), And (logical
AND without short-circuit evaluation), OrElse (logical inclusive OR with short-circuit evaluation),
Or (logical inclusive OR without short-circuit evaluation), Xor (logical exclusive OR) and
Not (logical NOT, also called logical negation).
• The AndAlso operator can be used to ensure that two conditions are both true.
• The OrElse operator can be used to ensure that at least one of two conditions is true.
• The And and Or operators are similar to the AndAlso and OrElse operators, except that they
always evaluate both of their operands.
• A condition containing the logical exclusive OR (Xor) operator is true if and only if exactly one
of its operands is true.
• A condition that begins with the logical NOT (Not) operator is true if and only if the condition to
the right of the logical NOT operator is false.
• In flowcharts, small circles indicate the single entry point and exit point of each structure.
• Connecting individual flowchart symbols arbitrarily can lead to unstructured programs. Therefore,
the programming profession has chosen to employ only a limited set of control structures and to
build structured programs by combining control structures in only two simple ways.
Chapter 5 Control Structures: Part 2 177
• To connect control structures in sequence to form structured programs, the exit point of one control
structure is connected to the entry point of the next control structure (i.e., the control structures simply
are placed one after another in a program). We call this process “control structure stacking.”
• The rules for forming structured programs also allow control structures to be nested.
• Structured programming promotes simplicity.
• Bohm and Jacopini have demonstrated that only three forms of control are necessary—sequence,
selection and repetition.
• Selection is implemented with one of three structures—If/Then, If/Then/Else and
Select Case.
• Repetition is implemented with one of seven structures—While, Do While/Loop, Do/Loop
While, Do Until/Loop, Do/Loop Until, For/Next, and For Each/Next (introduced in
Chapter 7, Arrays).
• The If/Then structure is sufficient to provide any form of selection.
• The While structure is sufficient to provide any form of repetition.
• Control structures can be combined in only two ways—stacking and nesting.
TERMINOLOGY
AbortRetryIgnore constant iteration of a loop
body of a loop levels of nesting
Boolean values logical AND with short-circuit
buttons for a message dialog evaluation (AndAlso)
Case keyword logical AND without short-circuit
Case Else statement valuation (And)
control structure logical exclusive OR (Xor)
control-structure nesting logical inclusive OR with short-circuit
control-structure stacking evaluation (OrElse)
controlling expression logical inclusive OR without short-circuit
counter-controlled repetition evaluation (Or)
Decimal data type logical NOT (Not)
decrement of loop logical operator
diamond symbol loop body
Do/Loop Until structure loop counter
Do/Loop While structure loop-continuation condition
double-selection structure message dialog button
End Select statement message dialog icon
entry point of a control structure MessageBoxButtons.
Exit Do statement AbortRetryIgnore constant
Exit For statement MessageBoxButtons.OK constant
Exit While statement MessageBoxButtons.OKCancel constant
For Each/Next structure MessageBoxButtons.RetryCancel
For/Next structure constant
For/Next header MessageBoxButtons.YesNo constant
hexadecimal (base16) number system MessageBoxButtons.YesNoCancel
icon for a message dialog constant
If/Then structure MessageBoxButtons class
If/Then/Else structure MessageBoxIcon class
increment of control variable MessageBoxIcon.Error constant
Is keyword MessageBoxIcon.Exclamation constant
178 Control Structures: Part 2 Chapter 5
SELF-REVIEW EXERCISES
5.1 State whether each of the following is true or false. If false, explain why.
a) The Case Else is required in the Select Case selection structure.
b) The expression x > y AndAlso a y is true or a < b is true.
c) An expression containing the OrElse operator is true if either or both of its operands is
true.
d) The expression x 4 is true if x is less than or equal to y and y is greater
than 4.
e) Logical operator Or performs short-circuit evaluation.
f) A While structure with the header
While (x > 10 AndAlso x < 100)
iterates while 10 < x operator
with the keyword.
d) In a For/Next structure, incrementing occurs the body of the structure is
performed.
e) Placing expressions whose values do not change inside structures can lead
to poor performance.
f) The four types of MessageBox icons are exclamation, information, error and
.
g) The expression following the keywords Select Case is called the .
5.3 Write a Visual Basic statement or a set of Visual Basic statements to accomplish each of the
following:
MessageBoxIcon.Information constant sequence
MessageBoxIcon.Question constant short-circuit evaluation
multiple-selection structure Show method of class MessageBox
nested building block simplest flowchart
nested control structure single selection
nesting single-entry/single-exit sequence, selection and
nesting rule repetition structures
Next keyword stacking rule
overlapped building block Step keyword in a For/Next structure
program construction principle String formatting code
rectangle symbol structured programming
repetition To keyword in a For/Next structure
Select Case structure unary operator
selection unstructured flowchart
Chapter 5 Control Structures: Part 2 179
a) Sum the odd integers between 1 and 99 using a For/Next structure. Assume that the
integer variables sum and count have been declared.
b) Write a statement that exits a While loop.
c) Print the integers from 1 to 20, using a Do/Loop While loop and the counter variable x.
Assume that the variable x has been declared, but not initialized. Print only five integers
per line. [Hint: Use the calculation x Mod 5. When the value of this is 0, print a newline
character; otherwise, print a tab character. Call Console.WriteLine to output the
newline character and call Console.Write(vbTab) to output the tab character.]
d) Repeat part c, using a For/Next structure.
ANSWERS TO SELF-REVIEW EXERCISES
5.1 a) False. The Case Else is optional. b) False. Both of the relational expressions must be
true for the entire expression to be true. c) True. d) True. 4. e) False. Logical operator Or always evaluates
both of its operands. f) True. g) True. h) False. There is often a trade-off between good software
engineering and high performance. i) False. The AndAlso operator has higher precedence than the
OrElse operator.
5.2 a) Step. b) Decimal. c) Is. d) after. e) repetition. f) question mark. g) controlling expression.
5.3 a) sum = 0
For count = 1 To 99 Step 2
sum += count
Next
b) Exit While
c) x = 1
Do
Console.Write(x)
If x Mod 5 = 0 Then
Console.WriteLine()
Else
Console.Write(vbTab)
End If
x += 1
Loop While x <= 20
or
x = 1
Do
If x Mod 5 = 0 Then
Console.WriteLine(x)
Else
Console.Write(x & vbTab)
End If
180 Control Structures: Part 2 Chapter 5
x += 1
Loop While x <= 20
d) For x = 1 To 20
Console.Write(x)
If x Mod 5 = 0 Then
Console.WriteLine()
Else
Console.Write(vbTab)
End If
Next
or
For x = 1 To 20
If x Mod 5 = 0 Then
Console.WriteLine(x)
Else
Console.Write(x & vbTab)
End If
Next
EXERCISES
5.4 The factorial method is used frequently in probability problems. The factorial of a positive
integer n (written n! and pronounced “n factorial”) is equal to the product of the positive integers from
1 to n. Even for relatively small values of n, the factorial method yields extremely large numbers. For
instance, when n is 13, n! is 6227020800—a number too large to be represented with data type Integer
(a 32-bit integer value). To calculate the factorials of large values of n, data type Long (a 64-
bit integer value) must be used. Write a program that evaluates the factorials of the integers from 1 to
20 using data type Long. Display the results in a two column output table. [Hint: create a Windows
application, use Labels as the columns and the vbCrLf constant to line up the rows.] The first column
should display the n values (1–20). The second column should display n!.
5.5 Write two programs that each print a table of the binary, octal, and hexadecimal equivalents
of the decimal numbers in the range 1–256. If you are not familiar with these number systems, read
Appendix B, Number Systems, first.
a) For the first program, print the results to the console without using any String formats.
b) For the second program, print the results to the console using both the decimal and hexadecimal
String formats (there are no formats for binary and octal in Visual Basic).
5.6 (Pythagorean Triples) Some right triangles have sides that are all integers. A set of three integer
values for the sides of a right triangle is called a Pythagorean triple. These three sides must satisfy
the relationship that the sum of the squares of the two sides is equal to the square of the
hypotenuse. Write a program to find all Pythagorean triples for side1, side2 and hypotenuse,
none larger than 30. Use a triple-nested For/Next loop that tries all possibilities. This is an example
of “brute force” computing. You will learn in more advanced computer science courses that there are
some problems for which there is no known algorithmic approach other than using sheer brute force.
Chapter 5 Control Structures: Part 2 181
5.7 Write a program that displays the following patterns separately, one below the other. Use
For/Next loops to generate the patterns. All asterisks (*) should be printed by a single statement of
the form Console.Write("*") (this causes the asterisks to print side by side). A statement of
the form Console.WriteLine() can be used to position to the next line and a statement of the
form Console.WriteLine(" ") can be used to display spaces for the last two patterns. There
should be no other output statements in the program. [Hint: The last two patterns require that each
line begin with an appropriate number of blanks.] Maximize your use of repetition (with nested For/
Next structures) and minimize the number of output statements.
5.8 Modify Exercise 5.7 to combine your code from the four separate triangles of asterisks into
a single program that prints all four patterns side by side, making clever use of nested For/Next
loops.
5.9 Write a program that prints the following diamond shape. You may use output statements that
print a single asterisk (*), a single space or a single newline character. Maximize your use of repetition
(with nested For/Next structures) and minimize the number of output statements.
5.10 Modify the program you wrote in Exercise 5.9 to read an odd number in the range from 1 to
19 to specify the number of rows in the diamond. Your program should then display a diamond of the
appropriate size. Use a Do/Loop Until to validate user input.
(A) (B) (C) (D)
* ********** ********** *
** ********* ********* **
*** ******** ******** ***
**** ******* ******* ****
***** ****** ****** *****
****** ***** ***** ******
******* **** **** *******
******** *** *** ********
********* ** ** *********
********** * * **********
*
***
*****
*******
*********
*******
*****
***
*
6
Procedures
Objectives
• To construct programs modularly from pieces called
procedures.
• To introduce the common Math methods available in
the Framework Class Library.
• To create new procedures.
• To understand the mechanisms used to pass
information between procedures.
• To introduce simulation techniques that employ
random-number generation.
• To understand how the visibility of identifiers is
limited to specific regions of programs.
• To understand how to write and use recursive
procedures (procedures that call themselves).
Form ever follows function.
Louis Henri Sullivan
E pluribus unum.
(One composed of many.)
Virgil
O! call back yesterday, bid time return.
William Shakespeare, Richard II
Call me Ishmael.
Herman Melville, Moby Dick
When you call me that, smile.
Owen Wister
Chapter 6 Procedures 183
6.1 Introduction
Most computer programs that solve real-world problems are much larger than the programs
presented in the first few chapters of this text. Experience has shown that the best way to
develop and maintain a large program is to construct it from small, manageable pieces. This
technique is known as divide and conquer. In this chapter, we describe many key features
of the Visual Basic language that facilitate the design, implementation, operation and maintenance
of large programs.
6.2 Modules, Classes and Procedures
Visual Basic programs consist of many pieces, including modules and classes. The programmer
combines new modules and classes with “prepackaged” classes available in the .NET
Framework Class Library (FCL). These modules and classes are composed of smaller pieces
called procedures. When procedures are contained in a class, we refer to them as methods.
The FCL provides a rich collection of classes and methods for performing common
mathematical calculations, string manipulations, character manipulations, input/output
Outline
6.1 Introduction
6.2 Modules, Classes and Procedures
6.3 Sub Procedures
6.4 Function Procedures
6.5 Methods
6.6 Argument Promotion
6.7 Option Strict and Data-Type Conversions
6.8 Value Types and Reference Types
6.9 Passing Arguments: Pass-by-Value vs. Pass-by-Reference
6.10 Duration of Identifiers
6.11 Scope Rules
6.12 Random-Number Generation
6.13 Example: Game of Chance
6.14 Recursion
6.15 Example Using Recursion: Fibonacci Series
6.16 Recursion vs. Iteration
6.17 Procedure Overloading and Optional Arguments
6.17.1 Procedure Overloading
6.17.2 Optional Arguments
6.18 Modules

Pemrograman Web/TI/ AK045216/2 sks
Contoh script ASP- 1
•VBScript adalah bahasa scripting standar untuk membuat halaman ASP.
Pada contoh-contoh script berikut digunakan VBScript:
•Contoh 1 :
– Langkah pembuatan :
• Masukkan text ‘Hello World’ pada variabel FirstVar
• Buat tag awal HTML
• Gunakan untuk menampilkan isi variabel FirstVar
• Akhiri tag HTML
– Script lengkap :

• Example 1





Summary • Terminology • Self-Review Exercises • Answers to Self-Review Exercises • Exercises
184 Procedures Chapter 6
operations, error checking and many other useful operations. This framework makes the
programmer’s job easier, because the methods provide many of the capabilities programmers
need. In earlier chapters, we introduced some FCL classes, such as Console, which
provides methods for inputting and outputting data.
Software Engineering Observation 6.1
Familiarize yourself with the rich collection of classes and methods in the Framework Class
Library. 6.1
Software Engineering Observation 6.2
When possible, use .NET Framework classes and methods instead of writing new classes and
methods. This reduces program development time and avoids introducing new errors. 6.2
Performance Tip 6.1
.NET Framework Class Library methods are written to perform efficiently. 6.1
Although the FCL provides methods that perform many common tasks, it cannot provide
every conceivable feature that a programmer could want, so Visual Basic allows programmers
to create their own programmer-defined procedures to meet the unique
requirements of a particular problem. Three types of procedures exist: Sub procedures,
Function procedures and event procedures. Throughout this chapter, the term “procedure”
refers to both Sub procedures and Function procedures unless otherwise noted.
Programmers write procedures to define specific tasks that a program may use many
times during its execution. Although the same programmer-defined procedure can be executed
at multiple points in a program, the actual statements that define the procedure are
written only once.
A procedure is invoked (i.e., made to perform its designated task) by a procedure call.
The procedure call specifies the procedure name and provides information (as arguments)
that the callee (i.e, the procedure being called) requires to do its job. When the procedure
completes its task, it returns control to the caller (i.e., the calling procedure). In some cases,
the procedure also returns a result to the caller. A common analogy for this is the hierarchical
form of management. A boss (the caller) asks a worker (the callee) to perform a task
and return (i.e., report on) the results when the task is done. The boss does not need to know
how the worker performs the designated task. For example, the worker might call other
workers—the boss would be unaware of this. Soon, we show how this hiding of implementation
details promotes good software engineering. Figure 6.1 depicts a Boss procedure
communicating with worker procedures Worker1, Worker2 and Worker3 in a hierarchical
manner. Note that Worker1 acts as a “boss” procedure to Worker4 and Worker5
in this particular example.
There are several motivations for the division of code into procedures. First, the divideand-
conquer approach makes program development more manageable. Another motivation
is software reusability—the ability to use existing procedures as building blocks for new
programs. When proper naming and definition conventions are applied, programs can be
created from standardized pieces that accomplish specific tasks, to minimize the need for
customized code. A third motivation involves avoiding the repetition of code in a program.
When code is packaged as a procedure, the code can be executed from several locations in
a program simply by calling, or invoking, the procedure.
Chapter 6 Procedures 185
Good Programming Practice 6.1
Use modularity to increase the clarity and organization of a program. This not only helps others
understand the program, but also aids in program development, testing and debugging. 6.1
Software Engineering Observation 6.3
To promote reusability, the capabilities of each procedure should be limited to the performance
of a single, well-defined task, and the name of the procedure should express that task
effectively. 6.3
Software Engineering Observation 6.4
If you cannot choose a concise name that expresses the task performed by a procedure, the
procedure could be attempting to perform too many diverse tasks. It is usually best to divide
such a procedure into several smaller procedures. 6.4
6.3 Sub Procedures
The programs presented earlier in the book each contained at least one procedure definition
(e.g., Main) that called FCL methods (such as Console.WriteLine) to accomplish
the program’s tasks. We now consider how to write customized procedures.
Consider the console application in Fig. 6.2, which uses a Sub procedure (invoked
from the application’s Main procedure) to print a worker’s payment information.
Fig. 6.1 Hierarchical boss-procedure/worker-procedure relationship.
Boss
Worker1 Worker2 Worker3
Worker4 Worker5
1 ‘ Fig. 6.2: Payment.vb
2 ‘ Sub procedure that prints payment information.
34
Module modPayment
56
Sub Main()
78
‘ call Sub procedure PrintPay 4 times
9 PrintPay(40, 10.5)
10 PrintPay(38, 21.75)
Fig. 6.2 Sub procedure for printing payment information (part 1 of 2).
186 Procedures Chapter 6
The program contains two procedure definitions. Lines 6–14 define Sub procedure
Main, which executes when the console application is loaded. Lines 17–21 define Sub
procedure PrintPay, which executes when it is invoked, or called, from another procedure,
in this case Main.
Main makes four calls (lines 9–12) to Sub procedure PrintPay, causing
PrintPay to execute four times. Although the procedure arguments in this example are
constants, arguments can also be variables or expressions. For example, the statement
PrintPay(employeeOneExtraHours, employeeOneWage * 1.5)
could be used to display payment information for an employee who is being paid time-anda-
half for working overtime.
When Main calls PrintPay, the program makes a copy of the value of each argument
(e.g., 40 and 10.5 on line 9), and program control transfers to the first line of procedure
PrintPay. Procedure PrintPay receives the copied values and stores them in
the parameter variables hours and wage. Then, PrintPay calculates hours * wage
and displays the result, using the currency format (line 20). When the End Sub statement
on line 21 is encountered, control is returned to the calling procedure, Main.
The first line of procedure PrintPay (line 17) shows (inside the parentheses) that
PrintPay declares a Double variable hours and a Decimal variable wage. These
parameters hold the values passed to PrintPay within the definition of this procedure.
Notice that the entire procedure definition of PrintPay appears within the body of
module modPayment. All procedures must be defined inside a module or a class.
The format of a procedure definition is
Sub procedure-name(parameter-list)
declarations and statements
End Sub
11 PrintPay(20, 13)
12 PrintPay(50, 14)
13
14 End Sub ‘ Main
15
16 ‘ print dollar amount earned in command window
17 Sub PrintPay(ByVal hours As Double, ByVal wage As Decimal)
18
19 ‘ pay = hours * wage
20 Console.WriteLine(“The payment is {0:C}”, hours * wage)
21 End Sub ‘ PrintPay
22
23 End Module ‘ modPayment
The payment is $420.00
The payment is $826.50
The payment is $260.00
The payment is $700.00
Fig. 6.2 Sub procedure for printing payment information (part 2 of 2).
Chapter 6 Procedures 187
Good Programming Practice 6.2
Place a blank line between procedure definitions to separate the procedures and enhance
program readability. 6.2
Common Programming Error 6.1
Defining a procedure outside of a class or module definition is a syntax error. 6.1
The first line is sometimes known as the procedure header. The procedure-name, which
directly follows the Sub keyword in the procedure header, can be any valid identifier and
is used to call this Sub procedure within the program.
The parameter-list is a comma-separated list in which the Sub procedure declares
each parameter variable’s type and name. There must be one argument in the procedure call
for each parameter in the procedure header (we will see an exception to this rule in
Section 6.17). The arguments also must be compatible with the parameter’s type (i.e.,
Visual Basic must be able to assign the value of the argument to the parameter). For
example, a parameter of type Double could receive the value of 7.35, 22 or –.03546, but
not “hello”, because a Double value cannot contain a String. In Section 6.6 we discuss
this issue in detail. If a procedure does not receive any values, the parameter list is
empty (i.e., the procedure name is followed by an empty set of parentheses).
Notice that the parameter declarations in the procedure header for PrintPay (line
17) look similar to variable declarations, but use keyword ByVal instead of Dim. ByVal
specifies that the calling program should pass a copy of the value of the argument in the
procedure call to the parameter, which can be used in the Sub procedure body. Section 6.9
discusses argument passing in detail.
Common Programming Error 6.2
Declaring a variable in the procedure’s body with the same name as a parameter variable
in the procedure header is a syntax error. 6.2
Testing and Debugging Tip 6.1
Although it is allowable, an argument passed to a procedure should not have the same name
as the corresponding parameter in the procedure definition. This distinction prevents ambiguity
that could lead to logic errors. 6.1
The declarations and statements in the procedure definition form the procedure body.
The procedure body contains Visual Basic code that performs actions, generally by manipulating
or interacting with the parameters. The procedure body must be terminated with
keywords End Sub, which define the end of the procedure. The procedure body is also
referred to as a block. A block is a sequence of statements and declarations grouped
together as the body of some structure and terminated with an End, Next, Else or Loop
statement, depending on the type of structure. Variables can be declared in any block, and
blocks can be nested.
Common Programming Error 6.3
Defining a procedure inside another procedure is a syntax error—procedures cannot be
nested. 6.3
Control returns to the caller when execution reaches the End Sub statement (i.e., the
end of the procedure body). Alternatively, keywords Return and Exit Sub can be used
188 Procedures Chapter 6
anywhere in a procedure to return control to the point at which a Sub procedure was
invoked. We discuss Return and Exit Sub in detail, momentarily.
Good Programming Practice 6.3
The selection of meaningful procedure names and parameter names makes programs more
readable and reduces the need for excessive comments. 6.3
Software Engineering Observation 6.5
Procedure names tend to be verbs because procedures typically perform operations on data.
By convention, programmer-defined procedure names begin with an uppercase first letter.
For example, a procedure that sends an e-mail message might be named SendMail. 6.5
Software Engineering Observation 6.6
A procedure that requires a large number of parameters might be performing too many tasks.
Consider dividing the procedure into smaller procedures that perform separate tasks. As a
“rule of thumb,” the procedure header should fit on one line (if possible). 6.6
Software Engineering Observation 6.7
As a “rule of thumb,” a procedure should be limited to one printed page. Better yet, a procedure
should be no longer than half a printed page. Regardless of how long a procedure is,
it should perform one task well. 6.7
Testing and Debugging Tip 6.2
Small procedures are easier to test, debug and understand than large procedures. 6.2
Performance Tip 6.2
When a programmer divides a procedure into several procedures that communicate with one
another, this communication takes time and sometimes leads to poor execution performance. 6.2
Software Engineering Observation 6.8
The procedure header and procedure calls all must agree with regard to the number, type
and order of parameters. We discuss exceptions to this in Section 6.17. 6.8
6.4 Function Procedures
Function procedures are similar to Sub procedures, with one important difference:
Function procedures return a value (i.e., send a value) to the caller, whereas Sub procedures
do not. The console application in Fig. 6.3 uses Function procedure Square to
calculate the squares of the Integers from 1–10.
1 ‘ Fig. 6.3: SquareInteger.vb
2 ‘ Function procedure to square a number.
34
Module modSquareInteger
56
Sub Main()
7 Dim i As Integer ‘ counter
8
Fig. 6.3 Function procedure for squaring an integer (part 1 of 2).
Chapter 6 Procedures 189
The For structure (lines 12–14) displays the results of squaring the Integers from 1–
10. Each iteration of the loop calculates the square of control variable i and displays it in the
command window.
Function procedure Square is invoked (line 13) with the expression Square(i).
When program control reaches this expression, the program calls Function Square (lines
20–22). At this point, the program makes a copy of the value of i (the argument), and program
control transfers to the first line of Function Square. Square receives the copy
of i’s value and stores it in the parameter y. Line 21 is a Return statement, which terminates
execution of the procedure and returns the result of y ^ 2 to the calling program. The
result is returned to the point on line 13 where Square was invoked. Line 13 displays the
value of i and the value returned by Square in the command window. This process is
repeated 10 times.
The format of a Function procedure definition is
Function procedure-name(parameter-list) As return-type
declarations and statements
End Function
The procedure-name, parameter-list, and the declarations and statements in a Function
procedure definition behave like the corresponding elements in a Sub procedure definition.
9 Console.WriteLine(“Number” & vbTab & “Square” & vbCrLf)
10
11 ‘ square numbers from 1 to 10
12 For i = 1 To 10
13 Console.WriteLine(i & vbTab & Square(i))
14 Next
15
16 End Sub ‘ Main
17
18 ‘ Function Square is executed
19 ‘ only when the function is explicitly called.
20 Function Square(ByVal y As Integer) As Integer
21 Return y ^ 2
22 End Function ‘ Square
23
24 End Module ‘ modSquareInteger
Number Square
1 1
2 4
3 9
4 16
5 25
6 36
7 49
8 64
9 81
10 100
Fig. 6.3 Function procedure for squaring an integer (part 2 of 2).
190 Procedures Chapter 6
In the Function header, the return-type indicates the data type of the result returned from
the Function to its caller. The statement
Return expression
can occur anywhere in a Function procedure body and returns the value of expression
to the caller. If necessary, Visual Basic attempts to convert the expression to the Function
procedure’s return-type. Functions Return exactly one value. When a Return
statement is executed, control returns immediately to the point at which that
procedure was invoked.
Common Programming Error 6.4
If the expression in a Return statement cannot be converted to the Function procedure’s
return-type, a runtime error is generated. 6.4
Common Programming Error 6.5
Failure to return a value from a Function procedure (e.g., by forgetting to provide a Return
statement) causes the procedure to return the default value for the return-type, often
producing incorrect output. 6.5
6.5 Methods
A method is any procedure that is contained within a class. We have already presented several
FCL methods (i.e., methods contained in classes that are part of the FCL). Programmers
also can define custom methods in programmer-defined classes, such as a class used
to define a Windows application. The Windows application in Fig. 6.4 uses two methods
to calculate the largest of three Doubles.
1 ‘ Fig. 6.4: Maximum.vb
2 ‘ Program finds the maximum of three numbers input.
34
Public Class FrmMaximum
5 Inherits System.Windows.Forms.Form
67
‘ prompts for three inputs
8 Friend WithEvents lblOne As System.Windows.Forms.Label
9 Friend WithEvents lblTwo As System.Windows.Forms.Label
10 Friend WithEvents lblThree As System.Windows.Forms.Label
11
12 ‘ displays result
13 Friend WithEvents lblMaximum As System.Windows.Forms.Label
14
15 ‘ read three numbers
16 Friend WithEvents txtFirst As System.Windows.Forms.TextBox
17 Friend WithEvents txtSecond As System.Windows.Forms.TextBox
18 Friend WithEvents txtThird As System.Windows.Forms.TextBox
19
20 ‘ reads inputs and calculate results
21 Friend WithEvents cmdMaximum As System.Windows.Forms.Button
22
Fig. 6.4 Method that determines the largest of three numbers (part 1 of 2).
Chapter 6 Procedures 191
Until now, many of our applications have facilitated user interaction via either the
command window (in which the user can type an input value into the program) or a message
dialog (which displays a message to the user and allows the user to click OK to dismiss
the dialog). In Chapter 4, Control Structures: Part 1, we introduced Windows applications
by creating a program that displays information in a label on a form.
Although the command window and message dialogs are valid ways to receive input
from a user and display output, they are limited in their capabilities—the command
window can obtain only one line of input at a time from the user, and a message dialog
can display only one message. It is common to receive multiple inputs at the same time
(such as the three values in this example), or to display many pieces of data at once. To
introduce more sophisticated user interface programming, the program in Fig. 6.4 uses
GUI event handling (i.e., the ability to respond to a state change in the GUI, such as when
the user clicks a button).
23 ‘ Visual Studio .NET generated code
24
25 ‘ obtain values in each text box, call procedure Maximum
26 Private Sub cmdMaximum_Click(ByVal sender As System.Object, _
27 ByVal e As System.EventArgs) Handles cmdMaximum.Click
28
29 Dim value1, value2, value3 As Double
30
31 value1 = txtFirst.Text
32 value2 = txtSecond.Text
33 value3 = txtThird.Text
34
35 lblMaximum.Text = Maximum(value1, value2, value3)
36 End Sub ‘ cmdMaximum_Click
37
38 ‘ find maximum of three parameter values
39 Function Maximum(ByVal valueOne As Double, _
40 ByVal valueTwo As Double, ByVal valueThree As Double)
41
42 Return Math.Max(Math.Max(valueOne, valueTwo), valueThree)
43 End Function ‘ Maximum
44
45 End Class ‘ FrmMaximum
Fig. 6.4 Method that determines the largest of three numbers (part 2 of 2).
192 Procedures Chapter 6
Class FrmMaximum uses a GUI consisting of three TextBoxes (txtFirst, txt-
Second and txtThird) for user input, a Button (cmdMaximum) to invoke the calculation
and four Labels, including lblMaximum, which displays the results. We create
these components visually, using the Toolbox, and change their properties in the Properties
window. Lines 7–21 are declarations indicating the name of each component.
Although these lines of code are actually part of the Visual Studio .NET generated code,
we display them to indicate the objects that are part of the form (as always, the complete
code for this program is on the CD-ROM that accompanies this book and at
http://www.deitel.com).
Line 5 indicates that class FrmMaximum Inherits from System.Windows.
Forms.Form. Remember that all forms inherit from class System.Windows.
Forms.Form. A class can inherit attributes and behaviors (data and methods)
from another class if that class is specified to the right of the Inherits keyword. We discuss
inheritance in detail in Chapter 9, Object-Oriented Programming: Inheritance.
FrmMaximum contains two programmer-defined methods. Method Maximum (lines
39–43) takes three Double parameters and returns the value of the largest parameter. Note
that this method definition looks just like the definition of a Function procedure in a
module. The program also includes method cmdMaximum_Click (lines 26–36). When
the user double-clicks a component, such as a Button, in Design mode, the IDE generates
a method that Handles an event (i.e., an event handler). An event represents a user
action, such as clicking a Button or altering a value. An event handler is a method that is
executed (called) when a certain event is raised (occurs). In this case, method
cmdMaximum_Click handles the event in which Button cmdMaximum is clicked.
Programmers write code to perform certain tasks when such events occur. By employing
both events and objects, programmers can create applications that enable more sophisticated
user interactions than those we have seen previously. Event-handler names created
by the IDE begin with the object’s name, followed by an underscore and the name of the
event. We explain how to create our own event handlers, which can be given any name, in
Chapter 12, Graphical User Interface Concepts: Part 1.
When the user clicks cmdMaximum, procedure cmdMaximum_Click (lines 26–36)
executes. Lines 31–33 retrieve the values in the three TextBoxes, using the Text property.
The values are converted implicitly to type Double and stored in variables value1,
value2 and value3.
Line 35 calls method Maximum (lines 39–43) with the arguments value1, value2
and value3. The values of these arguments are then stored in parameters valueOne,
valueTwo and valueThree in method Maximum. Maximum returns the result of the
expression on line 42, which makes two calls to method Max of the Math class. Method
Max returns the largest of its two Double arguments, meaning the computation in line 42
first compares valueOne and valueTwo, then compares the value returned by the first
method call to valueThree. Calls to methods, such as Math.Max, that are defined in a
class in the FCL must include the class name and the dot (.) operator (also called the
member access operator). However, calls to methods defined in the class that contains the
method call need only specify the method name.
When control returns to method cmdMaximum_Click, line 35 assigns the value
returned by method Maximum to lblMaximum’s Text property, causing it to be displayed
for the user.
Chapter 6 Procedures 193
The reader may notice that typing the opening parenthesis after a method or procedure
name causes Visual Studio to display a window containing the procedure’s argument
names and types. This is the Parameter Info feature (Fig. 6.5) of the IDE. Parameter Info
greatly simplifies coding by identifying accessible procedures and their arguments. The
Parameter Info feature displays information for programmer-defined procedures and all
methods contained in the FCL.
Good Programming Practice 6.4
Selecting descriptive parameter names makes the information provided by the Parameter Info
feature more meaningful. 6.4
Visual Basic also provides the IntelliSense feature, which displays all the members in
a class. For instance, when the programmer types the dot (.) operator (also called the
member access operator) after the class name, Math, in Fig. 6.6, IntelliSense provides a
list of all the available methods in class Math. The Math class contains numerous methods
that allow the programmer to perform a variety of common mathematical calculations.
Fig. 6.5 Parameter Info feature of the Visual Studio .NET IDE.
Fig. 6.6 IntelliSense feature of the Visual Studio .NET IDE.
Parameter Info window
194 Procedures Chapter 6
As an example of the variety of FCL methods, some Math class methods are summarized
in Fig. 6.7. Throughout the table, the variables x and y are of type Double; however,
many of the methods also provide versions that take values of other data types as arguments.
In addition, the Math class also defines two mathematical constants: Math.PI and
Math.E. The constant Math.PI (3.14159265358979323846) of class Math is the
ratio of a circle’s circumference to its diameter (i.e., twice the radius). The constant
Math.E (2.7182818284590452354) is the base value for natural logarithms (calculated
with the Math.Log method).
Common Programming Error 6.6
Failure to invoke a Math class method by preceding the method name with the class name
Math and a dot operator (.) is a syntax error. 6.6
Method Description Example
Abs(x) returns the absolute value of x Abs(23.7) is 23.7
Abs(0) is 0
Abs(-23.7) is 23.7
Ceiling(x) rounds x to the smallest integer
not less than x
Ceiling(9.2) is 10.0
Ceiling(-9.8) is -9.0
Cos(x) returns the trigonometric cosine
of x (x in radians)
Cos(0.0) is 1.0
Exp(x) returns the exponential ex Exp(1.0) is approximately
2.71828182845905
Exp(2.0) is approximately
7.38905609893065
Floor(x) rounds x to the largest integer
not greater than x
Floor(9.2) is 9.0
Floor(-9.8) is -10.0
Log(x) returns the natural logarithm of
x (base e)
Log(2.7182818284590451)
is approximately 1.0
Log(7.3890560989306504)
is approximately 2.0
Max(x, y) returns the larger value of x and
y (also has versions for
Single, Integer and Long
values)
Max(2.3, 12.7) is 12.7
Max(-2.3, -12.7) is -2.3
Min(x, y) returns the smaller value of x
and y (also has versions for
Single, Integer and Long
values)
Min(2.3, 12.7) is 2.3
Min(-2.3, -12.7) is -12.7
Pow(x, y) calculates x raised to power y
(xy)
Pow(2.0, 7.0) is 128.0
Pow(9.0, .5) is 3.0
Sin(x) returns the trigonometric sine of
x (x in radians)
Sin(0.0) is 0.0
Fig. 6.7 Math class methods (part 1 of 2).
Chapter 6 Procedures 195
Software Engineering Observation 6.9
It is not necessary to add an assembly reference to use the Math class methods in a program,
because class Math is located in namespace System, which is implicitly added to all console
applications. 6.9
6.6 Argument Promotion
An important feature of procedure definitions is the coercion of arguments (i.e., the forcing
of arguments to the appropriate data type so that they can be passed to a procedure). Visual
Basic supports both widening and narrowing conversions. Widening conversion occurs
when a type is converted to another type (usually one that can hold more data) without losing
data, whereas a narrowing conversion occurs when there is potential for data loss during
the conversion (usually to a type that holds a smaller amount of data). Figure 6.8 lists
the widening conversions supported by Visual Basic.
For example, the Math class method Sqrt can be called with an Integer argument,
even though the method is defined in the Math class to receive a Double argument. The
statement
Console.Write(Math.Sqrt(4))
correctly evaluates Math.Sqrt(4) and prints the value 2. Visual Basic promotes (i.e.,
converts) the Integer value 4 to the Double value 4.0 before the value is passed to
Math.Sqrt. In this case, the argument value does not correspond precisely to the parameter
type in the method definition, so an implicit widening conversion changes the value to
the proper type before the method is called. Visual Basic also performs narrowing conversions
on arguments passed to procedures. For example, if String variable number contains
the value “4”, the method call Math.Sqrt(number) correctly evaluates to 2.
However, some implicit narrowing conversions can fail, resulting in runtime errors and
logic errors. For example, if number contains the value “hello”, passing it as an argument
to method Math.Sqrt causes a runtime error. In the next section, we discuss some
measures the programmer can take to help avoid such issues.
Common Programming Error 6.7
When performing a narrowing conversion (e.g., Double to Integer), conversion of a
primitive-data-type value to another primitive data type might change the value. Also, the
conversion of any integral value to a floating-point value and back to an integral value could
introduce rounding errors into the result. 6.7
Sqrt(x) returns the square root of x Sqrt(9.0) is 3.0
Sqrt(2.0) is 1.4142135623731
Tan(x) returns the trigonometric
tangent of x (x in radians)
Tan(0.0) is 0.0
Method Description Example
Fig. 6.7 Math class methods (part 2 of 2).
196 Procedures Chapter 6
Argument promotion applies not only to primitive data-type values passed as arguments
to methods, but also to expressions containing values of two or more data types. Such expressions
are referred to as mixed-type expressions. In a mixed-type expression, each value is promoted
to the “highest” data type in the expression (i.e., widening conversions are made until
the values are of the same type). For example, if singleNumber is of type Single and
integerNumber is of type Integer, when Visual Basic evaluates the expression
singleNumber + integerNumber
the value of integerNumber is converted to type Single, then added to single-
Number, producing a Single result. Although the values’ original data types are maintained,
a temporary version of each value is created for use in the expression, and the data
types of the temporary versions are modified appropriately.
6.7 Option Strict and Data-Type Conversions
Visual Basic provides several options for controlling the way the compiler handles data
types. These options can help programmers eliminate such errors as those caused by narrowing
conversions, making code more reliable and secure. The first option is Option
Explicit, which is set to On by default, meaning it was enabled in the Visual Basic programs
created in Chapters 2–5. Option Explicit forces the programmer to declare explicitly
all variables before they are used in a program. Forcing explicit declarations
eliminates spelling errors and other subtle errors that may occur if Option Explicit is
turned off. For example, when Option Explicit is set to Off, the compiler interprets
misspelled variable names as new variable declarations, which create subtle errors that can
be difficult to debug.
A second option, which is by default set to Off, is Option Strict. Visual Basic provides
Option Strict as a means to increase program clarity and reduce debugging time.
Type Conversion Types
Boolean Object
Byte Short, Integer, Long, Decimal, Single, Double or Object
Char String or Object
Date Object
Decimal Single, Double or Object
Double Object
Integer Long, Decimal, Single, Double or Object
Long Decimal, Single, Double or Object
Object none
Short Integer, Long, Decimal, Single, Double or Object
Single Double or Object
String Object
Fig. 6.8 Widening conversions.
Chapter 6 Procedures 197
When set to On, Option Strict causes the compiler to check all conversions and
requires the programmer to perform an explicit conversion for all narrowing conversions
that could cause data loss (e.g., conversion from Double to Integer) or program termination
(e.g., conversion of a String, such as “hello”, to type Integer).
The methods in class Convert change data types explicitly. The name of each conversion
method is the word To, followed by the name of the data type to which the method
converts its argument. For instance, to store a String input by the user in variable
number of type Integer (represented in Visual Basic .NET as type Int32, a 32-bit
integer) with Option Strict set to On, we use the statement
number = Convert.ToInt32(Console.ReadLine())
When Option Strict is set to Off, Visual Basic performs such type conversions
implicitly, meaning the programmer might not realize that a narrowing conversion is being
performed. If the data being converted is incompatible with the new data type, a runtime
error occurs. Option Strict draws the programmer’s attention to narrowing conversions
so that they can be eliminated or handled properly. In Chapter 11, Exception Handling,
we discuss how to handle the errors caused by failed narrowing conversions.
Software Engineering Observation 6.10
Performing explicit conversions allows programs to execute more efficiently by eliminating the
need to determine the data type of the value being changed before the conversion executes. 6.10
From this point forward, all code examples have Option Strict set to On.
Option Strict can be activated through the IDE by right-clicking the project name in
the Solution Explorer. From the resulting menu, select Properties to open the Property
Pages dialog Fig. 6.9. From the directory tree on the left side of the dialog, select
Build from the Common Properties list. In the middle of the dialog is a drop-down box
labeled Option Strict:. By default, the option is set to Off. Choose On from the dropdown
box and press Apply.
Fig. 6.9 Property Pages dialog with Option Strict set to On.
198 Procedures Chapter 6
Setting Option Strict to On in the Property Pages applies the change globally,
to the entire project. The programmer also can enable Option Strict within an individual
code file by typing Option Strict On at the start of the file above any declarations
or Imports statements.
6.8 Value Types and Reference Types
In the next section, we discuss passing arguments to procedures by value and by reference.
To understand this, we first need to make a distinction between data types in Visual Basic.
All Visual Basic data types can be categorized as either value types or reference types. A
variable of a value type contains data of that type. Normally, value types are used for a single
piece of data, such as an Integer or a Double value. By contrast, a variable of a
reference type (sometimes called a reference) contains a location in memory where data is
stored. The location in memory can contain many individual pieces of data. Collectively,
reference types are known as objects and are discussed in detail in Chapters 8, 9 and 10,
Object-Based Programming, Object-Oriented Programming: Inheritance, and Object-Oriented
Programming: Polymorphism.
Both value types and reference types include built-in types and types that the programmer
can create. The built-in value types include the integral types (Byte, Short,
Integer and Long), the floating-point types (Single and Double) and types
Boolean, Date, Decimal and Char. The built-in reference types include Object and
String (although type String often behaves more like a value type, as we discuss in
the next section). The value types that can be constructed by the programmer include
Structures and Enumerations. The reference types that can be created by the programmer
include classes, interfaces and delegates. Programmer-defined types are discussed
in greater detail in Chapter 8, Object-Based Programming, Chapter 9, Object-
Oriented Programming: Inheritance and Chapter 15, Strings, Characters and Regular
Expressions.
The table in Fig. 6.10 lists the primitive data types, which form the building blocks for
more complicated types, such as classes. If Option Explicit is set to On, all variables
must have a type before they can be used in a program. This requirement is referred to as
strong typing.
Type
Size
in bits Values Standard
Boolean 16 True or False
Char 16 One Unicode character (Unicode character set)
Byte 8 0 to 255
Date 64 1 January 0001 to 31 December 9999
0:00:00 to 23:59:59
Decimal 128 1.0E-28 to 7.9E+28
Short 16 –32,768 to 32,767
Fig. 6.10 Visual Basic primitive data types (part 1 of 2).
Chapter 6 Procedures 199
Each value type in the table is accompanied by its size in bits (there are 8 bits to a byte)
and its range of values. To promote portability, Microsoft chose to use internationally recognized
standards for both character formats (Unicode) and floating-point numbers (IEEE
754). We discuss the Unicode character formats in Appendix F, Unicode.
Values typed directly in program code are called literals. Each literal corresponds to
one of the primitive data types. We already have seen literals for commonly-used types,
such as String, Integer and Double. However, some of Visual Basic’s data types use
special notations for creating literals. For instance, to create a literal of type Char, follow
a single-character String with the type character c. The statement
Dim character As Char = “Z”c
declares Char variable character and initializes it to the “Z” character.
Similarly, literals of specific integral data types can be created by following an integer
with the type character S (for Short), I (for Integer) or L (for Long). To create
floating-point literals, follow a floating-point number with type character F (for Single)
or R (for Double). Type character D can be used to create Decimal literals.
Visual Basic also allows programmers to type floating-point literals in scientific notation,
by following a floating-point number by the character E and a positive or negative
exponent of 10. For example, 1.909E-5 corresponds to the value 0.00001909. This
notation is useful for specifying floating-point values that are too large or too small to be
written in fixed-point notation.
Figure 6.11 displays Visual Basic’s type characters and examples of literals for each
data type. All literals must be within the range for the literal’s type, as specified in Fig. 6.10.
Integer 32 –2,147,483,648 to
2,147,483,647
Long 64 –9,223,372,036,854,775,808
to 9,223,372,036,854,775,807
Single 32 ±1.5E-45 to ±3.4E+38 (IEEE 754 floating point)
Double 64 ±5.0E–324 to ±1.7E+308 (IEEE 754 floating point)
Object 32 Data of any type
String 0 to ~2000000000 Unicode characters (Unicode character set)
Type
Size
in bits Values Standard
Fig. 6.10 Visual Basic primitive data types (part 2 of 2).
Type Type character Example
Char c “u”c
Single F 9.802E+31F
Fig. 6.11 Literals with type characters (part 1 of 2).
200 Procedures Chapter 6
6.9 Passing Arguments: Pass-by-Value vs. Pass-by-Reference
Arguments are passed in one of two ways: Pass-by-value and pass-by-reference (also
called call-by-value and call-by-reference). When an argument is passed by value, the program
makes a copy of the argument’s value and passes that copy to the called procedure.
With pass-by-value, changes to the called procedure’s copy do not affect the original variable’s
value. In contrast, when an argument is passed by reference, the caller gives the
called procedure the ability to access and modify the caller’s original data directly.
Figure 6.12 demonstrates passing value-type arguments by value and by reference.1
The program passes three value-type variables, number1, number2 and number3, in
different ways to procedures SquareByValue (lines 39–45) and SquareByReference
(lines 48–54). Keyword ByVal in the procedure header of SquareByValue (line 39) indicates
that value-type arguments should be passed by value. When number1 is passed to
SquareByValue (line 13), a copy of the value stored in number1 (i.e., 2) is passed to the
procedure. Therefore, the value of number1 in the calling procedure, Main, is not modified
when parameter number is squared in procedure SquareByValue (line 42).
Procedure SquareByReference uses keyword ByRef (line 48) to receive its
value-type parameter by reference. When Main calls SquareByReference (line 23),
a reference to the value stored in number2 is passed, which gives SquareByReference
direct access to the value stored in the original variable. Thus, the value stored in
number2 after SquareByReference finishes executing is the same as the final value
of parameter number.
When arguments are enclosed in parentheses, (), a copy of the value of the argument
is passed to the procedure, even if the procedure header includes keyword ByRef. Thus,
the value of number3 does not change after it is passed to SquareByReference (line
33) via parentheses.
Passing value-type arguments with keyword ByRef is useful when procedures need
to alter argument values directly. However, passing by reference can weaken security,
because the called procedure can modify the caller’s data.
Reference-type variables passed with keyword ByVal are effectively passed by reference,
as the value that is copied is the reference for the object. Although Visual Basic
allows programmers to use keyword ByRef with reference-type parameters, it is usually
Double R 6.04E-187R
Decimal D 128309.76D
Short S 3420S
Integer I -867I
Long L 19235827493259374L
1. In Chapter 7 we discuss passing reference-type arguments by value and by reference.
Type Type character Example
Fig. 6.11 Literals with type characters (part 2 of 2).
Chapter 6 Procedures 201
not necessary to do so except with type String. Although they technically are reference
types, String arguments cannot be modified directly when passed with keyword ByVal,
due to some subtle details of the String data type, which we discuss in Chapter 15,
Strings, Characters and Regular Expressions.
1 ‘ Fig. 6.12: ByRefTest.vb
2 ‘ Demonstrates passing by reference.
34
Module modByRefTest
56
‘ squares three values ByVal and ByRef, displays results
7 Sub Main()
8 Dim number1 As Integer = 2
9
10 Console.WriteLine(“Passing a value-type argument by value:”)
11 Console.WriteLine(“Before calling SquareByValue, ” & _
12 “number1 is {0}”, number1)
13 SquareByValue(number1) ‘ passes number1 by value
14 Console.WriteLine(“After returning from SquareByValue, ” & _
15 “number1 is {0}” & vbCrLf, number1)
16
17 Dim number2 As Integer = 2
18
19 Console.WriteLine(“Passing a value-type argument” & _
20 ” by reference:”)
21 Console.WriteLine(“Before calling SquareByReference, ” & _
22 “number2 is {0}”, number2)
23 SquareByReference(number2) ‘ passes number2 by reference
24 Console.WriteLine(“After returning from ” & _
25 “SquareByReference, number2 is {0}” & vbCrLf, number2)
26
27 Dim number3 As Integer = 2
28
29 Console.WriteLine(“Passing a value-type argument” & _
30 ” by reference, but in parentheses:”)
31 Console.WriteLine(“Before calling SquareByReference ” & _
32 “using parentheses, number3 is {0}”, number3)
33 SquareByReference((number3)) ‘ passes number3 by value
34 Console.WriteLine(“After returning from ” & _
35 “SquareByReference, number3 is {0}”, number3)
36
37 End Sub ‘ Main
38
39 ‘ squares number by value (note ByVal keyword)
40 Sub SquareByValue(ByVal number As Integer)
41 Console.WriteLine(“After entering SquareByValue, ” & _
42 “number is {0}”, number)
43 number *= number
44 Console.WriteLine(“Before exiting SquareByValue, ” & _
45 “number is {0}”, number)
46 End Sub ‘ SquareByValue
47
Fig. 6.12 ByVal and ByRef used to pass value-type arguments (part 1 of 2).
202 Procedures Chapter 6
Testing and Debugging Tip 6.3
When passing arguments by value, changes to the called procedure’s copy do not affect the
original variable’s value. This prevents possible side effects that could hinder the development
of correct and reliable software systems. Always pass value-type arguments by value
unless you explicitly intend for the called procedure to modify the caller’s data. 6.3
Software Engineering Observation 6.11
Although keywords ByVal and ByRef may be used to pass reference-type variables by value
or by reference, the called procedure can manipulate the caller’s reference-type variable
directly in both cases. Therefore, it is rarely appropriate to use ByRef with reference-type
variables. We discuss this subtle issue in detail in Chapter 7, Arrays. 6.11
6.10 Duration of Identifiers
Throughout the earlier chapters of this book, we have used identifiers for various purposes,
including as variable names and as the names of user-defined procedures, modules and
classes. Every identifier has certain attributes, including duration and scope.
An identifier’s duration (also called its lifetime) is the period during which the identifier
exists in memory. Some identifiers exist briefly, some are created and destroyed repeatedly,
yet others are maintained through the entire execution of a program.
48 ‘ squares number by reference (note ByRef keyword)
49 Sub SquareByReference(ByRef number As Integer)
50 Console.WriteLine(“After entering SquareByReference” & _
51 “, number is {0}”, number)
52 number *= number
53 Console.WriteLine(“Before exiting SquareByReference” & _
54 “, number is {0}”, number)
55 End Sub ‘ SquareByReference
56
57 End Module ‘ modByRefTest
Passing a value-type argument by value:
Before calling SquareByValue, number1 is 2
After entering SquareByValue, number is 2
Before exiting SquareByValue, number is 4
After returning from SquareByValue, number1 is 2
Passing a value-type argument by reference:
Before calling SquareByReference, number2 is 2
After entering SquareByReference, number is 2
Before exiting SquareByReference, number is 4
After returning from SquareByReference, number2 is 4
Passing a value-type argument by reference, but in parentheses:
Before calling SquareByReference using parentheses, number3 is 2
After entering SquareByReference, number is 2
Before exiting SquareByReference, number is 4
After returning from SquareByReference, number3 is 2
Fig. 6.12 ByVal and ByRef used to pass value-type arguments (part 2 of 2).
Chapter 6 Procedures 203
Software Engineering Observation 6.12
When returning information from a Function procedure via a Return statement, valuetype
variables always are returned by value (i.e., a copy is returned), whereas reference-type
variables always are returned by reference (i.e., a reference to an object is returned). 6.12
The scope of an identifier is the portion of a program in which the variable’s identifier
can be referenced. Some identifiers can be referenced throughout a program; others can be
referenced only from limited portions of a program (such as within a single procedure). This
section discusses the duration of identifiers. Section 6.11 discusses the scope of identifiers.
Identifiers that represent local variables in a procedure (i.e., parameters and variables
declared in the procedure body) have automatic duration. Automatic-duration variables are
created when program control enters the procedure in which they are declared, exist while
the procedure is active and are destroyed when the procedure is exited.2 For the remainder
of the text, we refer to variables of automatic duration simply as automatic variables, or
local variables.
Variables declared inside a module or class, but outside any procedure definition, exist
as long as their containing class or module is loaded in memory. Variables declared in a
module exist throughout a program’s execution. By default, a variable declared in a class,
such as a Form class for a Windows application, is an instance variable. In the case of a
Form, this means that the variable is created when the Form loads and exists until the
Form is closed. We discuss instance variables in detail in Chapter 8, Object-Based Programming.
Software Engineering Observation 6.13
Automatic duration is an example of the principle of least privilege. This principle states that
each component of a system should have only the rights and privileges it needs to accomplish
its designated task. This helps prevent accidental and/or malicious errors from occurring in
systems. Why have variables stored in memory and accessible when they are not needed? 6.13
6.11 Scope Rules
The scope (sometimes called declaration space) of a variable, reference or procedure identifier
is the portion of the program in which the identifier can be accessed. The possible
scopes for an identifier are class scope, module scope, namespace scope and block scope.
Members of a class have class scope, which means that they are visible in what is
known as the declaration space of a class. Class scope begins at the class identifier after
keyword Class and terminates at the End Class statement. This scope enables a method
of that class to invoke directly all members defined in that class and to access members
inherited into that class.3 In a sense, members of a class are global to the methods of the
class in which they are defined. This means that the methods can modify instance variables
of the class (i.e., variables declared in the class definition, but outside any method definition)
directly and invoke other methods of the class.
2. Variables in a procedure can also be declared using keyword Static, in which case the variable
is created and initialized during the first execution of the procedure then maintains its value between
subsequent calls to the procedure.
3. In Chapter 8, Object-Based Programming, we see that Shared members are an exception to this
rule.
204 Procedures Chapter 6
In Visual Basic .NET, identifiers declared inside a block, such as the body of a procedure
definition or the body of an If/Then selection structure, have block scope (local-variable
declaration space). Block scope begins at the identifier’s declaration and ends at the block’s
End statement (or equivalent, e.g., Next). Local variables of a procedure have block scope.
Procedure parameters also have block scope, because they are considered local variables of
the procedure. Any block can contain variable declarations. When blocks are nested in a body
of a procedure, an error is generated if an identifier declared in an outer block has the same
name as an identifier declared in an inner block. However, if a local variable in a called procedure
shares its name with a variable with class scope, such as an instance variable, the classscope
variable is “hidden” until the called procedure terminates execution.
Variables declared in a module have module scope, which is similar to class scope.
Variables declared in a module are accessible to all procedures defined in the module.
Module scope and class scope are sometimes referred to collectively as module scope. Like
class-scope variables, module-scope variables are hidden when they have the same identifier
as a local variable.
By default, procedures defined in a module have namespace scope, which generally
means that they may be accessed throughout a project. Namespace scope is useful in
projects that contain multiple pieces (i.e., modules and classes). If a project contains a
module and a class, methods in the class can access the procedures of the module. Although
variables declared in a module have module scope, they can be given namespace scope by
replacing keyword Dim with keyword Public in the declaration. We discuss how to add
modules to projects in Section 6.18.
Good Programming Practice 6.5
Avoid local-variable names that hide class-variable or module-variable names. 6.5
The program in Fig. 6.13 demonstrates scoping issues with instance variables and local
variables. Instance variable value is declared and initialized to 1 in line 12. As explained
previously, this variable is hidden in any procedure that declares a variable named value.
The FrmScoping_Load method declares a local variable value (line 19) and initializes
it to 5. This variable is displayed on lblOutput (note the declaration on line 7, which is
actually part of the Visual Studio .NET generated code) to illustrate that the instance variable
value is hidden in FrmScoping_Load.
1 ‘ Fig. 6.13: Scoping.vb
2 ‘ Demonstrates scope rules and instance variables.
34
Public Class FrmScoping
5 Inherits System.Windows.Forms.Form
67
Friend WithEvents lblOutput As System.Windows.Forms.Label
89
‘ Visual Studio .NET generated code
10
11 ‘ instance variable can be used anywhere in class
12 Dim value As Integer = 1
13
Fig. 6.13 Scoping rules in a class (part 1 of 2).
Chapter 6 Procedures 205
14 ‘ demonstrates class scope and block scope
15 Private Sub FrmScoping_Load(ByVal sender As System.Object, _
16 ByVal e As System.EventArgs) Handles MyBase.Load
17
18 ‘ variable local to FrmScoping_Load hides instance variable
19 Dim value As Integer = 5
20
21 lblOutput.Text = “local variable value in” & _
22 ” FrmScoping_Load is ” & value
23
24 MethodA() ‘ MethodA has automatic local value
25 MethodB() ‘ MethodB uses instance variable value
26 MethodA() ‘ MethodA creates new automatic local value
27 MethodB() ‘ instance variable value retains its value
28
29 lblOutput.Text &= vbCrLf & vbCrLf & “local variable ” & _
30 “value in FrmScoping_Load is ” & value
31 End Sub ‘ FrmScoping_Load
32
33 ‘ automatic local variable value hides instance variable
34 Sub MethodA()
35 Dim value As Integer = 25 ‘ initialized after each call
36
37 lblOutput.Text &= vbCrLf & vbCrLf & “local variable ” & _
38 “value in MethodA is ” & value & ” after entering MethodA”
39 value += 1
40 lblOutput.Text &= vbCrLf & “local variable ” & _
41 “value in MethodA is ” & value & ” before exiting MethodA”
42 End Sub ‘ MethodA
43
44 ‘ uses instance variable value
45 Sub MethodB()
46 lblOutput.Text &= vbCrLf & vbCrLf & “instance variable” & _
47 ” value is ” & value & ” after entering MethodB”
48 value *= 10
49 lblOutput.Text &= vbCrLf & “instance variable ” & _
50 “value is ” & value & ” before exiting MethodB”
51 End Sub ‘ MethodB
52
53 End Class ‘ FrmScoping
Fig. 6.13 Scoping rules in a class (part 2 of 2).
206 Procedures Chapter 6
The program defines two other methods—MethodA and MethodB—which take no
arguments and return nothing. Each method is called twice from FrmScoping_Load.
MethodA defines local variable value (line 35) and initializes it to 25. When MethodA is
called, the variable is displayed in the label lblOutput, incremented and displayed again
before exiting the method. Automatic variable value is destroyed when MethodA terminates.
Thus, each time this method is called, value must be recreated and reinitialized to 25.
MethodB does not declare any variables. Therefore, when this procedure refers to variable
value, the instance variable value (line 12) is used. When MethodB is called, the
instance variable is displayed, multiplied by 10 and displayed again before exiting the
method. The next time method MethodB is called, the instance variable retains its modified
value, 10 and line 48 causes value (line 12) to become 100. Finally, the program again displays
the local variable value in method FrmScoping_Load to show that none of the
method calls modified this variable value—both methods refer to variables in other scopes.
6.12 Random-Number Generation
We now take a brief and hopefully entertaining diversion into a popular programming application—
simulation and game playing. In this section and the next, we develop a structured
game-playing program that includes multiple methods. The program employs many
of the control structures that we have studied to this point, in addition to introducing several
new concepts.
There is something in the air of a gambling casino that invigorates a wide variety of
people, ranging from the high rollers at the plush mahogany-and-felt craps tables to the
quarter-poppers at the one-armed bandits. Many of these individuals are drawn by the element
of chance—the possibility that luck will convert a pocketful of money into a mountain
of wealth. The element of chance can be introduced into computer applications through
class Random (located in namespace System).
Consider the following statements:
Dim randomObject As Random = New Random()
Dim randomNumber As Integer = randomObject.Next()
The first statement declares randomObject as a reference to an object of type Random.
The value of randomObject is initialized using keyword New, which creates a new instance
of class Random (i.e., a Random object). In Visual Basic, keyword New creates an
object of a specified type and returns the object’s location in memory.
The second statement declares Integer variable randomNumber and assigns it the
value returned by calling Random method Next. We access method Next by following
the reference name, randomObject, by the dot (.) operator and the method name.
Method Next generates a positive Integer value between zero and the constant
Int32.MaxValue (2,147,483,647). If Next produces values at random, every value in
this range has an equal chance (or probability) of being chosen when Next is called. The
values returned by Next are actually pseudo-random numbers, or a sequence of values
produced by a complex mathematical calculation. This mathematical calculation requires a
seed value, which, if different each time the program is run, causes the series of mathematical
calculations to be different as well (so that the numbers generated are indeed random).
When we create a Random object, the current time of day becomes the seed value for the
calculation. Alternatively, we can pass a seed value as an argument in the parentheses after
Chapter 6 Procedures 207
New Random. Passing in the same seed twice results in the same series of random numbers.
Using the current time of day as the seed value is effective, because the time is likely
to change for each Random object we create.
The generation of random numbers often is necessary in a program. However, the
range of values produced by Next (i.e., values between 0–2,147,483,647) often is different
from that needed in a particular application. For example, a program that simulates cointossing
might require only 0 for “heads” and 1 for “tails.” A program that simulates the
rolling of a six-sided die would require random Integers from 1–6. Similarly, a program
that randomly predicts the next type of spaceship (out of four possibilities) that flies across
the horizon in a video game might require random Integers from 1–4.
By passing an argument to method Next as follows
value = 1 + randomObject.Next(6)
we can produce integers in the range 1–6. When a single argument is passed to Next, the
values returned by Next will be in the range from 0 to (but not including) the value of that
argument. This is called scaling. The number 6 is the scaling factor. We shift the range of
numbers produced by adding 1 to our previous result, so that the return values are between
1 and 6, rather than 0 and 5. The values produced by Next are always in the range
x ≤x + randomObject.Next(y) y
Visual Basic simplifies this process by allowing the programmer to pass two arguments
to Next. For example, the above statement also could be written as
value = randomObject.Next(1, 7)
Note that we must use 7 as the second argument to method Next to produce integers
in the range from 1–6. The first argument indicates the minimum value in our desired range,
whereas the second is equal to 1 + the maximum value desired. Thus, the values produced
by this version of Next will always be in the range
x ≤randomObject.Next(x, y) y
In this case, x is the shifting value, and y-x is the scaling factor. Figure 6.14 demonstrates
the use of class Random and method Next by simulating 20 rolls of a six-sided die and
showing the value of each roll in a MessageBox. Note that all the values are in the range
from 1–6, inclusive.
The program in Fig. 6.15 uses class Random to simulate rolling four six-sided dice. We
then use some of the functionality from this program in another example (Fig. 6.16) to demonstrate
that the numbers generated by Next occur with approximately equal likelihood.
In Fig. 6.15, we use event-handling method cmdRoll_Click, which executes whenever
the user clicks cmdRoll, resulting in method DisplayDie being called four times,
once for each Label on the Form. Calling DisplayDie (lines 35–44) causes four dice to
appear as if they are being rolled each time cmdRoll is clicked. Note that, when this program
runs, the dice images do not appear until the user clicks cmdRoll for the first time.
Method DisplayDie specifies the correct image for the face value calculated by
method Next (line 38). Notice that we declare randomObject as an instance variable of
FrmRollDice (line 21). This allows the same Random object to be used each time Disvbhtp2_
208 Procedures Chapter 6
playDie executes. We use the Image property (line 41) to display an image on a label. We
set the property’s value with an assignment statement (lines 41–43). Notice that we specify
the image to display through procedure FromFile in class Image (contained in the
System.Drawing namespace). Method Directory.GetCurrentDirectory
(contained in the System.IO namespace) returns the location of the folder in which the current
project is located, including bin, the directory containing the compiled project files. The
die images must be placed in this folder for the solutions in Fig. 6.15 and Fig. 6.16 to operate
properly. The graphics used in this example and several other examples in this chapter were
created with Adobe® Photoshop™ Elements and are located in the project directory available
on the CD-ROM that accompanies this book and at http://www.deitel.com.
Notice that we must include an Imports directive (line 4) to use classes in
System.IO, but not to use classes in System.Drawing. By default, Windows applications
import several namespaces, including Microsoft.VisualBasic, System,
System.Drawing, System.Windows.Forms and System.Collections. The
se namespaces are imported for the entire project, eliminating the need for Imports directives
in individual project files. Other namespaces can be imported into a project via the
Property Pages dialog (opened by selecting Project > Properties from the menu bar)
in the Imports listing under Common Properties. Some of the namespaces imported
by default are not used in this example. For instance, we do not yet use namespace
System.Collections, which allows programmers to create collections of objects (see
Chapter 24, Data Structures and Collections).
The Windows application in Fig. 6.16 rolls 12 dice to show that the numbers generated
by class Random occur with approximately equal frequencies. The program displays the
cumulative frequencies of each face in a TextBox.
1 ‘ Fig. 6.14: RandomInteger.vb
2 ‘ Generating random integers.
34
Imports System.Windows.Forms
56
Module modRandomInteger
78
Sub Main()
9 Dim randomObject As Random = New Random()
10 Dim randomNumber As Integer
11 Dim output As String = “”
12 Dim i As Integer
13
14 For i = 1 To 20
15 randomNumber = randomObject.Next(1, 7)
16 output &= randomNumber & ” ”
17
18 If i Mod 5 = 0 Then ‘ is i a multiple of 5?
19 output &= vbCrLf
20 End If
21
22 Next
Fig. 6.14 Random integers created by calling method Next of class Random
(part 1 of 2).
Chapter 6 Procedures 209
23
24 MessageBox.Show(output, “20 Random Numbers from 1 to 6”, _
25 MessageBoxButtons.OK, MessageBoxIcon.Information)
26 End Sub ‘ Main
27
28 End Module ‘ modRandomInteger
1 ‘ Fig. 6.15: RollDice.vb
2 ‘ Rolling four dice.
34
Imports System.IO
56
Public Class FrmRollDice
7 Inherits System.Windows.Forms.Form
89
‘ button for rolling dice
10 Friend WithEvents cmdRoll As System.Windows.Forms.Button
11
12 ‘ labels to display die images
13 Friend WithEvents lblDie1 As System.Windows.Forms.Label
14 Friend WithEvents lblDie2 As System.Windows.Forms.Label
15 Friend WithEvents lblDie3 As System.Windows.Forms.Label
16 Friend WithEvents lblDie4 As System.Windows.Forms.Label
17
18 ‘ Visual Studio .NET generated code
19
20 ‘ declare Random object reference
21 Dim randomNumber As Random = New Random()
22
23 ‘ display results of four rolls
24 Private Sub cmdRoll_Click(ByVal sender As System.Object, _
25 ByVal e As System.EventArgs) Handles cmdRoll.Click
26
27 ‘ method randomly assigns a face to each die
28 DisplayDie(lblDie1)
29 DisplayDie(lblDie2)
30 DisplayDie(lblDie3)
31 DisplayDie(lblDie4)
32 End Sub ‘ cmdRoll_Click
33
Fig. 6.15 Demonstrates 4 die rolls (part 1 of 2).
Fig. 6.14 Random integers created by calling method Next of class Random
(part 2 of 2).
210 Procedures Chapter 6
Figure 6.16 contains two screenshots: One on the left that shows the program when the
program initially executes and one on the right that shows the program after the user has
clicked Roll over 200 times. If the values produced by method Next are indeed random,
the frequencies of the face values (1–6) should be approximately the same (as the left
screenshot illustrates).
To show that the die rolls occur with approximately equal likelihood, the program in
Fig. 6.16 has been modified to keep some simple statistics. We declare counters for each of
the possible rolls in line 31. Notice that the counters are instance variables, i.e., variables
with class scope. Lines 60–76 display the frequency of each roll as percentages using the
“P” format code.
As the program output demonstrates, we have utilized function Next to simulate the
rolling of a six-sided die. Over the course of many die rolls, each of the possible faces from
1–6 appears with equal likelihood, or approximately one-sixth of the time. Note that no
Case Else is provided in the Select structure (lines 91–111), because we know that the
values generated are in the range 1–6. In Chapter 7, Arrays, we explain how to replace the
entire Select structure in this program with a single-line statement.
Run the program several times and observe the results. Notice that a different sequence
of random numbers is obtained each time the program is executed, causing the resulting frequencies
to vary.
34 ‘ get a random die image
35 Sub DisplayDie(ByVal dieLabel As Label)
36
37 ‘ generate random integer in range 1 to 6
38 Dim face As Integer = randomNumber.Next(1, 7)
39
40 ‘ load corresponding image
41 dieLabel.Image = Image.FromFile( _
42 Directory.GetCurrentDirectory & “\Images\die” & _
43 face & “.png”)
44 End Sub ‘ DisplayDie
45
46 End Class ‘ FrmRollDice
Fig. 6.15 Demonstrates 4 die rolls (part 2 of 2).
Chapter 6 Procedures 211
1 ‘ Fig. 6.16: RollTwelveDice.vb
2 ‘ Rolling 12 dice with frequency chart.
34
Imports System.IO
56
Public Class FrmRollTwelveDice
7 Inherits System.Windows.Forms.Form
89
‘ labels to display die images
10 Friend WithEvents lblDie1 As System.Windows.Forms.Label
11 Friend WithEvents lblDie2 As System.Windows.Forms.Label
12 Friend WithEvents lblDie3 As System.Windows.Forms.Label
13 Friend WithEvents lblDie4 As System.Windows.Forms.Label
14 Friend WithEvents lblDie5 As System.Windows.Forms.Label
15 Friend WithEvents lblDie6 As System.Windows.Forms.Label
16 Friend WithEvents lblDie7 As System.Windows.Forms.Label
17 Friend WithEvents lblDie8 As System.Windows.Forms.Label
18 Friend WithEvents lblDie9 As System.Windows.Forms.Label
19 Friend WithEvents lblDie10 As System.Windows.Forms.Label
20 Friend WithEvents lblDie11 As System.Windows.Forms.Label
21 Friend WithEvents lblDie12 As System.Windows.Forms.Label
22
23 ‘ displays roll frequencies
24 Friend WithEvents displayTextBox As _
25 System.Windows.Forms.TextBox
26
27 ‘ Visual Studio .NET generated code
28
29 ‘ declarations
30 Dim randomObject As Random = New Random()
31 Dim ones, twos, threes, fours, fives, sixes As Integer
32
33 Private Sub cmdRoll_Click _
34 (ByVal sender As System.Object, _
35 ByVal e As System.EventArgs) Handles cmdRoll.Click
36
37 ‘ assign random faces to 12 dice using DisplayDie
38 DisplayDie(lblDie1)
39 DisplayDie(lblDie2)
40 DisplayDie(lblDie3)
41 DisplayDie(lblDie4)
42 DisplayDie(lblDie5)
43 DisplayDie(lblDie6)
44 DisplayDie(lblDie7)
45 DisplayDie(lblDie8)
46 DisplayDie(lblDie9)
47 DisplayDie(lblDie10)
48 DisplayDie(lblDie11)
49 DisplayDie(lblDie12)
50
51 Dim total As Integer = ones + twos + threes + fours + _
52 fives + sixes
53
Fig. 6.16 Random class used to simulate rolling 12 six-sided dice (part 1 of 3).
212 Procedures Chapter 6
54 Dim output As String
55
56 ‘ display frequencies of faces
57 output = “Face” & vbTab & vbTab & _
58 “Frequency” & vbTab & “Percent”
59
60 output &= vbCrLf & “1” & vbTab & vbTab & ones & _
61 vbTab & vbTab & String.Format(“{0:P}”, ones / total)
62
63 output &= vbCrLf & “2” & vbTab & vbTab & twos & vbTab & _
64 vbTab & String.Format(“{0:P}”, twos / total)
65
66 output &= vbCrLf & “3” & vbTab & vbTab & threes & vbTab & _
67 vbTab & String.Format(“{0:P}”, threes / total)
68
69 output &= vbCrLf & “4” & vbTab & vbTab & fours & vbTab & _
70 vbTab & String.Format(“{0:P}”, fours / total)
71
72 output &= vbCrLf & “5” & vbTab & vbTab & fives & vbTab & _
73 vbTab & String.Format(“{0:P}”, fives / total)
74
75 output &= vbCrLf & “6” & vbTab & vbTab & sixes & vbTab & _
76 vbTab & String.Format(“{0:P}”, sixes / total) & vbCrLf
77
78 displayTextBox.Text = output
79 End Sub ‘ cmdRoll_Click
80
81 ‘ display a single die image
82 Sub DisplayDie(ByVal dieLabel As Label)
83
84 Dim face As Integer = randomObject.Next(1, 7)
85
86 dieLabel.Image = _
87 Image.FromFile(Directory.GetCurrentDirectory & _
88 “\Images\die” & face & “.png”)
89
90 ‘ maintain count of die faces
91 Select Case face
92
93 Case 1
94 ones += 1
95
96 Case 2
97 twos += 1
98
99 Case 3
100 threes += 1
101
102 Case 4
103 fours += 1
104
105 Case 5
106 fives += 1
Fig. 6.16 Random class used to simulate rolling 12 six-sided dice (part 2 of 3).
Chapter 6 Procedures 213
6.13 Example: Game of Chance
One of the most popular games of chance is a dice game known as “craps,” played in casinos
and back alleys throughout the world. The rules of the game are straightforward:
A player rolls two dice. Each die has six faces. Each face contains 1, 2, 3, 4, 5 or 6 spots.
After the dice have come to rest, the sum of the spots on the two upward faces is calculated.
If the sum is 7 or 11 on the first throw, the player wins. If the sum is 2, 3 or 12 on the first
throw (called “craps”), the player loses (i.e., the “house” wins). If the sum is 4, 5, 6, 8, 9 or
10 on the first throw, that sum becomes the player’s “point.” To win, players must continue
rolling the dice until they “make their point” (i.e., roll their point value). The player loses by
rolling a 7 before making the point.
The application in Fig. 6.17 simulates the game of craps.
107
108 Case 6
109 sixes += 1
110
111 End Select
112
113 End Sub ‘ DisplayDie
114
End Class ‘ FrmRollTwelveDice
Fig. 6.16 Random class used to simulate rolling 12 six-sided dice (part 3 of 3).
214 Procedures Chapter 6
Notice that the player must roll two dice on the first and all subsequent rolls. When
executing the application, click the Play button to play the game. The form displays the
results of each roll. The screen captures depict the execution of two games.
Lines 9–21 indicate that this program uses classes PictureBox, Label, Button
and GroupBox from namespace System.Windows.Forms. Although the Windows
Form Designer uses the full name for these classes (e.g., System.Windows.
Forms.PictureBox), we show only the class names for simplicity. Class names
are sufficient in this case, because System.Windows.Forms is imported by default for
Windows applications.
This program introduces several new GUI components. The first, called a GroupBox,
displays the user’s point. A GroupBox is a container used to group related components.
Within the GroupBox pointDiceGroup, we add two PictureBoxes, which are
components that display images. Components are added to a GroupBox by dragging and
dropping a component onto the GroupBox.
Before introducing any method definitions, the program includes several declarations,
including our first Enumeration on lines 26–32 and our first Constant identifiers on lines
35–36. Constant identifiers and Enumerations enhance program readability by providing
descriptive identifiers for numbers or Strings that have special meaning. Constant
identifiers and Enumerations help programmers ensure that values are consistent
throughout a program. Keyword Const creates a single constant identifier; Enumerations
are used to define groups of related constants. In this case, we create Constant identifiers
for the file names that are used throughout the program and create an Enumeration of
descriptive names for the various dice combinations in Craps (i.e., SNAKE_EYES, TREY,
CRAPS, YO_LEVEN and BOX_CARS). Constant identifiers must be assigned constant
values and cannot be modified after they are declared.
1 ‘ Fig 6.17: CrapsGame.vb
2 ‘ Playing a craps game.
34
Imports System.IO
56
Public Class FrmCrapsGame
7 Inherits System.Windows.Forms.Form
89
Friend WithEvents cmdRoll As Button ‘ rolls dice
10 Friend WithEvents cmdPlay As Button ‘ starts new game
11
12 ‘ dice displayed after each roll
13 Friend WithEvents picDie1 As PictureBox
14 Friend WithEvents picDie2 As PictureBox
15
16 ‘ pointDiceGroup groups dice representing player’s point
17 Friend WithEvents pointDiceGroup As GroupBox
18 Friend WithEvents picPointDie1 As PictureBox
19 Friend WithEvents picPointDie2 As PictureBox
20
21 Friend WithEvents lblStatus As Label
22
Fig. 6.17 Craps game using class Random (part 1 of 4).
Chapter 6 Procedures 215
23 ‘ Visual Studio .NET generated code
24
25 ‘ die-roll constants
26 Enum DiceNames
27 SNAKE_EYES = 2
28 TREY = 3
29 CRAPS = 7
30 YO_LEVEN = 11
31 BOX_CARS = 12
32 End Enum
33
34 ‘ file-name and directory constants
35 Const FILE_PREFIX As String = “/images/die”
36 Const FILE_SUFFIX As String = “.png”
37
38 Dim myPoint As Integer
39 Dim myDie1 As Integer
40 Dim myDie2 As Integer
41 Dim randomObject As Random = New Random()
42
43 ‘ begins new game and determines point
44 Private Sub cmdPlay_Click(ByVal sender As System.Object, _
45 ByVal e As System.EventArgs) Handles cmdPlay.Click
46
47 ‘ initialize variables for new game
48 myPoint = 0
49 pointDiceGroup.Text = “Point”
50 lblStatus.Text = “”
51
52 ‘ remove point-die images
53 picPointDie1.Image = Nothing
54 picPointDie2.Image = Nothing
55
56 Dim sum As Integer = RollDice()
57
58 ‘ check die roll
59 Select Case sum
60
61 Case DiceNames.CRAPS, DiceNames.YO_LEVEN
62
63 ‘ disable roll button
64 cmdRoll.Enabled = False
65 lblStatus.Text = “You Win!!!”
66
67 Case DiceNames.SNAKE_EYES, _
68 DiceNames.TREY, DiceNames.BOX_CARS
69
70 cmdRoll.Enabled = False
71 lblStatus.Text = “Sorry. You Lose.”
72
73 Case Else
74 myPoint = sum
75 pointDiceGroup.Text = “Point is ” & sum
Fig. 6.17 Craps game using class Random (part 2 of 4).
216 Procedures Chapter 6
76 lblStatus.Text = “Roll Again!”
77 DisplayDie(picPointDie1, myDie1)
78 DisplayDie(picPointDie2, myDie2)
79 cmdPlay.Enabled = False
80 cmdRoll.Enabled = True
81
82 End Select
83
84 End Sub ‘ cmdPlay_Click
85
86 ‘ determines outcome of next roll
87 Private Sub cmdRoll_Click(ByVal sender As System.Object, _
88 ByVal e As System.EventArgs) Handles cmdRoll.Click
89
90 Dim sum As Integer = RollDice()
91
92 ‘ check outcome of roll
93 If sum = myPoint Then
94 lblStatus.Text = “You Win!!!”
95 cmdRoll.Enabled = False
96 cmdPlay.Enabled = True
97 ElseIf sum = DiceNames.CRAPS Then
98 lblStatus.Text = “Sorry. You Lose.”
99 cmdRoll.Enabled = False
100 cmdPlay.Enabled = True
101 End If
102
103 End Sub ‘ cmdRoll_Click
104
105 ‘ display die image
106 Sub DisplayDie(ByVal picDie As PictureBox, _
107 ByVal face As Integer)
108
109 ‘ assign die image to picture box
110 picDie.Image = _
111 Image.FromFile(Directory.GetCurrentDirectory & _
112 FILE_PREFIX & face & FILE_SUFFIX)
113 End Sub ‘ DisplayDie
114
115 ‘ generate random die rolls
116 Function RollDice() As Integer
117 Dim die1, die2 As Integer
118
119 ‘ determine random integer
120 die1 = randomObject.Next(1, 7)
121 die2 = randomObject.Next(1, 7)
122
123 ‘ display rolls
124 DisplayDie(picDie1, die1)
125 DisplayDie(picDie2, die2)
126
Fig. 6.17 Craps game using class Random (part 3 of 4).
Chapter 6 Procedures 217
After the constant-identifier declarations and the declarations for several instance variables
(lines 38–41), method cmdPlay_Click is defined (lines 44–84). Method
cmdPlay_Click is the event handler for the event cmdPlay.Click (created by
double-clicking cmdPlay in Design mode). In this example, the method’s task is to process
a user’s interaction with Button cmdPlay (which displays the text Play on the user
interface).
When the user clicks the Play button, method cmdPlay_Click sets up a new game
by initializing several values (lines 48–50). Setting the Image property of
picPointDie1 and picPointDie2 to Nothing (lines 53–54) causes the PictureBoxes
to appear blank. Keyword Nothing can be used with reference-type variables
to specify that no object is associated with the variable.
Method cmdPlay_Click executes the game’s opening roll by calling RollDice
(line 56). Internally, RollDice (lines 116–132) generates two random numbers and calls
method DisplayDie (lines 106–113), which loads an appropriate die image on the PictureBox
passed to it.
127 ‘ set values
128 myDie1 = die1
129 myDie2 = die2
130
131 Return die1 + die2
132 End Function ‘ RollDice
133
134 End Class ‘ FrmCrapsGame
Fig. 6.17 Craps game using class Random (part 4 of 4).
GroupBox PictureBoxes (displaying images)
218 Procedures Chapter 6
When RollDice returns, the Select structure (lines 59–82) analyzes the roll
returned by RollDice to determine how play should continue (i.e., by terminating the
game with a win or loss, or by enabling subsequent rolls). Depending on the value of the
roll, the buttons cmdRoll and cmdPlay become either enabled or disabled. Disabling a
Button causes no action to be performed when the Button is clicked. Buttons can be
enabled and disabled by setting the Enabled property to True or False.
If Button cmdRoll is enabled, clicking it invokes method cmdRoll_Click
(lines 87–103), which executes an additional roll of the dice. Method cmdRoll_Click
then analyzes the roll, letting users know whether they won or lost.
6.14 Recursion
In most of the programs we have discussed so far, procedures have called one another in a
disciplined, hierarchical manner. However, in some instances, it is useful to enable procedures
to call themselves. A recursive procedure is a procedure that calls itself either directly
or indirectly (i.e., through another procedure). Recursion is an important topic that is
discussed at length in upper-level computer science courses. In this section and the next,
we present simple examples of recursion.
Prior to examining actual programs containing recursive procedures, we first consider
recursion conceptually. Recursive problem-solving approaches have a number of elements
in common. A recursive procedure is called to solve a problem. The procedure actually
knows how to solve only the simplest case(s), or base case(s). If the procedure is called
with a base case, the procedure returns a result. If the procedure is called with a more complex
problem, the procedure divides the problem into two conceptual pieces; a piece that
the procedure knows how to perform (base case), and a piece that the procedure does not
know how to perform. To make recursion feasible, the latter piece must resemble the original
problem, but be a slightly simpler or smaller version of it. The procedure invokes
(calls) a fresh copy of itself to work on the smaller problem—this is referred to as a recursive
call, or a recursion step. The recursion step also normally includes the keyword
Return, because its result will be combined with the portion of the problem that the procedure
knew how to solve. Such a combination will form a result that will be passed back
to the original caller.
The recursion step executes while the original call to the procedure is still “open” (i.e.,
has not finished executing). The recursion step can result in many more recursive calls, as
the procedure divides each new subproblem into two conceptual pieces. As the procedure
continues to call itself with slightly simpler versions of the original problem, the sequence
of smaller and smaller problems must converge on the base case, so that the recursion can
eventually terminate. At that point, the procedure recognizes the base case and returns a
result to the previous copy of the procedure. A sequence of returns ensues up the line until
the original procedure call returns the final result to the caller. As an example of these concepts,
let us write a recursive program that performs a popular mathematical calculation.
The factorial of a nonnegative integer n, written n! (and read “n factorial”), is the product
n • ( n – 1 ) • ( n – 2 ) • … • 1
with 1! equal to 1, and 0! defined as 1. For example, 5! is the product 5 • 4 • 3 • 2 • 1, which
is equal to 120.
Chapter 6 Procedures 219
The factorial of an integer number greater than or equal to 0 can be calculated iteratively
(nonrecursively) using a For repetition structure, as follows:
Dim counter, factorial As Integer = 1
For counter = number To 1 Step -1
factorial *= counter
Next
We arrive at a recursive definition of the factorial procedure with the following relationship:
n! = n • ( n – 1 )!
For example, 5! is clearly equal to 5 • 4!, as is shown by the following:
5! = 5 • 4 • 3 • 2 • 1
5! = 5 • ( 4 • 3 • 2 • 1 )
5! = 5 • ( 4! )
A recursive evaluation of 5! would proceed as in Fig. 6.18. Figure 6.18a shows how
the succession of recursive calls proceeds until 1! is evaluated to be 1, which terminates the
recursion. Figure 6.18b depicts the values that are returned from each recursive call to its
caller until the final value is calculated and returned.
The program of Fig. 6.19 recursively calculates and prints factorials. (The choice of
the data type Long will be explained soon). The recursive method Factorial (lines 33–
41) first tests (line 35) to determine whether its terminating condition is true (i.e., number
is less than or equal to 1). If number is less than or equal to 1, Factorial returns 1, no
further recursion is necessary, and the method returns. If number is greater than 1, line 38
expresses the problem as the product of number and a recursive call to Factorial, evaluating
the factorial of number – 1. Note that Factorial(number – 1) is a slightly
simpler problem than the original calculation, Factorial(number).
Fig. 6.18 Recursive evaluation of 5!.
5!
5 * 4!
4 * 3!
3 * 2!
2 * 1!
1
(a) Procession of recursive calls (b) Values returned from each recursive call
5!
5 * 4!
4 * 3!
3 * 2!
2 * 1!
1
Final value = 120
5! = 5 * 24 = 120 is returned
4! = 4 * 6 = 24 is returned
3! = 3 * 2 = 6 is returned
2! = 2 * 1 = 2 is returned
1 returned
220 Procedures Chapter 6
Function Factorial (line 33) receives a parameter of type Long and returns a
result of type Long. As is seen in the output window of Fig. 6.19, factorial values escalate
quickly. We choose data type Long to enable the program to calculate factorials greater than
12!. Unfortunately, the values produced by the Factorial method increase at such a rate
that the range of even the Long type is quickly exceeded. This points to a weakness in most
programming languages: They are not easily extended to handle the unique requirements of
various applications, such as the evaluation of large factorials. As we will see in our treatment
of object-oriented programming beginning in Chapter 8, Visual Basic is an extensible language—
programmers with unique requirements can extend the language with new data types
(called classes). For example, a programmer could create a HugeInteger class that would
enable a program to calculate the factorials of arbitrarily large numbers.
1 ‘ Fig. 6.19: Factorial.vb
2 ‘ Calculating factorials using recursion.
34
Public Class FrmFactorial
5 Inherits System.Windows.Forms.Form
67
Friend WithEvents lblEnter As Label ‘ prompts for Integer
8 Friend WithEvents lblFactorial As Label ‘ indicates output
9
10 Friend WithEvents txtInput As TextBox ‘ reads an Integer
11 Friend WithEvents txtDisplay As TextBox ‘ displays output
12
13 Friend WithEvents cmdCalculate As Button ‘ generates output
14
15 ‘ Visual Studio .NET generated code
16
17 Private Sub cmdCalculate_Click(ByVal sender As System.Object, _
18 ByVal e As System.EventArgs) Handles cmdCalculate.Click
19
20 Dim value As Integer = Convert.ToInt32(txtInput.Text)
21 Dim i As Integer
22 Dim output As String
23
24 txtDisplay.Text = “”
25
26 For i = 0 To value
27 txtDisplay.Text &= i & “! = ” & Factorial(i) & vbCrLf
28 Next
29
30 End Sub ‘ cmdCalculate_Click
31
32 ‘ recursively generates factorial of number
33 Function Factorial(ByVal number As Long) As Long
34
35 If number Add Module.]
FrmDiceModuleTest in Fig. 6.26 demonstrates using the modDice procedures to
respond to button clicks. Procedure cmdRollDie1_Click (lines 23–27) rolls a die and
obtains the default image. We call procedures contained in modDice by following the
module name with the dot (.) operator and the procedure name. Using the functionality
provided by modDice, the body of this procedure requires only one statement (line 26).
Thus, we easily can create a similar Button, cmdRollDie2. In this case, procedure
cmdRollDie2_Click (lines 29–34) uses the Optional argument to prefix the image
name and select a different image. Procedure cmdRollTen_Click (lines 36–40) sets the
Text property of lblSum to the result of 10 rolls.
1 ‘ Fig. 6.25: DiceModule.vb
2 ‘ A collection of common dice procedures.
34
Imports System.IO
56
Module modDice
78
Dim randomObject As Random = New Random()
9
10 ‘ rolls single die
11 Function RollDie() As Integer
12 Return randomObject.Next(1, 7)
13 End Function ‘ RollDie
14
15 ‘ die summation procedure
16 Function RollAndSum(ByVal diceNumber As Integer) _
17 As Integer
18
19 Dim i As Integer
20 Dim sum As Integer = 0
21
Fig. 6.25 Module used to define a group of related procedures (part 1 of 2).
232 Procedures Chapter 6
For the program in Fig. 6.26, we add DiceModule.vb to the project to provide access
to the procedures defined in modDice. To include a module in a project, select
File > Add Existing Item…. In the dialog that is displayed, select the module file name
and click Open. By default, a copy the file is added to the project directory unless you specify
to open the module file as a linked file. Once a module has been added to a project, the procedures
contained in the module have namespace scope. By default, procedures with
namespace scope are accessible to all other parts of a project, such as methods in classes and
procedures in other modules. Although it is not necessary, the programmer may place the file
containing the module’s code in the same directory as the other files for the project.
22 For i = 1 To diceNumber
23 sum += RollDie()
24 Next
25
26 Return sum
27 End Function ‘ RollAndSum
28
29 ‘ returns die image
30 Function GetDieImage(ByVal dieValue As Integer, _
31 Optional ByVal baseImageName As String = “die”) _
32 As System.Drawing.Image
33
34 Return Image.FromFile( _
35 Directory.GetCurrentDirectory & _
36 “\Images\” & baseImageName & dieValue & “.png”)
37 End Function ‘ GetDieImage
38
39 End Module ‘ modDice
1 ‘ Fig. 6.26: DiceModuleTest.vb
2 ‘ Demonstrates modDiceModule procedures
34
Imports System.Drawing
56
Public Class FrmDiceModuleTest
7 Inherits System.Windows.Forms.Form
89
Friend WithEvents lblSum As Label ‘ displays 10-roll sum
10
11 Friend WithEvents diceGroup As GroupBox
12
13 ‘ dice images
14 Friend WithEvents picDie1 As PictureBox
15 Friend WithEvents picDie2 As PictureBox
16
17 Friend WithEvents cmdRollDie1 As Button ‘ rolls blue die
18 Friend WithEvents cmdRollTen As Button ‘ simulates 10 rolls
19 Friend WithEvents cmdRollDie2 As Button ‘ rolls red die
Fig. 6.26 Testing the modDice procedures (part 1 of 2).
Fig. 6.25 Module used to define a group of related procedures (part 2 of 2).
Chapter 6 Procedures 233
SUMMARY
• Experience has shown that the best way to develop and maintain a large program is to construct it
from small, manageable pieces. This technique is known as divide and conquer.
• Visual Basic programs consist of many pieces, including modules and classes.
• Modules and classes are composed of smaller pieces called procedures. When procedures are contained
in a class, we refer to them as methods.
• Visual Basic provides many classes and methods in the .NET Framework Class Library (FCL).
This rich collection of features allows programmers to develop robust applications quickly.
• Three types of procedures exist: Sub procedures, Function procedures and event procedures.
• Procedures promote software reusability—the ability to use existing procedures as building blocks
for new programs.
• The first statement of a procedure definition is the procedure header.
20
21 ‘ Visual Studio .NET generated code
22
23 Private Sub cmdRollDie1_Click(ByVal sender As System.Object, _
24 ByVal e As System.EventArgs) Handles cmdRollDie1.Click
25
26 picDie1.Image = modDice.GetDieImage(modDice.RollDie())
27 End Sub ‘ cmdRollDie1_Click
28
29 Private Sub cmdRollDie2_Click(ByVal sender As System.Object, _
30 ByVal e As System.EventArgs) Handles cmdRollDie2.Click
31
32 picDie2.Image = modDice.GetDieImage(modDice.RollDie(), _
33 “redDie”)
34 End Sub ‘ cmdRollDie2_Click
35
36 Private Sub cmdRollTen_Click(ByVal sender As System.Object, _
37 ByVal e As System.EventArgs) Handles cmdRollTen.Click
38
39 lblSum.Text = Convert.ToString(modDice.RollAndSum(10))
40 End Sub ‘ cmdRollTen_Click
41
42 End Class ‘ FrmDiceModuleTest
Fig. 6.26 Testing the modDice procedures (part 2 of 2).
234 Procedures Chapter 6
• The declarations and statements in the procedure definition form the procedure body.
• The procedure header and procedure call must agree with regard to the number, type and order of
arguments.
• The characteristics of Function procedures are similar to those of Sub procedures. However,
Function procedures return a value (i.e., send back a value) to the caller.
• In a Function header, the return type indicates the data type of the result returned from the
Function to its caller.
• Keyword Return, followed by an expression, returns a value from a Function procedure.
• If a Function procedure body does not specify a Return statement, program control returns to
the point at which a procedure was invoked when the End Function keywords are encountered.
• An event represents a user action, such as the clicking of a button or the alteration of a value.
• Calls to methods, such as Math.Max, that are defined in a separate class must include the class
name and the dot (.) operator (also called the member access operator). However, calls to methods
defined in the class that contains the method call need only specify the method name.
• The Parameter Info feature of the IDE identifies accessible procedures and their arguments. Parameter
Info greatly simplifies coding. The Parameter Info feature provides information not only
about programmer-defined procedures, but about all methods contained in the FCL.
• The IntelliSense feature displays all the members in a class.
• Widening conversion occurs when a type is converted to another type (usually one that can hold
more data) without losing data.
• Narrowing conversion occurs when there is potential for data loss during a conversion (usually to
a type that holds a smaller amount of data). Some narrowing conversions can fail, resulting in runtime
errors and logic errors.
• Visual Basic supports both widening and narrowing conversions.
• Option Explicit, which is set to On by default, forces the programmer to declare all variables
explicitly before they are used in a program. Forcing explicit declarations eliminates spelling errors
and other subtle errors that may occur if Option Explicit is turned Off.
• Option Strict, which is set to Off by default, increases program clarity and reduces debugging
time. When set to On, Option Strict requires the programmer to perform all narrowing
conversions explicitly.
• The methods in class Convert changes data types explicitly. The name of each conversion method
is the word To, followed by the name of the data type to which the method converts its argument.
• All data types can be categorized as either value types or reference types. A variable of a value
type contains data of that type. A variable of a reference type contains the location in memory
where the data is stored.
• Both value and reference types include built-in types and types that programmers can create.
• Values typed directly in program code are called literals. Each literal corresponds to one of the
primitive data types. Some of Visual Basic’s data types use special notations, such as type characters,
for creating literals.
• Arguments are passed in one of two ways: Pass-by-value and pass-by-reference (also called callby-
value and call-by-reference).
• When an argument is passed by value, the program makes a copy of the argument’s value and passes
that copy to the called procedure. Changes to the called procedure’s copy do not affect the original
variable’s value.
Chapter 6 Procedures 235
• When an argument is passed by reference, the caller gives the procedure the ability to access and
modify the caller’s original data directly. Pass-by-reference can improve performance, because it
eliminates the need to copy large data items, such as large objects; however, pass-by-reference can
weaken security, because the called procedure can modify the caller’s data.
• By default, the code editor includes keyword ByVal in parameter declarations to indicate that the
parameter is passed by value. In the case of value-type variables, this means that the value stored
in the variable is copied and passed to the procedure, preventing the procedure from accessing the
original value in the variable.
• Value-type arguments enclosed in parentheses, (), are passed by value even if the procedure
header declares the parameter with keyword ByRef.
• An identifier’s duration (also called its lifetime) is the period during which the identifier exists in
memory.
• Identifiers that represent local variables in a procedure (i.e., parameters and variables declared in
the procedure body) have automatic duration. Automatic-duration variables are created when program
control enters the procedure in which they are declared, exist while the procedure is active
and are destroyed when the procedure is exited.
• Variables declared with keyword Static inside a procedure definition have static duration,
meaning they have the same duration as the Class or Module that contains the procedure.
• The scope (sometimes called declaration space) of a variable, reference or procedure identifier is
the portion of the program in which the identifier can be accessed. The possible scopes for an identifier
are class scope, module scope, namespace scope and block scope.
• In Visual Basic .NET, identifiers declared inside a block, such as the body of a procedure definition
or the body of an If selection structure, have block scope. Block scope begins at the identifier’s
declaration and ends at the block’s End statement.
• Procedures in a module have namespace scope, which means that they may be accessed throughout
a project.
• It is possible to create variables with namespace scope by replacing keyword Dim with keyword
Public in the declaration of a variable in a module.
• Constant identifiers and Enumerations enhance program readability by providing descriptive
identifiers for numbers or Strings that have special meaning.
• A recursive procedure is a procedure that calls itself, either indirectly (i.e., through another procedure)
or directly.
• Any problem that can be solved recursively also can be solved iteratively (nonrecursively).
• The element of chance can be introduced into computer applications through class Random (located
in namespace System). Method Next returns a random number.
• Overloading allows the programmer to define several procedures with the same name, as long as
these procedures have different sets of parameters (number of parameters, types of the parameters
and order of the parameters). This allows the programmer to reduce the complexity of the program
and create a more flexible application.
• Overloaded procedures are distinguished by their signatures, which are a combination of the procedure’s
name and parameter types. The compiler uses a logical process known as overload resolution
to determine which procedure should be called.
• Procedure calls cannot be distinguished by return type. A syntax error is generated when two procedures
have the same signature and different return types. However, overloaded procedures with
different signatures can have different return types.
236 Procedures Chapter 6
• Programmers use modules to group related procedures so that they can be reused in other projects.
Modules are similar in many ways to classes; they allow programmers to build reusable components
without a full knowledge of object-oriented programming.
• Once a module has been added to a project, the procedures contained in the module have
namespace scope. By default, procedures with namespace scope are accessible to all other parts of
a project, such as methods in classes and procedures in other modules.
• Visual Basic allows programmers to create procedures that take one or more optional arguments.
When a parameter is declared as optional, the caller has the option of passing that particular argument.
Optional arguments are specified in the procedure header with keyword Optional.
TERMINOLOGY
. (dot operator) infinite recursion
argument to a procedure call inheritance
automatic duration instance variables of a class
automatic initialization of a variable interface
base case invoke
block scope iteration
Button class lifetime of an identifier
ByRef keyword local variable
ByVal keyword Math class method
call-by-reference method
call-by-value method body
calling procedure method call
class method overloading
class scope mixed-type expression
Click event Module
coercion of arguments modularizing a program with procedures
comma-separated list of arguments named constant
complexity theory narrowing conversion
Const keyword nested block
constant identifier nested control structure
control structures in iteration Next method
control structures in recursion optional argument
convergence Optional keyword
declaration overloaded procedure
default argument parameter list
divide-and-conquer approach parentheses
duration of an identifier pass-by-reference
Enum keyword pass-by-value
enumeration precedence
event handling principle of least privilege
exhausting memory procedure
exponential “explosion” of calls procedure body
Factorial method procedure call
Fibonacci series, defined recursively procedure overloading
Function procedure programmer-defined procedure
golden ratio promotions for primitive data types
hierarchical structure Public keyword
infinite loop Random class
Chapter 6 Procedures 237
SELF-REVIEW EXERCISES
6.1 Fill in the blanks in each of the following statements:
a) Procedures in Visual Basic can be defined in and .
b) A procedure is invoked with a .
c) A variable known only within the procedure in which it is defined is called a .
d) The statement in a called Function procedure can be used to pass the value
of an expression back to the calling procedure.
e) A procedure defined with keyword does not return a value.
f) The of an identifier is the portion of the program in which the identifier can
be used.
g) The three ways to return control from a called Sub procedure to a caller are ,
and .
h) The method in class Random produces random numbers.
i) Variables declared in a block or in a procedure’s parameter list are of duration.
j) A procedure that calls itself either directly or indirectly is a procedure.
k) A recursive procedure typically has two components: One that provides a means for the
recursion to terminate by testing for a case, and one that expresses the problem
as a recursive call for a problem slightly simpler than the original call.
l) In Visual Basic, it is possible to have various procedures with the same name that operate
on different types or numbers of arguments. This is called procedure .
m) Local variables declared at the beginning of a procedure have scope, as do
procedure parameters, which are considered local variables of the procedure.
n) Iteration uses a structure.
o) Recursion uses a structure.
p) Recursion achieves repetition through repeated calls.
q) It is possible to define procedures with the same , but different parameter
lists.
r) Recursion terminates when the is reached.
s) The is a comma-separated list containing the declarations of the parameters
received by the called procedure.
t) The is the data type of the result returned from a called Function procedure.
u) An is a signal that is sent when some action takes place, such as a button being
clicked.
6.2 State whether each of the following is true or false. If false, explain why.
a) Math method Abs rounds its parameter to the smallest integer.
recursive evaluation signature
recursive method simulation
reference type software reusability
Return keyword Static duration
return-value type Sub procedure
scaling factor termination test
scientific notation type character
scope of an identifier user-interface event
sequence of random numbers value type
shifting value widening conversion
side effect
238 Procedures Chapter 6
b) Math method Exp is the exponential method that calculates ex.
c) A recursive procedure is one that calls itself.
d) Conversion from type Single to type Double requires a widening conversion.
e) Variable type Char cannot be converted to type Integer.
f) When a procedure recursively calls itself, it is known as the base case.
g) Forgetting to return a value from a recursive procedure when one is needed results in a
logic error.
h) Infinite recursion occurs when a procedure converges on the base case.
i) Visual Basic supports Optional arguments.
j) Any problem that can be solved recursively also can be solved iteratively.
6.3 For the program in Fig. 6.27, state the scope (either class scope or block scope) of each of the
following elements:
a) The variable i.
b) The variable base.
c) The method Cube.
d) The method FrmCubeTest_Load.
e) The variable output.
6.4 Write an application that tests whether the examples of the Math class method calls shown
in Fig. 6.7 actually produce the indicated results.
6.5 Give the procedure header for each of the following:
a) Procedure Hypotenuse, which takes two double-precision, floating-point arguments,
side1 and side2, and returns a double-precision, floating-point result.
b) Procedure Smallest, which takes three integers, x, y and z, and returns an integer.
c) Procedure Instructions, which does not take any arguments and does not return a
value.
d) Procedure IntegerToSingle, which takes an integer argument, number, and returns
a floating-point result.
6.6 Find the error in each of the following program segments and explain how the error can be
corrected:
1 ‘ Fig. 6.27: CubeTest.vb
2 ‘ Printing the cubes of 1-10.
34
Public Class FrmCubeTest
5 Inherits System.Windows.Forms.Form
67
Friend WithEvents lblOutput As Label
89
‘ Visual Studio .NET generated code
10
11 Dim i As Integer
12
13 Private Sub FrmCubeTest_Load(ByVal sender As System.Object, _
14 ByVal e As System.EventArgs) Handles MyBase.Load
15
16 Dim output As String = “”
17
Fig. 6.27 Printing the results of cubing 10 numbers (part 1 of 2).
Chapter 6 Procedures 239
a) Sub General1()
Console.WriteLine(“Inside procedure General1”)
Sub General2()
Console.WriteLine(“Inside procedure General2”)
End Sub ‘ General2
End Sub ‘ General1
b) Function Sum(ByVal x As Integer, ByVal y As Integer) _
As Integer
Dim result As Integer
result = x + y
End Function ‘ Sum
c) Sub Printer1(ByVal value As Single)
Dim value As Single
Console.WriteLine(value)
End Sub ‘ Printer1
d) Sub Product()
Dim a As Integer = 6
Dim b As Integer = 5
Dim result As Integer = a * b
Console.WriteLine(“Result is ” & result)
Return result
End Sub ‘ Product
e) Function Sum(ByVal value As Integer) As Integer
If value = 0 Then
Return 0
Else
value += Sum(value – 1)
End If
End Function ‘ Sum
18 For i = 1 To 10
19 output &= Cube(i) & vbCrLf
20 Next
21
22 lblOutput.Text = output
23 End Sub ‘ FrmCubeTest_Load
24
25 Function Cube(ByVal base As Integer) As Integer
26 Return Convert.ToInt32(base ^ 3)
27 End Function ‘ Cube
28
29 End Class ‘ FrmCubeTest
Fig. 6.27 Printing the results of cubing 10 numbers (part 2 of 2).
240 Procedures Chapter 6
ANSWERS TO SELF-REVIEW EXERCISES
6.1 a) classes, modules. b) procedure call. c) local variable. d) Return. e) Sub. f) scope.
g) Return, Exit Sub, encountering the End Sub statement. h) Next. i) automatic. j) recursive.
k) base. l) overloading. m) block. n) repetition. o) selection. p) procedure. q) name. r) base case. s)
parameter list. t) return-value type. u) event.
6.2 a) False. Math method Abs returns the absolute value of a number. b) True. c) True. d) True.
e) False. Type Char can be converted to type Integer with a narrowing conversion. f) False. A
procedure’s recursively calling itself is known as the recursive call or recursion step. g) True. h) False.
Infinite recursion occurs when a recursive procedure does not converge on the base case. i) True.
j) True.
6.3 a) Class scope. b) Block scope. c) Class scope. d) Class scope. e) Block scope.
6.4 The following code demonstrates the use of some Math library method calls:
1 ‘ Ex. 6.4: MathTest.vb
2 ‘ Testing the Math class methods
34
Module modMathTest
56
Sub Main()
7 Console.WriteLine(“Math.Abs(23.7) = ” & _
8 Convert.ToString(Math.Abs(23.7)))
9 Console.WriteLine(“Math.Abs(0.0) = ” & _
10 Convert.ToString(Math.Abs(0)))
11 Console.WriteLine(“Math.Abs(-23.7) = ” & _
12 Convert.ToString(Math.Abs(-23.7)))
13 Console.WriteLine(“Math.Ceiling(9.2) = ” & _
14 Convert.ToString(Math.Ceiling(9.2)))
15 Console.WriteLine(“Math.Ceiling(-9.8) = ” & _
16 Convert.ToString(Math.Ceiling(-9.8)))
17 Console.WriteLine(“Math.Cos(0.0) = ” & _
18 Convert.ToString(Math.Cos(0)))
19 Console.WriteLine(“Math.Exp(1.0) = ” & _
20 Convert.ToString(Math.Exp(1)))
21 Console.WriteLine(“Math.Exp(2.0) = ” & _
22 Convert.ToString(Math.Exp(2)))
23 Console.WriteLine(“Math.Floor(9.2) = ” & _
24 Convert.ToString(Math.Floor(9.2)))
25 Console.WriteLine(“Math.Floor(-9.8) = ” & _
26 Convert.ToString(Math.Floor(-9.8)))
27 Console.WriteLine(“Math.Log(2.718282) = ” & _
28 Convert.ToString(Math.Log(2.718282)))
29 Console.WriteLine(“Math.Log(7.389056) = ” & _
30 Convert.ToString(Math.Log(7.389056)))
31 Console.WriteLine(“Math.Max(2.3, 12.7) = ” & _
32 Convert.ToString(Math.Max(2.3, 12.7)))
33 Console.WriteLine(“Math.Max(-2.3, -12.7) = ” & _
34 Convert.ToString(Math.Max(-2.3, -12.7)))
35 Console.WriteLine(“Math.Min(2.3, 12.7) = ” & _
36 Convert.ToString(Math.Min(2.3, 12.7)))
37 Console.WriteLine(“Math.Min(-2.3, -12.7) = ” & _
38 Convert.ToString(Math.Min(-2.3, -12.7)))
Chapter 6 Procedures 241
6.5 a) Function Hypotenuse(ByVal side1 As Double, _
ByVal side2 As Double) As Double
b) Function Smallest(ByVal x As Integer, _
ByVal y As Integer, ByVal z As Integer) As Integer
c) Sub Instructions()
d) Function IntegerToSingle(ByVal number As Integer) As Single
6.6 a) Error: Procedure General2 is defined in procedure General1.
Correction: Move the definition of General2 out of the definition of General1.
b) Error: The procedure is supposed to return an Integer, but does not.
Correction: Delete the statement result = x + y and place the following statement in
the method:
39 Console.WriteLine(“Math.Pow(2, 7) = ” & _
40 Convert.ToString(Math.Pow(2, 7)))
41 Console.WriteLine(“Math.Pow(9, .5) = ” & _
42 Convert.ToString(Math.Pow(9, 0.5)))
43 Console.WriteLine(“Math.Sin(0.0) = ” & _
44 Convert.ToString(Math.Sin(0)))
45 Console.WriteLine(“Math.Sqrt(9.0) = ” & _
46 Convert.ToString(Math.Sqrt(9)))
47 Console.WriteLine(“Math.Sqrt(2.0) = ” & _
48 Convert.ToString(Math.Sqrt(2)))
49 Console.WriteLine(“Math.Tan(0.0) = ” & _
50 Convert.ToString(Math.Tan(0)))
51
52 End Sub ‘ Main
53
54 End Module ‘ modMathTest
Math.Abs(23.7) = 23.7
Math.Abs(0.0) = 0
Math.Abs(-23.7) = 23.7
Math.Ceiling(9.2) = 10
Math.Ceiling(-9.8) = -9
Math.Cos(0.0) = 1
Math.Exp(1.0) = 2.71828182845905
Math.Exp(2.0) = 7.38905609893065
Math.Floor(9.2) = 9
Math.Floor(-9.8) = -10
Math.Log(2.718282) = 1.00000006310639
Math.Log(7.389056) = 1.99999998661119
Math.Max(2.3, 12.7) = 12.7
Math.Max(-2.3, -12.7) = -2.3
Math.Min(2.3, 12.7) = 2.3
Math.Min(-2.3, -12.7) = -12.7
Math.Pow(2, 7) = 128
Math.Pow(9, .5) = 3
Math.Sin(0.0) = 0
Math.Sqrt(9.0) = 3
Math.Sqrt(2.0) = 1.4142135623731
Math.Tan(0.0) = 0
242 Procedures Chapter 6
Return x + y
or add the following statement at the end of the method body:
Return result
c) Error: Parameter value is redefined in the procedure definition.
Correction: Delete the declaration Dim value As Single.
d) Error: The procedure returns a value, but is defined as a Sub procedure.
Correction: Change the procedure to a Function procedure with return type Integer.
e) Error: The result of value += Sum(value – 1) is not returned by this recursive method,
resulting in a logic error.
Correction: Rewrite the statement in the Else clause as
Return value + sum(value – 1)
EXERCISES
6.7 What is the value of x after each of the following statements is performed?
a) x = Math.Abs(7.5)
b) x = Math.Floor(7.5)
c) x = Math.Abs(0.0)
d) x = Math.Ceiling(0.0)
e) x = Math.Abs(-6.4)
f) x = Math.Ceiling(-6.4)
g) x = Math.Ceiling(-Math.Abs(-8 + Math.Floor(-5.5)))
6.8 A parking garage charges a $2.00 minimum fee to park for up to three hours. The garage
charges an additional $0.50 per hour for each hour or part thereof in excess of three hours. The maximum
charge for any given 24-hour period is $10.00. Assume that no car parks for longer than 24
hours at a time. Write a program that calculates and displays the parking charges for each customer
who parked a car in this garage yesterday. You should enter in a TextBox the hours parked for each
customer. The program should display the charge for the current customer. The program should use
the method CalculateCharges to determine the charge for each customer. Use the techniques
described in the chapter to read the Double value from a TextBox.
6.9 Write a method IntegerPower(base, exponent) that returns the value of
baseexponent
For example, IntegerPower(3, 4) = 3 * 3 * 3 * 3. Assume that exponent is a positive integer
and that base is an integer. Method IntegerPower should use a For/Next loop or While loop to
control the calculation. Do not use any Math library methods or the exponentiation operator, ^. Incorporate
this method into a Windows application that reads integer values from TextBoxes for base
and exponent from the user and performs the calculation by calling method IntegerPower.
6.10 Define a method Hypotenuse that calculates the length of the hypotenuse of a right triangle
when the other two sides are given. The method should take two arguments of type Double and
return the hypotenuse as a Double. Incorporate this method into a Windows application that reads
integer values for side1 and side2 from TextBoxes and performs the calculation with the Hypotenuse
method. Determine the length of the hypotenuse for each of the following triangles:
Chapter 6 Procedures 243
6.11 Write a method SquareOfAsterisks that displays a solid square of asterisks whose side
is specified in integer parameter side. For example, if side is 4, the method displays
****
****
****
****
Incorporate this method into a Windows application that reads an integer value for side from the
user and performs the drawing with the SquareOfAsterisks method. This method should
gather data from Textboxes and should print to a Label.
6.12 Modify the method created in Exercise 6.11 to form the square out of whatever character is
contained in parameter fillCharacter. Thus, if side is 5 and fillCharacter is “#”, this
method should print
#####
#####
#####
#####
#####
6.13 Write a Windows application that simulates coin tossing. Let the program toss the coin each
time the user presses the Toss button. Count the number of times each side of the coin appears. Display
the results. The program should call a separate method Flip, which takes no arguments and returns
False for tails and True for heads. [Note: If the program simulates the coin
tossing realistically, each side of the coin should appear approximately half the time.]
6.14 Computers are playing an increasing role in education. Write a program that will help an elementary
school student learn multiplication. Use the Next method from an object of type Random
to produce two positive one-digit integers. It should display a question, such as
How much is 6 times 7?
The student should then type the answer into a TextBox. Your program should check the student’s
answer. If it is correct, display “Very good!” in a Label, then ask another multiplication question.
If the answer is incorrect, display “No. Please try again.” in the same Label, then let
the student try the same question again until the student finally gets it right. A separate method
should be used to generate each new question. This method should be called once when the program
begins execution and then each time the user answers a question correctly.
6.15 (Towers of Hanoi) Every budding computer scientist must grapple with certain classic problems;
the Towers of Hanoi (Fig. 6.28) is one of the most famous. Legend has it that, in a temple in
the Far East, priests are attempting to move a stack of disks from one peg to another. The initial stack
had 64 disks threaded onto one peg and arranged from bottom to top by decreasing size. The priests
are attempting to move the stack from this peg to a second peg, under the constraints that exactly one
disk is moved at a time and that at no time may a larger disk be placed above a smaller disk. A third
peg is available for temporarily holding disks. Supposedly, the world will end when the priests complete
their task, so there is little incentive for us to facilitate their efforts.
Triangle Side 1 Side 2
1 3.0 4.0
2 5.0 12.0
3 8.0 15.0
244 Procedures Chapter 6
Let us assume that the priests are attempting to move the disks from peg 1 to peg 3. We wish to
develop an algorithm that prints the precise sequence of peg-to-peg disk transfers.
If we were to approach this problem with conventional techniques, we would find ourselves
hopelessly knotted up in managing the disks. However, if we approach the problem with recursion in
mind, it becomes tractable. Moving n disks can be viewed in terms of moving only n – 1 disks (and
hence, the recursion) as follows:
a) Move n – 1 disks from peg 1 to peg 2, using peg 3 as a temporary holding area.
b) Move the last disk (the largest) from peg 1 to peg 3.
c) Move the n – 1 disks from peg 2 to peg 3, using peg 1 as a temporary holding area.
The process ends when the last task involves moving n = 1 disk (i.e., the base case). This is
accomplished by moving the disk without the need for a temporary holding area.
Write a program to solve the Towers of Hanoi problem. Allow the user to enter the number of
disks in a TextBox. Use a recursive Tower method with four parameters:
a) The number of disks to be moved
b) The peg on which these disks are threaded initially
c) The peg to which this stack of disks is to be moved
d) The peg to be used as a temporary holding area
Your program should display in a TextBox with scrolling functionality the precise instructions
for moving the disks from the starting peg to the destination peg. For example, to move a stack
of three disks from peg 1 to peg 3, your program should print the following series of moves:
1 →3 (This means move one disk from peg 1 to peg 3.)
1 →2
3 →2
1 →3
2 →1
2 →3
1 →3
Fig. 6.28 Towers of Hanoi for the case with four disks.
7
Arrays
Objectives
• To introduce the array data structure.
• To understand how arrays store, sort and search lists
and tables of values.
• To understand how to declare an array, initialize an
array and refer to individual elements of an array.
• To be able to pass arrays to methods.
• To understand basic sorting techniques.
• To be able to declare and manipulate
multi-dimensional arrays.
With sobs and tears he sorted out
Those of the largest size …
Lewis Carroll
Attempt the end, and never stand to doubt;
Nothing’s so hard, but search will find it out.
Robert Herrick
Now go, write it before them in a table,
and note it in a book.
Isaiah 30:8
‘Tis in my memory lock’d,
And you yourself shall keep the key of it.
William Shakespeare
246 Arrays Chapter 7
William Shakespeare
7.1 Introduction
This chapter introduces basic concepts and features of data structures. Arrays are data structures
consisting of data items of the same type. Arrays are “static” entities, in that they remain
the same size once they are created, although an array reference may be reassigned to
a new array of a different size. We begin by discussing constructing and accessing arrays;
we build on this knowledge to conduct more complex manipulations of arrays, including
powerful searching and sorting techniques. We then demonstrate the creation of more sophisticated
arrays that have multiple dimensions. Chapter 24, Data Structures and Collections,
introduces dynamic data structures, such as lists, queues, stacks and trees, which can
grow and shrink as programs execute. This later chapter also presents Visual Basic’s predefined
data structures that enable the programmer to use existing data structures for lists,
queues, stacks and trees, rather than “reinventing the wheel.”
7.2 Arrays
An array is a group of contiguous memory locations that have the same name and the same
type. Array names follow the same conventions that apply to other variable names, as was
discussed in Chapter 3, Introduction to Visual Basic Programming. To refer to a particular
Outline
7.1 Introduction
7.2 Arrays
7.3 Declaring and Allocating Arrays
7.4 Examples Using Arrays
7.4.1 Allocating an Array
7.4.2 Initializing the Values in an Array
7.4.3 Summing the Elements of an Array
7.4.4 Using Arrays to Analyze Survey Results
7.4.5 Using Histograms to Display Array Data Graphically
7.5 Passing Arrays to Procedures
7.6 Passing Arrays: ByVal vs. ByRef
7.7 Sorting Arrays
7.8 Searching Arrays: Linear Search and Binary Search
7.8.1 Searching an Array with Linear Search
7.8.2 Searching a Sorted Array with Binary Search
7.9 Multidimensional Rectangular and Jagged Arrays
7.10 Variable-Length Parameter Lists
7.11 For Each/Next Repetition Structure
Summary • Terminology • Self-Review Exercises • Answers to Self-Review Exercises • Exercises•
Special Section: Recursion Exercises
Chapter 7 Arrays 247
location or element in an array, we specify the name of the array and the position number
of the element to which we refer. Position numbers are values that indicate specific locations
within arrays.
Figure 7.1 depicts an integer array named numberArray. This array contains 12 elements,
any one of which can be referred to by giving the name of the array followed by the
position number of the element in parentheses (). The first element in every array is the
zeroth element. Thus, the first element of array numberArray is referred to as number-
Array(0), the second element of array numberArray is referred to as number-
Array(1), the seventh element of array numberArray is referred to as
numberArray(6) and so on. The ith element of array numberArray is referred to as
numberArray(i – 1).
The position number in parentheses more formally is called an index (or a subscript).
An index must be an integer or an integer expression. If a program uses an expression as an
index, the expression is evaluated first to determine the index. For example, if variable
value1 is equal to 5, and variable value2 is equal to 6, then the statement
numberArray(value1 + value2) += 2
adds 2 to array element numberArray(11). Note that an indexed array name (i.e., the
array name followed by an index enclosed in parentheses) is an lvalue—it can be used on
the left side of an assignment statement to place a new value into an array element.
Fig. 7.1 Array consisting of 12 elements.
Name of array (note
that all elements of this
array have the same
name, numberArray)
Position number (index or
subscript) of the element
within array numberArray
numberArray(0)
numberArray(1)
numberArray(2)
numberArray(3)
numberArray(4)
numberArray(5)
numberArray(6)
numberArray(7)
numberArray(8)
numberArray(9)
numberArray(10)
numberArray(11)
-45
6
0
72
1543
-89
0
62
-3
1
6453
78
248 Arrays Chapter 7
Let us examine array numberArray in Fig. 7.1 more closely. The name of the array
is numberArray. The 12 elements of the array are referred to as numberArray(0)
through numberArray(11). The value of numberArray(0) is -45, the value of
numberArray(1) is 6, the value of numberArray(2) is 0, the value of number-
Array(7) is 62 and the value of numberArray(11) is 78. Values stored in arrays can
be employed in various calculations and applications. For example, to determine the sum
of the values contained in the first three elements of array numberArray and then store
the result in variable sum, we would write
sum = numberArray(0) + numberArray(1) + numberArray(2)
To divide the value of the seventh element of array numberArray by 2 and assign the
result to the variable result, we would write
result = numberArray(6) \ 2
Common Programming Error 7.1
It is important to note the difference between the “seventh element of the array” and “array
element seven.” Array indices begin at 0, which means that the “seventh element of the array”
has the index 6, whereas “array element seven” has the index 7 and is actually the
eighth element of the array. This confusion is a common source of “off-by-one” errors. 7.1
Every array in Visual Basic “knows” its own length. The length of the array (i.e., 12
in this case) is determined by the following expression:
numberArray.Length
All arrays have access to the methods and properties of class System.Array, including
the Length property. For instance, method GetUpperBound returns the index of the
last element in the array. Method GetUpperBound takes one argument indicating a dimension
of the array. We discuss arrays with multiple dimensions in Section 7.9. For onedimensional
arrays, such as numberArray, the argument passed to GetUpperBound
is 0. For example, expression
numberArray.GetUpperBound(0)
returns 11. Notice that the value returned by method GetUpperBound is one less than
the value of the array’s Length property. Classes, objects and class methods are discussed
in detail in Chapter 8, Object-Based Programming.
7.3 Declaring and Allocating Arrays
Arrays occupy space in memory. The amount of memory required by an array depends on
the length of the array and the size of the data type of the elements in the array. The declaration
of an array creates a variable that can store a reference to an array but does not create
the array in memory. To declare an array, the programmer provides the array’s name and
data type. The following statement declares the array in Fig. 7.1:
Dim numberArray As Integer()
Chapter 7 Arrays 249
The parentheses that follow the data type indicate that numberArray is an array.
Arrays can be declared to contain any data type. In an array of primitive data types, every
element of the array contains one value of the declared data type. For example, every element
of an Integer array contains an Integer value.
Before the array can be used, the programmer must specify the size of the array and
allocate memory for the array, using keyword New. Recall from Chapter 6 that keyword
New creates an object. Arrays are represented as objects in Visual Basic, so they too, must
be allocated using keyword New. The value stored in the array variable is actually a reference
to the location in the computer’s memory where the array object is created. All nonprimitive-
type variables are reference variables (normally called references). To allocate
memory for the array numberArray after it has been declared, the statement
numberArray = New Integer(11) {}
is used. In our example, the number 11 defines the upper bound for the array. Array bounds
determine what indices can be used to access an element in the array. Here, the array
bounds are 0 (which is implicit in the preceding statement) and 11, meaning that an index
outside these bounds cannot be used to access elements in the array. Notice that the actual
size of the array is one larger than the upper bound specified in the allocation.
The required braces ({ and }) are called an initializer list and specify the initial values
of the elements in the array. When the initializer list is empty, the elements in the array are
initialized to the default value for the data type of the elements of the array. The default
value is 0 for numeric primitive data-type variables, False for Boolean variables and
Nothing for references. Keyword Nothing denotes an empty reference (i.e., a value
indicating that a reference variable has not been assigned an address in the computer’s
memory). The initializer list also can contain a comma-separated list specifying the initial
values of the elements in the array. For instance,
Dim numbers As Integer()
numbers = New Integer() {1, 2, 3, 6}
declares and allocates an array containing four Integer values. Visual Basic can determine
the array bounds from the number of elements in the initializer list. Thus, it is not necessary
to specify the size of the array when a non-empty initializer list is present.
The allocation of an array can be combined into the declaration, as in the statement
Dim numberArray As Integer() = New Integer(11) {}
Separating the declaration and allocation statements is useful, however, when the size of an
array depends on user input or on values calculated at runtime.
Programmers can declare arrays via several alternative methods, which we discuss
throughout this chapter. For example, several arrays can be declared with a single statement;
the following statement declares two array variables of type Double():
Dim array1, array2 As Double()
7.4 Examples Using Arrays
This section presents several examples that demonstrate the declaration, allocation and initialization
of arrays, as well as various manipulations of array elements. For simplicity, the
250 Arrays Chapter 7
examples in this section use arrays that contain elements of type Integer. Please remember
that a program can declare an array to have elements of any data type.
7.4.1 Allocating an Array
The program of Fig. 7.2 uses keyword New to allocate an array of 10 Integer elements,
which are initially zero (the default value in an array of type Integer). The program displays
the array elements in tabular format in a dialog.
1 ‘ Fig. 7.2: CreateArray.vb
2 ‘ Declaring and allocating an array.
34
Imports System.Windows.Forms
56
Module modCreateArray
78
Sub Main()
9 Dim output As String
10 Dim i As Integer
11
12 Dim array As Integer() ‘ declare array variable
13 array = New Integer(9) {} ‘ allocate memory for array
14
15 output &= “Subscript ” & vbTab & “Value” & vbCrLf
16
17 ‘ display values in array
18 For i = 0 To array.GetUpperBound(0)
19 output &= i & vbTab & array(i) & vbCrLf
20 Next
21
22 output &= vbCrLf & “The array contains ” & _
23 array.Length & ” elements.”
24
25 MessageBox.Show(output, “Array of Integer Values”, _
26 MessageBoxButtons.OK, MessageBoxIcon.Information)
27 End Sub ‘ Main
28
29 End Module ‘ modCreateArray
Fig. 7.2 Creating an array.
Chapter 7 Arrays 251
Line 12 declares array—a variable capable of storing a reference to an array of
Integer elements. Line 13 allocates an array of 10 elements using New and assigns it to
array. The program builds its output in String output. Line 15 appends to output
the headings for the columns displayed by the program. The columns represent the index
for each array element and the value of each array element, respectively.
Lines 18–20 use a For structure to append the index number (represented by i) and
value of each array element (array(i)) to output. Note the use of zero-based counting
(remember, indices start at 0), so that the loop accesses every array element. Also notice,
in the header of the For structure, the expression array.GetUpperBound(0), used
to retrieve the upper bound of the array. The Length property (lines 22–23) returns the
number of elements in the array.
7.4.2 Initializing the Values in an Array
The program of Fig. 7.3 creates two integer arrays of 10 elements each and sets the values
of the elements, using an initializer list and a For structure. The arrays are displayed in tabular
format in a message dialog.
Line 12 uses one statement to declare array1 and array2 as variables that are
capable of referring to arrays of integers. Lines 16–17 allocate the 10 elements of array1
with New and initialize the values in the array, using an initializer list. Line 20 allocates
array2, whose size is determined by the expression array1.GetUpperBound(0),
meaning array1 and array2, in this particular program, have the same upper bound.
1 ‘ Fig. 7.3: InitArray.vb
2 ‘ Initializing arrays.
34
Imports System.Windows.Forms
56
Module modInitArray
78
Sub Main()
9 Dim output As String
10 Dim i As Integer
11
12 Dim array1, array2 As Integer() ‘ declare two arrays
13
14 ‘ initializer list specifies number of elements
15 ‘ and value of each element
16 array1 = New Integer() {32, 27, 64, 18, 95, _
17 14, 90, 70, 60, 37}
18
19 ‘ allocate array2 based on length of array1
20 array2 = New Integer(array1.GetUpperBound(0)) {}
21
22 ‘ set values in array2 by a calculation
23 For i = 0 To array2.GetUpperBound(0)
24 array2(i) = 2 + 2 * i
25 Next
26
Fig. 7.3 Initializing array elements two different ways (part 1 of 2).
252 Arrays Chapter 7
The For structure in lines 23–25 initializes each element in array2. The elements in
array2 are initialized (line 24) to the even integers 2, 4, 6, …, 20. These numbers are
generated by multiplying each successive value of the loop counter by 2 and adding 2 to
the product. The For structure in lines 31–34 uses the values in the arrays to build String
output, which is displayed in a MessageBox (lines 36–37).
7.4.3 Summing the Elements of an Array
Often, the elements of an array represent a series of values that are employed in a calculation.
For example, if the elements of an array represent a group of students’ exam grades, the instructor
might wish to total the elements of the array, then calculate the class average for the
exam. The program in Fig. 7.4 sums the values contained in a 10-element integer array.
27 output &= “Subscript ” & vbTab & “Array1” & vbTab & _
28 “Array2” & vbCrLf
29
30 ‘ display values for both arrays
31 For i = 0 To array1.GetUpperBound(0)
32 output &= i & vbTab & array1(i) & vbTab & array2(i) & _
33 vbCrLf
34 Next
35
36 MessageBox.Show(output, “Array of Integer Values”, _
37 MessageBoxButtons.OK, MessageBoxIcon.Information)
38 End Sub ‘ Main
39
40 End Module ‘ modInitArray
1 ‘ Fig. 7.4: SumArray.vb
2 ‘ Computing sum of elements in array.
34
Imports System.Windows.Forms
56
Module modSumArray
7
Fig. 7.4 Computing the sum of the elements in an array (part 1 of 2).
Fig. 7.3 Initializing array elements two different ways (part 2 of 2).
Chapter 7 Arrays 253
Lines 9–10 declare, allocate and initialize the 10-element array array. Line 16, in the
body of the For structure, performs the addition. Alternatively, the values supplied as initializers
for array could have been read into the program. For example, the user could
enter the values through a TextBox, or the values could be read from a file on disk. Additional
information about reading values into a program can be found in Chapter 17, Files
and Streams.
7.4.4 Using Arrays to Analyze Survey Results
Our next example uses arrays to summarize data collected in a survey. Consider the following
problem statement:
Forty students were asked to rate on a scale of 1 to 10 the quality of the food in the student
cafeteria, with 1 being “awful” and 10 being “excellent”. Place the 40 responses in an integer
array and determine the frequency of each rating.
This exercise represents a typical array-processing application (Fig. 7.5). We wish to
summarize the number of responses of each type (i.e., 1–10). Array responses (lines
14–16) is a 40-element integer array containing the students’ responses to the survey. Using
an 11-element array frequency, we can count the number of occurrences of each
response. We ignore the first element, frequency(0), because it is more logical to have
a survey response of 1 result in frequency(1) being incremented rather than incrementing
frequency(0). We can use each response directly as an index on the frequency
array. Each element of the array is used as a counter for one of the possible types
8 Sub Main()
9 Dim array As Integer() = New Integer() _
10 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
11
12 Dim total As Integer = 0, i As Integer = 0
13
14 ‘ sum array element values
15 For i = 0 To array.GetUpperBound(0)
16 total += array(i)
17 Next
18
19 MessageBox.Show(“Total of array elements: ” & total, _
20 “Sum the elements of an Array”, MessageBoxButtons.OK, _
21 MessageBoxIcon.Information)
22 End Sub ‘ Main
23
24 End Module ‘ modSumArray
Fig. 7.4 Computing the sum of the elements in an array (part 2 of 2).
254 Arrays Chapter 7
of survey responses—frequency(1) counts the number of students who rated the food
as 1, frequency(7) counts the number of students who rated the food 7 and so on.
1 ‘ Fig. 7.5: StudentPoll.vb
2 ‘ Using arrays to display poll results.
34
Imports System.Windows.Forms
56
Module modStudentPoll
78
Sub Main()
9 Dim answer, rating As Integer
10 Dim output As String
11
12 ‘ student response array (typically input at run time)
13 Dim responses As Integer()
14 responses = New Integer() {1, 2, 6, 4, 8, 5, 9, 7, _
15 8, 10, 1, 6, 3, 8, 6, 10, 3, 8, 2, 7, 6, 5, 7, 6, _
16 8, 6, 7, 5, 6, 6, 5, 6, 7, 5, 6, 4, 8, 6, 8, 10}
17
18 ‘ response frequency array (indices 0 through 10)
19 Dim frequency As Integer() = New Integer(10) {}
20
21 ‘ count frequencies
22 For answer = 0 To responses.GetUpperBound(0)
23 frequency(responses(answer)) += 1
24 Next
25
26 output &= “Rating ” & vbTab & “Frequency ” & vbCrLf
27
28 For rating = 1 To frequency.GetUpperBound(0)
29 output &= rating & vbTab & frequency(rating) & vbCrLf
30 Next
31
32 MessageBox.Show(output, “Student Poll Program”, _
33 MessageBoxButtons.OK, MessageBoxIcon.Information)
34 End Sub ‘ Main
35
36 End Module ‘ modStudentPoll
Fig. 7.5 Simple student-poll analysis program.
Chapter 7 Arrays 255
Good Programming Practice 7.1
Strive for program clarity. Sometimes, it is worthwhile to forgo the most efficient use of memory
or processor time if the trade-off results in a clearer program. 7.1
Performance Tip 7.1
Sometimes, performance considerations outweigh clarity considerations. 7.1
The For structure (lines 22–24) reads the responses from the array responses one
at a time and increments one of the 10 counters in the frequency array (frequency(
1) to frequency(10)). The key statement in the loop appears in line 23. This
statement increments the appropriate frequency counter as determined by the value of
responses(answer).
Let us consider several iterations of the For structure. When counter answer is 0,
responses(answer) is the value of responses(0) (i.e., 1—see line 14). Therefore,
frequency(responses(answer)) actually is interpreted as frequency(
1), meaning the first counter in array frequency is incremented by one. In
evaluating the expression frequency(responses(answer)), Visual Basic starts
with the value in the innermost set of parentheses (answer, currently 0). The value of
answer is plugged into the expression, and Visual Basic evaluates the next set of parentheses
(responses(answer)). That value is used as the index for the frequency
array to determine which counter to increment (in this case, the 1 counter).
When answer is 1, responses(answer) is the value of responses(1) (i.e.,
2—see line 14). As a result, frequency(responses(answer)) actually is interpreted
as frequency(2), causing array element 2 (the third element of the array) to be
incremented.
When answer is 2, responses(answer) is the value of responses(2) (i.e.,
6—see line 14), so frequency(responses(answer)) is interpreted as frequency(
6), causing array element 6 (the seventh element of the array) to be incremented
and so on. Note that, regardless of the number of responses processed in the survey, only
an 11-element array (in which we ignore element zero) is required to summarize the results,
because all the response values are between 1 and 10, and the index values for an 11-element
array are 0–10. Note that, in the output in Fig. 7.5, the numbers in the frequency
column correctly add to 40 (the elements of the frequency array were initialized to zero
when the array was allocated with New).
If the data contained out-of-range values, such as 13, the program would attempt to add
1 to frequency(13). This is outside the bounds of the array. In other languages like C
and C++ programming languages, such a reference would be allowed by the compiler and
at execution time. The program would “walk” past the end of the array to where it thought
element number 13 was located and would add 1 to whatever happened to be stored at that
memory location. This could modify another variable in the program, possibly causing
incorrect results or even premature program termination. Visual Basic provides mechanisms
that prevent accessing elements outside the bounds of arrays.
Common Programming Error 7.2
Referencing an element outside the array bounds is a runtime error. 7.2
256 Arrays Chapter 7
Testing and Debugging Tip 7.1
When a program is executed, array element indices are checked for validity (i.e., all indices
must be greater than or equal to 0 and less than the length of the array). If an attempt is made
to use an invalid index to access an element, Visual Basic generates an IndexOutOfRangeException
exception. Exceptions are discussed in greater detail in Chapter 11, Exception
Handling. 7.1
Testing and Debugging Tip 7.2
When looping through an array, the array index should remain between 0 and the upper
bound of the array (i.e., the value returned by method GetUpperBound). The initial and
final values used in the repetition structure should prevent accessing elements outside this
range. 7.2
Testing and Debugging Tip 7.3
Programs should confirm the validity of all input values to prevent erroneous information
from affecting calculations. 7.3
7.4.5 Using Histograms to Display Array Data Graphically
Many programs present data to users in a visual or graphical format. For example, numeric
values are often displayed as bars in a bar chart, in which longer bars represent larger numeric
values. Figure 7.6 displays numeric data graphically by creating a histogram that depicts
each numeric value as a bar of asterisks (*).
1 ‘ Fig. 7.6: Histogram.vb
2 ‘ Using data to create histograms.
34
Imports System.Windows.Forms
56
Module modHistogram
78
Sub Main()
9 Dim output As String ‘ output string
10 Dim i, j As Integer ‘ counters
11
12 ‘ create data array
13 Dim array1 As Integer() = New Integer() _
14 {19, 3, 15, 7, 11, 9, 13, 5, 17, 1}
15
16 output &= “Element ” & vbTab & “Value ” & vbTab & _
17 “Histogram”
18
19 For i = 0 To array1.GetUpperBound(0)
20 output &= vbCrLf & i & vbTab & array1(i) & vbTab
21
22 For j = 1 To array1(i)
23 output &= “*” ‘ add one asterisk
24 Next
25
26 Next
Fig. 7.6 Program that prints histograms (part 1 of 2).
Chapter 7 Arrays 257
The program reads numbers from an array and graphs the information in the form of a
bar chart, or histogram. Each number is printed, and a bar consisting of a corresponding
number of asterisks is displayed beside the number. The nested For loops (lines 19–26)
append the bars to the String that is displayed in the MessageBox. Note the end value
(array1(i)) of the inner For structure on line 22. Each time the inner For structure is
reached (line 22), it counts from 1 to array1(i), using a value in array1 to determine
the final value of the control variable j—the number of asterisks to display.
Sometimes programs use a series of counter variables to summarize data, such as the
results of a survey. In Chapter 6, Procedures, we used a series of counters in our die-rolling
program to track the number of occurrences of each side on a six-sided die as the program
rolled the die 12 times. We indicated that there is a more elegant way of doing what we did
in Fig. 6.11 for writing the dice-rolling program. An array version of this application is
shown in Fig. 7.7.
27
28 MessageBox.show(output, “Histogram Printing Program”, _
29 MessageBoxButtons.OK, MessageBoxIcon.Information)
30 End Sub ‘ Main
31
32 End Module ‘ modHistogram
1 ‘ Fig. 7.7: RollDie.vb
2 ‘ Rolling 12 dice with frequency chart.
34
‘ Note: Directory.GetCurrentDirectory returns the directory of
5 ‘ the folder where the current project is plus
6 ‘ “bin/”. This is where the images must be placed
7 ‘ for the example to work properly.
89
Imports System.IO
10 Imports System.Windows.Forms
11
12 Public Class FrmRollDie
13 Inherits System.Windows.Forms.Form
14
Fig. 7.7 Using arrays to eliminate a Select Case structure (part 1 of 4).
Fig. 7.6 Program that prints histograms (part 2 of 2).
258 Arrays Chapter 7
15 Dim randomNumber As Random = New Random()
16 Dim frequency As Integer() = New Integer(6) {}
17
18 ‘ labels
19 Friend WithEvents lblDie1 As Label
20 Friend WithEvents lblDie2 As Label
21 Friend WithEvents lblDie3 As Label
22 Friend WithEvents lblDie4 As Label
23 Friend WithEvents lblDie5 As Label
24 Friend WithEvents lblDie6 As Label
25 Friend WithEvents lblDie7 As Label
26 Friend WithEvents lblDie8 As Label
27 Friend WithEvents lblDie9 As Label
28 Friend WithEvents lblDie11 As Label
29 Friend WithEvents lblDie10 As Label
30 Friend WithEvents lblDie12 As Label
31
32 ‘ text box
33 Friend WithEvents txtDisplay As TextBox
34
35 ‘ button
36 Friend WithEvents cmdRoll As Button
37
38 ‘ Visual Studio .NET generated code
39
40 ‘ event handler for cmdRoll button
41 Private Sub cmdRoll_Click(ByVal sender As System.Object, _
42 ByVal e As System.EventArgs) Handles cmdRoll.Click
43
44 ‘ pass labels to a method that
45 ‘ randomly assigns a face to each die
46 DisplayDie(lblDie1)
47 DisplayDie(lblDie2)
48 DisplayDie(lblDie3)
49 DisplayDie(lblDie4)
50 DisplayDie(lblDie5)
51 DisplayDie(lblDie6)
52 DisplayDie(lblDie7)
53 DisplayDie(lblDie8)
54 DisplayDie(lblDie9)
55 DisplayDie(lblDie10)
56 DisplayDie(lblDie11)
57 DisplayDie(lblDie12)
58
59 Dim total As Double = 0
60 Dim i As Integer
61
62 For i = 1 To frequency.GetUpperBound(0)
63 total += frequency(i)
64 Next
65
66 txtDisplay.Text = “Face” & vbTab & vbTab & “Frequency” & _
67 vbTab & vbTab & “Percent” & vbCrLf
Fig. 7.7 Using arrays to eliminate a Select Case structure (part 2 of 4).
Chapter 7 Arrays 259
68
69 ‘ output frequency values
70 For i = 1 To frequency.GetUpperBound(0)
71 txtDisplay.Text &= i & vbTab & vbTab & frequency(i) & _
72 vbTab & vbTab & vbTab & String.Format(“{0:N}”, _
73 frequency(i) / total * 100) & “%” & vbCrLf
74 Next
75
76 End Sub ‘ cmdRoll_Click
77
78 ‘ simulate roll, display proper
79 ‘ image and increment frequency
80 Sub DisplayDie(ByVal lblDie As Label)
81 Dim face As Integer = 1 + randomNumber.Next(6)
82
83 lblDie.Image = _
84 Image.FromFile(Directory.GetCurrentDirectory & _
85 “\Images\die” & face & “.png”)
86
87 frequency(face) += 1
88 End Sub ‘ DisplayDie
89
90 End Class ‘ FrmRollDie
Fig. 7.7 Using arrays to eliminate a Select Case structure (part 3 of 4).
260 Arrays Chapter 7
Lines 91–111 of Fig. 6.16 are replaced by line 87, which uses face’s value as the
index for array frequency to determine which element should be incremented during
each iteration of the loop. The random number calculation on line 81 produces numbers
from 1–6 (the values for a six-sided die); thus, the frequency array must have seven elements
to allow the index values 1–6. In this program, we ignore element 0 of array frequency.
Lines 66–74 replace lines 57–78 from Fig. 6.16. We can loop through array
frequency; therefore, we do not have to enumerate each line of text to display in the
Label, as we did in Fig. 6.16.
7.5 Passing Arrays to Procedures
To pass an array argument to a procedure, specify the name of the array without using parentheses.
For example, if array hourlyTemperatures has been declared as
Dim hourlyTemperatures As Integer() = New Integer(24) {}
the procedure call
DayData(hourlyTemperatures)
passes array hourlyTemperatures to procedure DayData.
Fig. 7.7 Using arrays to eliminate a Select Case structure (part 4 of 4).
Chapter 7 Arrays 261
Every array object “knows” its own upper bound (i.e., the value returned by the method
GetUpperBound), so, when we pass an array object to a procedure, we do not need to
pass the upper bound of the array as a separate argument.
For a procedure to receive an array through a procedure call, the procedure’s parameter
list must specify that an array will be received. For example, the procedure header for Day-
Data might be written as
Sub DayData(ByVal temperatureData As Integer())
indicating that DayData expects to receive an Integer array in parameter temperatureData.
In Visual Basic, arrays always are passed by reference, yet it is normally inappropriate
to use keyword ByRef in the procedure definition header. We discuss this subtle
(and somewhat complex) issue in more detail in Section 7.6.
Although entire arrays are always passed by reference, individual array elements can be
passed in the same manner as simple variables of that type. For instance, array element values
of primitive data types, such as Integer, can be passed by value or by reference, depending
on the procedure definition. To pass an array element to a procedure, use the indexed name
of the array element as an argument in the call to the procedure. The program in Fig. 7.8 demonstrates
the difference between passing an entire array and passing an array element.
1 ‘ Fig. 7.8: PassArray.vb
2 ‘ Passing arrays and individual array elements to procedures.
34
Imports System.Windows.Forms
56
Module modPassArray
7 Dim output As String
89
Sub Main()
10 Dim array1 As Integer() = New Integer() {1, 2, 3, 4, 5}
11 Dim i As Integer
12
13 output = “EFFECTS OF PASSING ENTIRE ARRAY ” & _
14 “BY REFERENCE:” & vbCrLf & vbCrLf & _
15 “The values of the original array are:” & vbCrLf
16
17 ‘ display original elements of array1
18 For i = 0 To array1.GetUpperBound(0)
19 output &= ” ” & array1(i)
20 Next
21
22 ModifyArray(array1) ‘ array is passed by reference
23
24 output &= vbCrLf & _
25 “The values of the modified array are:” & vbCrLf
26
27 ‘ display modified elements of array1
28 For i = 0 To array1.GetUpperBound(0)
29 output &= ” ” & array1(i)
30 Next
Fig. 7.8 Passing arrays and individual array elements to procedures (part 1 of 3).
262 Arrays Chapter 7
31
32 output &= vbCrLf & vbCrLf & _
33 “EFFECTS OF PASSING ARRAY ELEMENT ” & _
34 “BY VALUE:” & vbCrLf & vbCrLf & “array1(3) ” & _
35 “before ModifyElementByVal: ” & array1(3)
36
37 ‘ array element passed by value
38 ModifyElementByVal(array1(3))
39
40 output &= vbCrLf & “array1(3) after ” & _
41 “ModifyElementByVal: ” & array1(3)
42
43 output &= vbCrLf & vbCrLf & “EFFECTS OF PASSING ” & _
44 “ARRAY ELEMENT BY REFERENCE: ” & vbCrLf & vbCrLf & _
45 “array1(3) before ModifyElementByRef: ” & array1(3)
46
47 ‘ array element passed by reference
48 ModifyElementByRef(array1(3))
49
50 output &= vbCrLf & “array1(3) after ” & _
51 “ModifyElementByRef: ” & array1(3)
52
53 MessageBox.Show(output, “Passing Arrays”, _
54 MessageBoxButtons.OK, MessageBoxIcon.Information)
55 End Sub ‘ Main
56
57 ‘ procedure modifies array it receives (note ByVal)
58 Sub ModifyArray(ByVal arrayParameter As Integer())
59 Dim j As Integer
60
61 For j = 0 To arrayParameter.GetUpperBound(0)
62 arrayParameter(j) *= 2
63 Next
64
65 End Sub ‘ ModifyArray
66
67 ‘ procedure modifies integer passed to it
68 ‘ original is not be modified (note ByVal)
69 Sub ModifyElementByVal(ByVal element As Integer)
70
71 output &= vbCrLf & “Value received in ” & _
72 “ModifyElementByVal: ” & element
73 element *= 2
74 output &= vbCrLf & “Value calculated in ” & _
75 “ModifyElementByVal: ” & element
76 End Sub ‘ ModifyElementByVal
77
78 ‘ procedure modifies integer passed to it
79 ‘ original is be modified (note ByRef)
80 Sub ModifyElementByRef(ByRef element As Integer)
81
82 output &= vbCrLf & “Value received in ” & _
83 “ModifyElementByRef: ” & element
Fig. 7.8 Passing arrays and individual array elements to procedures (part 2 of 3).
Chapter 7 Arrays 263
The For/Next structure on lines 18–20 appends the five elements of integer array
array1 (line 10) to String output. Line 22 passes array1 to procedure ModifyArray
(line 58), which then multiplies each element by 2 (line 62). To illustrate that
array1’s elements were modified in the called procedure (i.e., as enabled by passing by
reference), the For/Next structure in lines 28–30 appends the five elements of array1
to output. As the screen capture indicates, the elements of array1 are indeed modified
by ModifyArray.
To show the value of array1(3) before the call to ModifyElementByVal, lines
32–35 append the value of array1(3) to String output. Line 38 invokes procedure
ModifyElementByVal and passes array1(3). When array1(3) is passed by
value, the Integer value in the fourth position of array array1 (now an 8) is copied
and is passed to procedure ModifyElementByVal, where it becomes the value of argument
element. Procedure ModifyElementByVal then multiplies element by 2
(line 73). The parameter of ModifyElementByVal is a local variable that is destroyed
when the procedure terminates. Thus, when control is returned to Main, the unmodified
value of array1(3) is appended to the string variable output (lines 40–41).
Lines 43–51 demonstrate the effects of procedure ModifyElementByRef (lines
80–87). This procedure performs the same calculation as ModifyElementByVal, multiplying
element by 2. In this case, array1(3) is passed by reference, meaning the
value of array1(3) appended to output (lines 50–51) is the same as the value calculated
in the procedure.
Common Programming Error 7.3
In the passing of an array to a procedure, including an empty pair of parentheses after the
array name is a syntax error. 7.3
84 element *= 2
85 output &= vbCrLf & “Value calculated in ” & _
86 “ModifyElementByRef: ” & element
87 End Sub ‘ ModifyElementByRef
88
89 End Module ‘ modPassArray
Fig. 7.8 Passing arrays and individual array elements to procedures (part 3 of 3).
264 Arrays Chapter 7
7.6 Passing Arrays: ByVal vs. ByRef
In Visual Basic .NET, a variable that “stores” an object, such as an array, does not actually
store the object itself. Instead, such a variable stores a reference to the object (i.e., the location
in the computer’s memory where the object is already stored). The distinction between
reference variables and primitive data type variables raises some subtle issues that programmers
must understand to create secure, stable programs.
When used to declare a value-type parameter, keyword ByVal causes the value of the
argument to be copied to a local variable in the procedure. Changes to the local variable are
reflected in the local copy of that variable, but not in the original variable in the calling program.
However, if the argument passed using keyword ByVal is of a reference type, the
value copied is also a reference to the original object in the computer’s memory. Thus, reference
types (like arrays and other objects) passed via keyword ByVal are actually passed
by reference, meaning changes to the objects in called procedures affect the original objects
in the callers.
Performance Tip 7.2
Passing arrays and other objects by reference makes sense for performance reasons. If arrays
were passed by value, a copy of each element would be passed. For large, frequently
passed arrays, this would waste time and would consume considerable storage for the copies
of the arrays—both of these problems cause poor performance. 7.2
Visual Basic also allows procedures to pass references with keyword ByRef. This is
a subtle capability, which, if misused, can lead to problems. For instance, when a referencetype
object like an array is passed with ByRef, the called procedure actually gains control
over the passed reference itself, allowing the called procedure to replace the original reference
in the caller with a different object or even with Nothing. Such behavior can lead to
unpredictable effects, which can be disastrous in mission-critical applications. The program
in Fig. 7.9 demonstrates the subtle difference between passing a reference ByVal vs.
passing a reference ByRef.
Lines 11–12 declare two integer array variables, firstArray and firstArray-
Copy (we make the copy so we can determine whether reference firstArray gets overwritten).
Line 15 allocates an array containing Integer values 1, 2 and 3 and stores the
array reference in variable firstArray. The assignment statement on line 16 copies reference
firstArray to variable firstArrayCopy, causing these variables to reference the
same array object. The For/Next structure in lines 24–26 prints the contents of firstArray
before it is passed to procedure FirstDouble on line 29 so we can verify that this
array is passed by reference (i.e., the called method indeed changes the array’s contents).
The For/Next structure in procedure FirstDouble (lines 94–96) multiplies the
values of all the elements in the array by 2. Line 99 allocates a new array containing the
values 11, 12 and 13; the reference for this array then is assigned to parameter array (in
an attempt to overwrite reference firstArray in Main—this, of course, will not
happen, because the reference was passed ByVal). After procedure FirstDouble executes,
the For/Next structure on lines 35–37 prints the contents of firstArray, demonstrating
that the values of the elements have been changed by the procedure (and
confirming that in Visual Basic, .NET arrays are always passed by reference). The If
structure on lines 40–46 uses the Is operator to compare references firstArray (which
we just attempted to overwrite) and firstArrayCopy. Visual Basic provides operator
Chapter 7 Arrays 265
Is for comparing references to determine whether they are referencing the same object.
The expression on line 40 is true if the operands to binary operator Is indeed reference the
same object. In this case, the object represented is the array allocated in line 15—not the
array allocated in procedure FirstDouble (line 99).
1 ‘ Fig. 7.9: ArrayReferenceTest.vb
2 ‘ Testing the effects of passing array references using
3 ‘ ByVal and ByRef.
45
Module modArrayReferenceTest
67
Sub Main()
8 Dim i As Integer
9
10 ‘ declare array references
11 Dim firstArray As Integer()
12 Dim firstArrayCopy As Integer()
13
14 ‘ allocate firstArray and copy its reference
15 firstArray = New Integer() {1, 2, 3}
16 firstArrayCopy = firstArray
17
18 Console.WriteLine(“Test passing array reference ” & _
19 “using ByVal.”)
20 Console.Write(“Contents of firstArray before ” & _
21 “calling FirstDouble: “)
22
23 ‘ print contents of firstArray
24 For i = 0 To firstArray.GetUpperBound(0)
25 Console.Write(firstArray(i) & ” “)
26 Next
27
28 ‘ pass firstArray using ByVal
29 FirstDouble(firstArray)
30
31 Console.Write(vbCrLf & “Contents of firstArray after ” & _
32 “calling FirstDouble: “)
33
34 ‘ print contents of firstArray
35 For i = 0 To firstArray.GetUpperBound(0)
36 Console.Write(firstArray(i) & ” “)
37 Next
38
39 ‘ test whether reference was changed by FirstDouble
40 If firstArray Is firstArrayCopy Then
41 Console.WriteLine(vbCrLf & “The references are ” & _
42 “equal.”)
43 Else
44 Console.WriteLine(vbCrLf & “The references are ” & _
45 “not equal.”)
46 End If
47
Fig. 7.9 Passing an array reference with ByVal and ByRef (part 1 of 3).
266 Arrays Chapter 7
48 ‘ declare array references
49 Dim secondArray As Integer()
50 Dim secondArrayCopy As Integer()
51
52 ‘ allocate secondArray and copy its reference
53 secondArray = New Integer() {1, 2, 3}
54 secondArrayCopy = secondArray
55
56 Console.WriteLine(vbCrLf & “Test passing array ” & _
57 “reference using ByRef.”)
58 Console.Write(“Contents of secondArray before ” & _
59 “calling SecondDouble: “)
60
61 ‘ print contents of secondArray before procedure call
62 For i = 0 To secondArray.GetUpperBound(0)
63 Console.Write(secondArray(i) & ” “)
64 Next
65
66 ‘ pass secondArray using ByRef
67 SecondDouble(secondArray)
68
69 Console.Write(vbCrLf & “Contents of secondArray ” & _
70 “after calling SecondDouble: “)
71
72 ‘ print contents of secondArray after procedure call
73 For i = 0 To secondArray.GetUpperBound(0)
74 Console.Write(secondArray(i) & ” “)
75 Next
76
77 ‘ test whether the reference was changed by SecondDouble
78 If secondArray Is secondArrayCopy Then
79 Console.WriteLine(vbCrLf & “The references are ” & _
80 “equal.”)
81 Else
82 Console.WriteLine(vbCrLf & “The references are ” & _
83 “not equal.”)
84 End If
85
86 End Sub ‘ Main
87
88 ‘ procedure modifies elements of array and assigns
89 ‘ new reference (note ByVal)
90 Sub FirstDouble(ByVal array As Integer())
91 Dim i As Integer
92
93 ‘ double each element value
94 For i = 0 To array.GetUpperBound(0)
95 array(i) *= 2
96 Next
97
98 ‘ create new reference and assign it to array
99 array = New Integer() {11, 12, 13}
100 End Sub ‘ FirstDouble
Fig. 7.9 Passing an array reference with ByVal and ByRef (part 2 of 3).
Chapter 7 Arrays 267
Lines 48–84 in procedure Main perform similar tests, using array variables second-
Array and secondArrayCopy and procedure SecondDouble (lines 104–114). Procedure
SecondDouble performs the same operations as FirstDouble, but receives its
array argument with ByRef. In this case, the reference stored in secondArray after the
procedure call is a reference to the array allocated on line 113 of SecondDouble, demonstrating
that a reference passed with ByRef can be modified by the called procedure so
that the reference actually points to a different object, in this case an array allocated in procedure
SecondDouble. The If structure in lines 78–84 demonstrates that second-
Array and secondArrayCopy no longer represent the same array.
Software Engineering Observation 7.1
Using ByVal to receive a reference-type object parameter does not cause the object to pass
by value—the object still passes by reference. Rather, ByVal causes the object’s reference
to pass by value. This prevents a called procedure from overwriting a reference in the caller.
In the vast majority of cases, protecting the caller’s reference from modification is the desired
behavior. If you encounter a situation where you truly want the called procedure to
modify the caller’s reference, pass the reference-type object ByRef—but, again, such situations
are rare. 7.1
Software Engineering Observation 7.2
In Visual Basic .NET, reference-type objects (including arrays) always pass by reference. So,
a called procedure receiving a reference to an object in a caller can change the caller’s object.7.2
101
102 ‘ procedure modifies elements of array and assigns
103 ‘ new reference (note ByRef)
104 Sub SecondDouble(ByRef array As Integer())
105 Dim i As Integer
106
107 ‘ double contents of array
108 For i = 0 To array.GetUpperBound(0)
109 array(i) *= 2
110 Next
111
112 ‘ create new reference and assign it to array
113 array = New Integer() {11, 12, 13}
114 End Sub ‘ SecondDouble
115
116 End Module ‘ modPassArray
Test passing array reference using ByVal.
Contents of firstArray before calling FirstDouble: 1 2 3
Contents of firstArray after calling FirstDouble: 2 4 6
The references are equal.
Test passing array reference using ByRef.
Contents of secondArray before calling SecondDouble: 1 2 3
Contents of secondArray after calling SecondDouble: 11 12 13
The references are not equal.
Fig. 7.9 Passing an array reference with ByVal and ByRef (part 3 of 3).
268 Arrays Chapter 7
7.7 Sorting Arrays
Sorting data (i.e., arranging the data into some particular order, such as ascending or descending
order) is one of the most popular computing applications. For example, a bank
sorts all checks by account number, so that it can prepare individual bank statements at the
end of each month. Telephone companies sort their lists of accounts by last name and, within
last-name listings, by first name, to make it easy to find phone numbers. Virtually every
organization must sort some data and, often, massive amounts of it. Sorting is an intriguing
problem that has attracted some of the most intense research efforts in the computer-science
field. This section discusses one of the simplest sorting schemes. In the exercises at the end
of this chapter, we investigate a more sophisticated sorting algorithm.
Performance Tip 7.3
Sometimes, the simplest algorithms perform poorly. Their virtue is that they are easy to write,
test and debug. Complex algorithms may be needed for a program to achieve maximum performance.
7.3
The module shown in Fig. 7.10 contains procedures for sorting the values of an integer
array into ascending order. The technique we use is called the bubble sort, or the sinking
sort, because in an ascending sort smaller values gradually “bubble” their way to the top of
the array (i.e., toward the first element) like air bubbles rising in water, while larger values
sink to the bottom (i.e., toward the end) of the array. The technique uses nested loops to
make several passes through the array. Each pass compares successive pairs of elements. If
a pair is in increasing order (or the values are equal), the bubble sort leaves the values as
they are. If a pair is in decreasing order, the bubble sort swaps their values in the array.
1 ‘ Fig. 7.10: BubbleSort.vb
2 ‘ Procedures for sorting an integer array.
34
Module modBubbleSort
56
‘ sort array using bubble sort algorithm
7 Sub BubbleSort(ByVal sortArray As Integer())
8 Dim pass, i As Integer
9
10 For pass = 1 To sortArray.GetUpperBound(0)
11
12 For i = 0 To sortArray.GetUpperBound(0) – 1
13
14 If sortArray(i) > sortArray(i + 1) Then
15 Swap(sortArray, i)
16 End If
17
18 Next
19
20 Next
21
22 End Sub ‘ BubbleSort
23
Fig. 7.10 BubbleSort procedure in modBubbleSort (part 1 of 2).
Chapter 7 Arrays 269
The module contains procedures BubbleSort and Swap. Procedure BubbleSort
(lines 7–22) sorts the elements of its parameter, sortArray. Procedure BubbleSort
calls procedure Swap (lines 25–33) as necessary to transpose two of the array elements.
The Windows application in Fig. 7.11 demonstrates procedure BubbleSort (Fig. 7.10)
by sorting an array of 10 randomly-generated elements (which may contain duplicates).
24 ‘ swap two array elements
25 Sub Swap(ByVal swapArray As Integer(), _
26 ByVal first As Integer)
27
28 Dim hold As Integer
29
30 hold = swapArray(first)
31 swapArray(first) = swapArray(first + 1)
32 swapArray(first + 1) = hold
33 End Sub ‘ Swap
34
35 End Module ‘ modBubbleSort
1 ‘ Fig. 7.11: BubbleSortTest.vb
2 ‘ Program creates random numbers and sorts them.
34
Imports System.Windows.Forms
56
Public Class FrmBubbleSort
7 Inherits System.Windows.Forms.Form
89
‘ buttons
10 Friend WithEvents cmdCreate As Button
11 Friend WithEvents cmdSort As Button
12
13 ‘ labels
14 Friend WithEvents lblOriginal As Label
15 Friend WithEvents lblSorted As Label
16
17 ‘ textboxes
18 Friend WithEvents txtOriginal As TextBox
19 Friend WithEvents txtSorted As TextBox
20
21 ‘ Visual Studio .NET generated code
22
23 Dim array As Integer() = New Integer(9) {}
24
25 ‘ creates random generated numbers
26 Private Sub cmdCreate_Click(ByVal sender As System.Object, _
27 ByVal e As System.EventArgs) Handles cmdCreate.Click
28
Fig. 7.11 Sorting an array with bubble sort (part 1 of 3).
Fig. 7.10 BubbleSort procedure in modBubbleSort (part 2 of 2).
270 Arrays Chapter 7
29 Dim output As String
30 Dim randomNumber As Random = New Random()
31 Dim i As Integer
32
33 txtSorted.Text = “”
34
35 ‘ create 10 random numbers and append to output
36 For i = 0 To array.GetUpperBound(0)
37 array(i) = randomNumber.Next(100)
38 output &= array(i) & vbCrLf
39 Next
40
41 txtOriginal.Text = output ‘ display numbers
42 cmdSort.Enabled = True ‘ enables cmdSort button
43 End Sub ‘ cmdCreate_Click
44
45 ‘ sorts randomly generated numbers
46 Private Sub cmdSort_Click(ByVal sender As System.Object, _
47 ByVal e As System.EventArgs) Handles cmdSort.Click
48
49 Dim output As String
50 Dim i As Integer
51
52 ‘ sort array
53 modBubbleSort.BubbleSort(array)
54
55 ‘ creates string with sorted numbers
56 For i = 0 To array.GetUpperBound(0)
57 output &= array(i) & vbCrLf
58 Next
59
60 txtSorted.Text = output ‘ display numbers
61 cmdSort.Enabled = False
62 End Sub ‘ cmdSort_Click
63
64 End Class ‘ FrmBubbleSort
Fig. 7.11 Sorting an array with bubble sort (part 2 of 3).
Chapter 7 Arrays 271
The program contains methods cmdCreate_Click and cmdSort_Click.
Method cmdCreate_Click (lines 26–43) assigns 10 random values to the elements of
array and displays the contents of the array in txtOriginal. Method
cmdSort_Click (lines 46–62) sorts array by calling procedure BubbleSort from
modBubbleSort.
Procedure BubbleSort receives the array as parameter sortArray. The nested
For/Next structures in lines 10–20 of Fig. 7.10 performs the sort. The outer loop controls
the number of passes of the array. The inner loop (lines 12–18) controls the comparisons
and swapping (if necessary) of the elements during each pass.
Procedure BubbleSort first compares sortArray(0) to sortArray(1), then
sortArray(1) to sortArray(2), and so on until it completes the pass by comparing
sortArray(8) to sortArray(9). Although there are 10 elements, the comparison
loop performs only nine comparisons (because the comparisons each involve a pair of numbers).
The comparisons performed in a bubble sort could cause a large value to move down
the array (sink) many positions on a single pass. However, a small value cannot move up
(bubble) more than one position per pass. On the first pass, the largest value is guaranteed
to sink to the bottom element of the array, sortArray(9). On the second pass, the
second-largest value is guaranteed to sink to sortArray(8). On the ninth pass, the ninth
largest value sinks to sortArray(1), leaving the smallest value in sortArray(0).
Thus, only nine passes are required to sort a 10-element array (and, in general, only n-1
passes are needed to sort an n-element array).
If a comparison reveals that the two elements are in descending order, BubbleSort
calls procedure Swap to exchange the two elements, placing them in ascending order in the
array. Procedure Swap receives the array (which it calls swapArray) and the index of the
first element of the array to transpose (with the subsequent element). The exchange is performed
by three assignments
hold = swapArray(first)
swapArray(first) = swapArray(first + 1)
swapArray(first + 1) = hold
Fig. 7.11 Sorting an array with bubble sort (part 3 of 3).
272 Arrays Chapter 7
where the extra variable hold temporarily stores one of the two values being swapped. The
swap cannot be performed with only the two assignments
swapArray(first) = swapArray(first + 1)
swapArray(first + 1) = swapArray(first)
If swapArray(first) is 7 and swapArray(first + 1) is 5, after the first assignment
both array elements contains 5, and the value 7 is lost—hence, the need for the extra
variable hold.
The advantage of the bubble sort is that it is easy to program. However, the bubble sort
runs slowly, as becomes apparent when sorting large arrays. In the exercises, we develop
efficient versions of the bubble sort and investigate a more efficient and more complex sort,
quicksort. More advanced courses (often titled “Data Structures” or “Algorithms” or
“Computational Complexity”) investigate sorting and searching in greater depth.
7.8 Searching Arrays: Linear Search and Binary Search
Often, programmers work with large amounts of data stored in arrays. It might be necessary
in this case to determine whether an array contains a value that matches a certain key value.
The process of locating a particular element value in an array is called searching. In this section,
we discuss two searching techniques—the simple linear search technique and the more
efficient (but more complex) binary search technique. Exercises 7.8 and 7.9 at the end of this
chapter ask you to implement recursive versions of the linear and binary searches.
7.8.1 Searching an Array with Linear Search
Module modLinearSearch in Fig. 7.12 contains a procedure for performing a linear
search. Procedure LinearSearch (lines 7–22) uses a For/Next structure containing an
If structure (lines 15–17) to compare each element of an array with a search key. If the
search key is found, the procedure returns the index value for the element, indicating the
position of the search key in the array. If the search key is not found, the procedure returns
–1. (The value –1 is a good choice because it is not a valid index number.) If the elements
of the array being searched are unordered, it is just as likely that the value will be found in
the first element as in the last, so the procedure will have to compare the search key with
half the elements of the array, on average.
1 ‘ Fig. 7.12: LinearSearch.vb
2 ‘ Linear search of an array.
34
Module modLinearSearch
56
‘ iterates through array
7 Function LinearSearch(ByVal key As Integer, _
8 ByVal numbers As Integer()) As Integer
9
10 Dim n As Integer
11
Fig

Fig. 7.12 Procedures for performing a linear search (part 1 of 2).
Chapter 7 Arrays 273
The program in Fig. 7.13 uses module modLinearSearch to search a 20-element
array filled with random values created when the user clicks cmdCreate. The user then
types a search key in a TextBox (named txtInput) and clicks cmdSearch to start
the search.
12 ‘ structure iterates linearly through array
13 For n = 0 To numbers.GetUpperBound(0)
14
15 If numbers(n) = key Then
16 Return n
17 End If
18
19 Next
20
21 Return -1
22 End Function ‘ LinearSearch
23
24 End Module ‘ modLinearSearch
1 ‘ Fig. 7.13: LinearSearchTest.vb
2 ‘ Linear search of an array.
34
Imports System.Windows.Forms
56
Public Class FrmLinearSearchTest
7 Inherits System.Windows.Forms.Form
89
‘ buttons
10 Friend WithEvents cmdSearch As Button
11 Friend WithEvents cmdCreate As Button
12
13 ‘ text boxes
14 Friend WithEvents txtInput As TextBox
15 Friend WithEvents txtData As TextBox
16
17 ‘ labels
18 Friend WithEvents lblEnter As Label
19 Friend WithEvents lblResult As Label
20
21 ‘ Visual Studio .NET generated code
22
23 Dim array1 As Integer() = New Integer(19) {}
24
25 ‘ creates random data
26 Private Sub cmdCreate_Click(ByVal sender As System.Object, _
27 ByVal e As System.EventArgs) Handles cmdCreate.Click
28
29 Dim output As String
30 Dim randomNumber As Random = New Random()
31 Dim i As Integer
Fig. 7.13 Linear search of an array (part 1 of 3).
Fig. 7.12 Procedures for performing a linear search (part 2 of 2).
274 Arrays Chapter 7
32
33 output = “Index” & vbTab & “Value” & vbCrLf
34
35 ‘ creates string containing 11 random numbers
36 For i = 0 To array1.GetUpperBound(0)
37 array1(i) = randomNumber.Next(1000)
38 output &= i & vbTab & array1(i) & vbCrLf
39 Next
40
41 txtData.Text = output ‘ displays numbers
42 txtInput.Text = “” ‘ clear search key text box
43 cmdSearch.Enabled = True ‘ enable search button
44 End Sub ‘ cmdCreate_Click
45
46 ‘ searches key of element
47 Private Sub cmdSearch_Click(ByVal sender As System.Object, _
48 ByVal e As System.EventArgs) Handles cmdSearch.Click
49
50 ‘ if search key text box is empty, display
51 ‘ message and exit procedure
52 If txtInput.Text = “” Then
53 MessageBox.Show(“You must enter a search key.”)
54 Exit Sub
55 End If
56
57 Dim searchKey As Integer = Convert.ToInt32(txtInput.Text)
58 Dim element As Integer = LinearSearch(searchKey, array1)
59
60 If element -1 Then
61 lblResult.Text = “Found Value in index ” & element
62 Else
63 lblResult.Text = “Value Not Found”
64 End If
65
66 End Sub ‘ cmdSearch_Click
67
68 End Class ‘ FrmLinearSearch
Fig. 7.13 Linear search of an array (part 2 of 3).
Chapter 7 Arrays 275
7.8.2 Searching a Sorted Array with Binary Search
The linear search method works well for small or unsorted arrays. However, for large arrays,
linear searching is inefficient. If the array is sorted, the high-speed binary search technique
can be used.
After each comparison, the binary search algorithm eliminates from consideration half
the elements in the array that is being searched. The algorithm locates the middle array element
and compares it with the search key. If they are equal, the search key has been found,
and the index of that element is returned. Otherwise, the problem is reduced to searching
half of the array. If the search key is less than the middle array element, the second half of
the array is eliminated from consideration, and searching continues with only the first half
of the array; otherwise, the second half of the array is searched. If the search key is not the
middle element in the specified subarray (a piece of the original array), the algorithm is
repeated in one quarter of the original array. The search continues until the search key is
equal to the middle element of a subarray, or until the subarray consists of one element that
is not equal to the search key (i.e., the search key is not found).
In a worst-case scenario, searching a sorted array of 1024 elements via binary search
requires only 10 comparisons. Repeatedly dividing 1024 by 2 (after each comparison, we
eliminate from consideration half the array) yields the successive values 512, 256, 128, 64,
32, 16, 8, 4, 2 and 1. The number 1024 (210) is divided by 2 only ten times to get the value
1, and division by 2 is equivalent to one comparison in the binary search algorithm. A
sorted array of 1,048,576 (220) elements takes a maximum of 20 comparisons to find the
key! Similarly, a key can be found in a sorted array of one billion elements in a maximum
of 30 comparisons! This is a tremendous increase in performance over the linear search,
which required comparing the search key with an average of half the elements in the array.
For a one-billion-element array, the difference is between an average of 500 million comparisons
and a maximum of 30 comparisons! The maximum number of comparisons
needed to complete a binary search of any sorted array is indicated by the exponent of the
first power of 2 that is greater than or equal to the number of elements in the array.
Figure 7.14 presents the iterative version of method BinarySearch (lines 60–86).
The method receives two arguments—integer array array1 (the array to search), and
integer searchKey (the search key). The array is passed to BinarySearch, even
Fig. 7.13 Linear search of an array (part 3 of 3).
276 Arrays Chapter 7
though the array is an instance variable of the class. Once again, this is done because an
array normally is passed to a procedure of another class for searching.
1 ‘ Fig. 7.14: BinarySearchTest.vb
2 ‘ Demonstrating binary search of an array.
34
Imports System.Windows.Forms
56
Public Class FrmBinarySearch
7 Inherits System.Windows.Forms.Form
89
‘ labels
10 Friend WithEvents lblEnterKey As Label
11 Friend WithEvents lblResult As Label
12 Friend WithEvents lblResultOutput As Label
13 Friend WithEvents lblDisplay As Label
14 Friend WithEvents lblIndex As Label
15 Friend WithEvents lblIndexes As Label
16
17 ‘ button
18 Friend WithEvents cmdFindKey As Button
19
20 ‘ text box
21 Friend WithEvents txtInput As TextBox
22
23 ‘ Visual Studio .NET generated code
24
25 Dim array1 As Integer() = New Integer(14) {}
26
27 ‘ FrmBinarySearch initializes array1 to ascending values
28 ‘ 0, 2, 4, 6, …, 28 when first loaded
29 Private Sub FrmBinarySearch_Load(ByVal sender As System.Object, _
30 ByVal e As System.EventArgs) Handles MyBase.Load
31
32 Dim i As Integer
33
34 For i = 0 To array1.GetUpperBound(0)
35 array1(i) = 2 * i
36 Next
37
38 End Sub ‘ FrmBinarySearch_Load
39
40 ‘ event handler for cmdFindKey button
41 Private Sub cmdFindKey_Click(ByVal sender As System.Object, _
42 ByVal e As System.EventArgs) Handles cmdFindKey.Click
43
44 Dim searchKey As Integer = Convert.ToInt32(txtInput.Text)
45
46 lblDisplay.Text = “”
47
48 ‘ perform binary search
49 Dim element As Integer = BinarySearch(array1, searchKey)
50
Fig. 7.14 Binary search of a sorted array (part 1 of 3).
Chapter 7 Arrays 277
51 If element -1 Then
52 lblResultOutput.Text = “Found value in element ” & element
53 Else
54 lblResultOutput.Text = “Value not found”
55 End If
56
57 End Sub ‘ cmdFindKey_Click
58
59 ‘ performs binary search
60 Function BinarySearch(ByVal array As Integer(), _
61 ByVal key As Integer) As Integer
62
63 Dim low As Integer = 0 ‘ low index
64 Dim high As Integer = array.GetUpperBound(0) ‘ high index
65 Dim middle As Integer ‘ middle index
66
67 While low <= high
68 middle = (low + high) \ 2
69
70 ' the following line displays part
71 ' of the array being manipulated during
72 ' each iteration of loop
73 BuildOutput(low, middle, high)
74
75 If key = array(middle) Then ' match
76 Return middle
77 ElseIf key < array(middle) Then ' search low end
78 high = middle – 1 ' of array
79 Else
80 low = middle + 1
81 End If
82
83 End While
84
85 Return -1 ' search key not found
86 End Function ' BinarySearch
87
88 Sub BuildOutput(ByVal low As Integer, _
89 ByVal middle As Integer, ByVal high As Integer)
90
91 Dim i As Integer
92
93 For i = 0 To array1.GetUpperBound(0)
94
95 If i high Then
96 lblDisplay.Text &= ” ”
97 ElseIf i = middle Then ‘ mark middle element in output
98 lblDisplay.Text &= String.Format(“{0:D2}”, _
99 array1(i)) & “* ”
100 Else
101 lblDisplay.Text &= String.Format(“{0:D2}”, _
102 array1(i)) & ” ”
103 End If
Fig. 7.14 Binary search of a sorted array (part 2 of 3).
278 Arrays Chapter 7
104
105 Next i
106
107 lblDisplay.Text &= vbCrLf
108 End Sub ‘ BuildOutput
109
110 End Class ‘ FrmBinarySearch
Fig. 7.14 Binary search of a sorted array (part 3 of 3).
Chapter 7 Arrays 279
Line 68 calculates the middle element of the array being searched by determining the
number of elements in the array and then dividing this value by 2. Recall that using the \
operator causes the remainder to be discarded. What happens, then, when there is an even
number of elements in the array? In this case there is no “middle” element, and the middle
of our array is actually between the two middle elements. When this occurs, the calculation
on line 68 returns the smaller of the two middle values.
The If/Else structure on lines 75–81 compares the middle element of the array to key.
If key matches the middle element of a subarray (line 75), middle (the index of the current
element) is returned, indicating that the value was found and the search is complete.
If key does not match the middle element of a subarray, the low index or high
index (both declared in the method) is adjusted so that a smaller subarray can be searched.
If key is less than the middle element (line 77), the high index is set to middle – 1, and
the search is continued on the elements from low to middle – 1. If key is greater than
the middle element (line 79), the low index is set to middle + 1, and the search is continued
on the elements from middle + 1 to high.
The program uses a 15-element array. The first power of 2 greater than or equal to the
number of array elements is 16 (24), so at most four comparisons are required to find the
key. To illustrate this concept, method BinarySearch calls method BuildOutput
(line 88) to output each subarray during the binary search process. The middle element in
each subarray is marked with an asterisk (*) to indicate the element with which the key is
compared. The format string “{0:D2}” on lines 98 and 101 causes the values to be formatted
as integers with at least two digits. Each search in this example results in a maximum
of four lines of output—one per comparison.
7.9 Multidimensional Rectangular and Jagged Arrays
So far, we have studied one-dimensional (or single-subscripted) arrays—i.e., those that
contain one row of values. In this section, we introduce multidimensional (often called multiple-
subscripted) arrays, which require two or more indices to identify particular elements.
We concentrate on two-dimensional (often called double-subscripted) arrays, or arrays that
contain multiple rows of values. There are two types of multidimensional arrays—rectangular
and jagged. Rectangular arrays with two indices often represent tables of values consisting
of information arranged in rows and columns. Each row is the same size, and each
column is the same size (hence, the term “rectangular”). To identify a particular table element,
we must specify the two indices—by convention, the first identifies the element’s
row, the second the element’s column. Figure 7.15 illustrates a two-dimensional rectangular
array, a, containing three rows and four columns. A rectangular two-dimensional array
with m rows and n columns is called an m-by-n array; the array in Fig. 7.15 is referred to
as a 3-by-4 array.
Every element in array a is identified in Fig. 7.15 by an element name of the form
a(i, j), where a is the name of the array and i and j are the indices that uniquely identify
the row and column of each element in array a. Notice that, because array indices are
determined through zero-based counting, the names of the elements in the first row have a
first index of 0; the names of the elements in the fourth column have a second index of 3.
Multidimensional arrays are initialized in declarations using the same process and notations
employed for one-dimensional arrays. For example, a two-dimensional rectangular
array numbers with two rows and two columns could be declared and initialized with
280 Arrays Chapter 7
Dim numbers As Integer(,) = New Integer(1,1) {}
numbers(0, 0) = 1
numbers(0, 1) = 2
numbers(1, 0) = 3
numbers(1, 1) = 4
Alternatively, the initialization can be written on one line, as shown below:
Dim numbers As Integer(,) = New Integer(,) {{1, 2}, {3, 4}}
The values are grouped by row in braces, with 1 and 2 initializing numbers(0,0) and
numbers(0,1), and 3 and 4 initializing numbers(1,0) and numbers(1,1). The
compiler determines the number of rows by counting the number of subinitializer lists (represented
by sets of braces) in the main initializer list. Then, the compiler determines the
number of columns in each row by counting the number of initializer values in the subinitializer
list for that row. In rectangular arrays, each row has the same number of values.
Jagged arrays are maintained as arrays of arrays. Unlike rectangular arrays, rows in
jagged arrays can be of different lengths. The statements
Dim array2 As Integer()() ‘ declare jagged array
array2 = New Integer(1)() {} ‘ allocate two rows
‘ allocate columns for row 0
array2(0) = New Integer() {1, 2}
‘ allocate columns for 1
array2(1) = New Integer() {3, 4, 5}
create Integer array array2 with row 0 (which is an array itself) containing two elements
(1 and 2), and row 1 containing three elements (3, 4 and 5). Notice that the array
name, followed by a single index (e.g., array2(0)), behaves exactly like a normal onedimensional
array variable. A one-dimensional array can be created and assigned to that
value.
Fig. 7.15 Two-dimensional array with three rows and four columns.
Row 0
Row 1
Row 2
Column 0 Column 1 Column 2 Column 3
Column index (or subscript)
Row index (or subscript)
Array name
a(1, 0) a(1, 1) a(1, 2) a(1, 3)
a(0, 0) a(0, 1) a(0, 2) a(0, 3)
a(2, 0) a(2, 1) a(2, 2) a(2, 3)
Chapter 7 Arrays 281
The program in Fig. 7.16 demonstrates the initialization of a rectangular array
(array1) and a jagged array (array2) in declarations and the use of nested For/Next
loops to traverse the arrays (i.e., to manipulate every array element).
The program declares two arrays in method Main. The allocation of array1 (line 14)
provides six initializers in two sublists. The first sublist initializes the first row (row 0) of the
array to the values 1, 2 and 3; the second sublist initializes the second row (row 1) of the array
to the values 4, 5 and 6. The declaration and allocation of array2 (line 17) create a jagged
array of 3 arrays (specified by the 2 in the first set of parentheses after keyword Integer).
Lines 18–20 initialize each subarray so that the first subarray contains the values 1 and 2, the
second contains the value 3 and the last contains the values 4, 5 and 6.
The nested For/Next structures in lines 24–31 append the elements of array1 to
string output. The nested For/Next structures traverse the arrays in two dimensions.
The outer For/Next structure traverses the rows; the inner For/Next structure traverses
the columns within a row. Each For/Next structure calls method GetUpperBound to
obtain the upper bound of the dimension it traverses. Notice that the dimensions are zerobased,
meaning the rows are dimension 0 and the columns are dimension 1.
1 ‘ Fig. 7.16: MultidimensionalArrays.vb
2 ‘ Initializing multi-dimensional arrays.
34
Imports System.Windows.Forms
56
Module modMultidimensionalArrays
78
Sub Main()
9 Dim output As String
10 Dim i, j As Integer
11
12 ‘ create rectangular two-dimensional array
13 Dim array1 As Integer(,)
14 array1 = New Integer(,) {{1, 2, 3}, {4, 5, 6}}
15
16 ‘ create jagged two-dimensional array
17 Dim array2 As Integer()() = New Integer(2)() {}
18
19 array2(0) = New Integer() {1, 2}
20 array2(1) = New Integer() {3}
21 array2(2) = New Integer() {4, 5, 6}
22
23 output = “Values in array1 by row are ” & vbCrLf
24
25 For i = 0 To array1.GetUpperBound(0)
26
27 For j = 0 To array1.GetUpperBound(1)
28 output &= array1(i, j) & ” ”
29 Next
30
31 output &= vbCrLf
32 Next
33
Fig. 7.16 Initializing multidimensional arrays (part 1 of 2).
282 Arrays Chapter 7
The nested For/Next structures in lines 36–43 behave similarly for array2. However,
in a jagged two-dimensional array, the second dimension is actually the first dimension
of a separate array. In the example, the inner For/Next structure determines the
number of columns in each row of the array by passing argument 0 to method GetUpper-
Bound, called on the array returned by accessing a single row of the jagged array. Arrays
of dimensions higher than two can be traversed using one nested For/Next structure for
each dimension.
Many common array manipulations use For/Next repetition structures. Imagine a
jagged array jaggedArray, which contains 3 rows, or arrays. The following For/Next
structure sets all the elements in the third row of array jaggedArray to zero:
For column = 0 To jaggedArray(2).GetUpperBound(0)
jaggedArray(2)(column) = 0
Next
We specified the third row; therefore, we know that the first index is always 2 (0 is the first
row and 1 is the second row). The For/Next loop varies only the second index (i.e., the
column index). Notice the use of jaggedArray(2).GetUpperBound(0) as the end
value of the For/Next structure. In this expression, we call the GetUpperBound method
on the array contained in the third row of jaggedArray. This statement demonstrates
that each row of jaggedArray is itself an array, and therefore methods called on this val-
34 output &= vbCrLf & “Values in array2 by row are ” & _
35 vbCrLf
36
37 For i = 0 To array2.GetUpperBound(0)
38
39 For j = 0 To array2(i).GetUpperBound(0)
40 output &= array2(i)(j) & ” ”
41 Next
42
43 output &= vbCrLf
44 Next
45
46 MessageBox.Show(output, _
47 “Initializing Multi-Dimensional Arrays”, _
48 MessageBoxButtons.OK, MessageBoxIcon.Information)
49 End Sub ‘ Main
50
51 End Module ‘ modMultidimensionalArrays
Fig. 7.16 Initializing multidimensional arrays (part 2 of 2).
Chapter 7 Arrays 283
ue behave as they would for a typical array. The preceding For/Next structure is equivalent
to the assignment statements
jaggedArray(2)(0) = 0
jaggedArray(2)(1) = 0
jaggedArray(2)(2) = 0
jaggedArray(2)(3) = 0
The following nested For/Next structure determines the total of all the elements in array
jaggedArray. We use method GetUpperBound in the headers of the For/Next
structures to determine the number of rows in jaggedArray and the number of columns
in each row.
Dim total, row, column As Integer
For row = 0 To jaggedArray.GetUpperBound(0)
For column = 0 To jaggedArray(row).GetUpperBound(0)
total += jaggedArray(row)(column)
Next
Next
The nested For/Next structure totals the elements of the array one row at a time. The outer
For/Next structure begins by setting the row index to 0, so the elements of the first row
can be totaled by the inner For/Next structure. The outer For/Next structure then increments
row to 1, so the second row can be totaled. The outer For/Next structure increments
row to 2, so the third row can be totaled. The result can be displayed when the outer
For/Next structure terminates.
The program in Fig. 7.17 performs several other array manipulations on a 3-by-4 array
grades. Each row of the array represents a student, and each column represents a grade
on one of the four exams that the student took during the semester. The array manipulations
are performed by four procedures: Procedure Minimum (line 44) determines the lowest
grade of any student for the semester. Procedure Maximum (line 66) determines the highest
grade of any student for the semester. Procedure Average (line 89) determines a particular
student’s semester average. Procedure BuildString (line 103) appends the twodimensional
array to string output in tabular format.
1 ‘ Fig 7.17: JaggedArray.vb
2 ‘ Jagged two-dimensional array example.
34
Imports System.Windows.Forms
56
Module modJaggedArray
7 Dim lastStudent, lastExam As Integer
8 Dim output As String
9
10 Sub Main()
11 Dim i As Integer
Fig. 7.17 Using jagged two-dimensional arrays (part 1 of 4).
284 Arrays Chapter 7
12
13 ‘ jagged array with 3 rows of exam scores
14 Dim gradeArray As Integer()() = New Integer(2)() {}
15
16 ‘ allocate each row with 4 student grades
17 gradeArray(0) = New Integer() {77, 68, 86, 73}
18 gradeArray(1) = New Integer() {98, 87, 89, 81}
19 gradeArray(2) = New Integer() {70, 90, 86, 81}
20
21 ‘ upper bounds for array manipulations
22 lastStudent = gradeArray.GetUpperBound(0)
23 lastExam = gradeArray(0).GetUpperBound(0)
24
25 output = “Students \ Exams” & vbCrLf
26
27 ‘ build output string
28 BuildString(gradeArray)
29 output &= vbCrLf & vbCrLf & “Lowest grade: ” & _
30 Minimum(gradeArray) & vbCrLf & “Highest grade: ” & _
31 Maximum(gradeArray) & vbCrLf
32
33 ‘ calculate each student’s average
34 For i = 0 To lastStudent
35 output &= vbCrLf & “Average for student ” & _
36 i & ” is ” & Average(gradeArray(i))
37 Next
38
39 MessageBox.Show(output, “Jagged two-dimensional array”, _
40 MessageBoxButtons.OK, MessageBoxIcon.Information)
41 End Sub ‘ Main
42
43 ‘ find minimum grade
44 Function Minimum(ByVal grades As Integer()()) _
45 As Integer
46
47 Dim lowGrade As Integer = 100
48 Dim i, j As Integer
49
50 For i = 0 To lastStudent
51
52 For j = 0 To lastExam
53
54 If grades(i)(j) highGrade Then
77 highGrade = grades(i)(j)
78 End If
79
80 Next
81
82 Next
83
84 Return highGrade
85 End Function ‘ Maximum
86
87 ‘ determine the average grade for student
88 ‘ (or set of grades)
89 Function Average(ByVal setOfGrades As Integer()) _
90 As Double
91
92 Dim i As Integer, total As Integer = 0
93
94 ‘ find sum of student’s grades
95 For i = 0 To lastExam
96 total += setOfGrades(i)
97 Next
98
99 Return total / setOfGrades.Length
100 End Function ‘ Average
101
102 ‘ creates String displaying array
103 Sub BuildString(ByVal grades As Integer()())
104 Dim i, j As Integer
105
106 ‘ align column heads
107 output &= ” ”
108
109 For i = 0 To lastExam
110 output &= “(” & i & “) ”
111 Next
112
113 For i = 0 To lastStudent
114 output &= vbCrLf & ” (” & i & “) ”
115
Fig. 7.17 Using jagged two-dimensional arrays (part 3 of 4).
286 Arrays Chapter 7
Procedures Minimum, Maximum and BuildString use array grades and the
variables lastStudent (upper bound for rows in the array) and lastExam (upper
bound for columns in the array). Each procedure uses nested For/Next structures to
iterate through array grades. Consider the nested For/Next structures in procedure
Minimum (lines 50–60). The outer For/Next structure sets i (i.e., the row index) to 0 so
the elements of the first row can be compared with variable lowGrade in the inner For/
Next structure (line 54). The inner For/Next structure loops through the four grades of
a particular row and compares each grade with lowGrade. If a grade is less than low-
Grade, then lowGrade is assigned that grade. The outer For/Next structure then increments
the row index by 1. The elements of the second row are compared with variable
lowGrade. The outer For/Next structure then increments the row index to 2. The elements
of the third row are compared with variable lowGrade. When execution of the
nested structures is complete (line 62), lowGrade contains the smallest grade in the twodimensional
array. Procedure Maximum behaves similarly to procedure Minimum.
Procedure Average takes one argument—a one-dimensional array of test results for
a particular student. Average is called (line 36) with argument gradeArray(i), which
is row i of the jagged two-dimensional array grades. For example, the argument
grades(1) represents the four grades for student 1 (i.e., a one-dimensional array of
grades). Remember that a jagged two-dimensional array is an array with elements that are
one-dimensional arrays. Procedure Average calculates the sum of the array elements,
divides the total by the number of test results (obtained using the Length property) and
then returns the floating-point result as a Double value (line 89).
116 For j = 0 To lastExam
117 output &= grades(i)(j) & ” ”
118 Next
119
120 Next
121
122 End Sub ‘ BuildString
123
124 End Module ‘ modJaggedArray
Fig. 7.17 Using jagged two-dimensional arrays (part 4 of 4).
Chapter 7 Arrays 287
7.10 Variable-Length Parameter Lists
It is possible to create procedures that receive a variable number of arguments, using keyword
ParamArray. The program in Fig. 7.18 calls programmer-defined procedure
AnyNumberArguments three times, passing a different number of values each time.
The values passed into procedure AnyNumberArguments are stored in one-dimensional
Integer array array1, which is declared using ParamArray.
Common Programming Error 7.4
Attempting to declare a parameter variable to the right of the ParamArray array variable
is a syntax error. 7.4
Common Programming Error 7.5
Attempting to use ParamArray with a multidimensional array is a syntax error. 7.5
1 ‘ Fig. 7.18: ParamArrayTest.vb
2 ‘ Using ParamArray to create variable-length parameter lists.
34
Module modParamArrayTest
56
Sub Main()
7 AnyNumberArguments()
8 AnyNumberArguments(2, 3)
9 AnyNumberArguments(7, 8, 9, 10, 11, 12)
10
11 End Sub ‘ Main
12
13 ‘ receives any number of arguments in array
14 Sub AnyNumberArguments(ByVal ParamArray array1 _
15 As Integer())
16
17 Dim i, total As Integer
18 total = 0
19
20 If array1.Length = 0 Then
21 Console.WriteLine(“Procedure AnyNumberArguments” & _
22 ” received 0 arguments.”)
23 Else
24 Console.Write(“The total of “)
25
26 For i = 0 To array1.GetUpperBound(0)
27 Console.Write(array1(i) & ” “)
28 total += array1(i)
29 Next
30
31 Console.WriteLine(“is {0}.”, total)
32 End If
33
34 End Sub ‘ AnyNumberArguments
35
36 End Module ‘ modParamArrayTest
Fig. 7.18 Creating variable-length parameter lists (part 1 of 2).
288 Arrays Chapter 7
Common Programming Error 7.6
Using ByRef with ParamArray is a syntax error. 7.6
We call procedure AnyNumberArguments in lines 7–9, passing a different number
of arguments each time. This procedure is defined on lines 14–34 and applies keyword
ParamArray to array1 in line 14. The If structure on lines 20–32 determines whether
the number of arguments passed to the procedure is zero. If not, lines 24–31 display
array1’s elements and their sum. All arguments passed to the ParamArray array must
be of the same type as the array, otherwise a syntax error occurs. Though we used an
Integer array in this example, any type of array can be used.
In the last chapter, we discussed procedure overloading. Often, programmers prefer to
use procedure overloading rather than writing procedures with variable-length parameter
lists.
Good Programming Practice 7.2
To increase a program’s readability and performance, the programmer should use procedure
overloading in favor of procedures with variable-length parameter lists. 7.2
7.11 For Each/Next Repetition Structure
Visual Basic provides the For Each/Next repetition structure for iterating through the
values in a data structure, such as an array. When used with one-dimensional arrays, For
Each/Next behaves like a For/Next structure that iterates through the range of indices
from 0 to the value returned by GetUpperBound(0). Instead of a counter, For Each/
Next uses a variable to represent the value of each element. The program in Fig. 7.19 uses
the For Each/Next structure to determine the minimum value in a two-dimensional array
of grades.
Procedure AnyNumberArguments received 0 arguments.
The total of 2 3 is 5.
The total of 7 8 9 10 11 12 is 57.
Fig. 7.18 Creating variable-length parameter lists (part 2 of 2).
1 ‘ Fig. 7.19: ForEach.vb
2 ‘ Program uses For Each/Next to find a minimum grade.
34
Module modForEach
56
Sub Main()
7 Dim gradeArray As Integer(,) = New Integer(,) _
8 {{77, 68, 86, 73}, {98, 87, 89, 81}, {70, 90, 86, 81}}
9
10 Dim grade As Integer
11 Dim lowGrade As Integer = 100
12
Fig. 7.19 Using For Each/Next with an array (part 1 of 2).
Chapter 7 Arrays 289
The program behaves similarly to procedure Minimum of Fig. 7.17, but consolidates
the nested For structures into one For Each structure. The header of the For Each repetition
structure (line 13) specifies a variable, grade, and an array, gradeArray. The
For Each/Next structure iterates through all the elements in gradeArray, sequentially
assigning each value to variable grade. The values are compared to variable lowGrade
(line 15), which stores the lowest grade in the array.
For rectangular arrays, the repetition of the For Each/Next structure begins with the
element whose indices are all zero, then iterates through all possible combinations of
indices, incrementing the rightmost index first. When the rightmost index reaches its upper
bound, it is reset to zero, and the index to the left of it is incremented by 1. In this case,
grade takes the values as they are ordered in the initializer list in line 8. When all the
grades have been processed, lowGrade is displayed.
Although many array calculations are handled best with a counter, For Each is useful
when the indices of the elements are not important. For Each/Next particularly is useful
for looping through arrays of objects, as we discuss in Chapter 10, Object-Oriented Programming:
Polymorphism
In this chapter, we showed how to program with arrays. We mentioned that Visual
Basic .NET arrays are objects. In Chapter 8, Object-Based Programming, we show how to
create classes, which are essentially the “blueprints” from which objects are instantiated
(i.e., created).
SUMMARY
• An array is a group of contiguous memory locations that have the same name and are of the same
type.
• The first element in every array is the zeroth element (i.e., element 0).
• The position number in parentheses more formally is called the index (or the subscript). An index
must be an integer or an integer expression.
• All arrays have access to the methods and properties of class System.Array, including the
GetUpperBound method and the Length property.
• To reference the ith element of an array, use i – 1 as the index.
13 For Each grade In gradeArray
14
15 If grade Add Class. Enter the class name in the Name text field and
click the Open button. Note that the class name (ending with the .vb file extension)
appears in the Solution Explorer below the project name.
The following application consists of class CTime (Fig. 8.1) and module modTime-
Test (Fig. 8.2). Class CTime contains the information needed to represent a specific time;
module modTimeTest contains method Main, which uses an instance of class CTime to
run the application.
In Fig. 8.1, lines 4–5 begin the CTime class definition, indicating that class CTime
inherits from class Object (of namespace System). Visual Basic programmers use
inheritance to create classes from existing classes. The Inherits keyword (line 5) followed
by class name Object indicates that class CTime inherits existing pieces of class
Object. If the programmer does not include line 5, the Visual Basic compiler includes it
implicitly. Because this is the first chapter that exposes classes, we include these declarations
for the classes in this chapter; however, we remove them in Chapter 9. A complete
understanding of inheritance is not necessary to the understanding of the concepts and programs
in this chapter. We explore inheritance in detail in Chapter 9.
1 ‘ Fig. 8.1: CTime.vb
2 ‘ Represents time in 24-hour format.
34
Class CTime
5 Inherits Object
67
‘ declare Integer instance values for hour, minute and second
8 Private mHour As Integer ‘ 0 – 23
9 Private mMinute As Integer ‘ 0 – 59
10 Private mSecond As Integer ‘ 0 – 59
11
12 ‘ Method New is the CTime constructor method, which initializes
13 ‘ instance variables to zero
14 Public Sub New()
15 SetTime(0, 0, 0)
16 End Sub ‘ New
17
18 ‘ set new time value using universal time;
19 ‘ perform validity checks on data;
20 ‘ set invalid values to zero
21 Public Sub SetTime(ByVal hourValue As Integer, _
22 ByVal minuteValue As Integer, ByVal secondValue As Integer)
23
24 ‘ check if hour is between 0 and 23, then set hour
25 If (hourValue >= 0 AndAlso hourValue = 0 AndAlso minuteValue = 0 AndAlso secondValue < 60) Then
40 mSecond = secondValue
41 Else
42 mSecond = 0
43 End If
44
45 End Sub ' SetTime
46
47 ' convert String to universal-time format
48 Public Function ToUniversalString() As String
49 Return String.Format("{0}:{1:D2}:{2:D2}", _
50 mHour, mMinute, mSecond)
51 End Function ' ToUniversalString
52
53 ' convert to String in standard-time format
54 Public Function ToStandardString() As String
55 Dim suffix As String = " PM"
56 Dim format As String = "{0}:{1:D2}:{2:D2}"
57 Dim standardHour As Integer
58
59 ' determine whether time is AM or PM
60 If mHour = 0 AndAlso hourValue = 0 AndAlso minuteValue = 0 AndAlso secondValue < 60) Then
67 mSecond = secondValue
68 Else
69 mSecond = 0
70 End If
71
72 End Sub ' SetTime
73
74 ' convert String to universal-time format
75 Public Function ToUniversalString() As String
76 Return String.Format("{0}:{1:D2}:{2:D2}", _
77 mHour, mMinute, mSecond)
78 End Function ' ToUniversalString
79
80 ' convert to String in standard-time format
81 Public Function ToStandardString() As String
82 Dim suffix As String = " PM"
83 Dim format As String = "{0}:{1:D2}:{2:D2}"
84 Dim standardHour As Integer
85
86 ' determine whether time is AM or PM
87 If mHour = 0 AndAlso value = 0 AndAlso value = 0 AndAlso value < 60) Then
109 mSecond = value
110 Else
111 mSecond = 0
112 End If
113
114 End Set
115
116 End Property ' Second
117
118 ' convert String to universal-time format
119 Public Function ToUniversalString() As String
120 Return String.Format("{0}:{1:D2}:{2:D2}", _
121 mHour, mMinute, mSecond)
122 End Function ' ToUniversalString
123
124 ' convert to String in standard-time format
125 Public Function ToStandardString() As String
126 Dim suffix As String = " PM"
127 Dim format As String = "{0}:{1:D2}:{2:D2}"
128 Dim standardHour As Integer
129
130 ' determine whether time is AM or PM
131 If mHour 0 AndAlso monthValue 0 AndAlso _
45 testDayValue <= daysPerMonth(mMonth)) Then
46
47 Return testDayValue
48 End If
49
50 ' check for leap year in February
51 If (mMonth = 2 AndAlso testDayValue = 29 AndAlso _
52 mYear Mod 400 = 0 OrElse mYear Mod 4 = 0 AndAlso _
53 mYear Mod 100 0) Then
54
55 Return testDayValue
56 Else
57
58 ‘ inform user of error
59 Dim errorMessage As String = _
60 “day ” & testDayValue & “invalid. Set to day 1. ”
61
62 MessageBox.Show(errorMessage, “”, _
63 MessageBoxButtons.OK, MessageBoxIcon.Error)
64
65 Return 1 ‘ leave object in consistent state
66 End If
67
68 End Function ‘ CheckDay
69
70 ‘ create string containing month/day/year format
71 Public Function ToStandardString() As String
72 Return mMonth & “/” & mDay & “/” & mYear
73 End Function ‘ ToStandardString
74
75 End Class ‘ CDay
Fig. 8.8 CDay class encapsulates day, month and year information (part 2 of 2).
Chapter 8 Object-Based Programming 323
Class CEmployee (Fig. 8.9) holds information relating to an employee’s birthday
and hire date (lines 7–10) using instance variables mFirstName, mLastName,
mBirthDate and mHireDate. Members mBirthDate and mHireDate are references
to CDay objects, each of which contains instance variables mMonth, mDay and
mYear. In this example, class CEmployee is composed of two references of class CDay.
The CEmployee constructor (lines 13–32) takes eight arguments (firstNameValue,
lastNameValue, birthMonthValue, birthDayValue, birthYearValue,
hireMonthValue, hireDayValue and hireYearValue). Lines 26–27 pass arguments
birthMonthValue, birthDayValue and birthYearValue to the CDay
constructor to create the mBirthDate object. Similarly, lines 30–31 pass arguments
hireMonthValue, hireDayValue and hireYearValue to the CDay constructor
to create the mHireDate object.
Module modCompositionTest (Fig. 8.10) runs the application with method
Main. Lines 9–10 instantiate a CEmployee object (“Bob Jones” with birthday 7/
24/1949 and hire date 3/12/1988), and lines 12–13 display the information to the
user in a MessageBox.
1 ‘ Fig. 8.9: CEmployee.vb
2 ‘ Represent employee name, birthday and hire date.
34
Class CEmployee
5 Inherits Object
67
Private mFirstName As String
8 Private mLastName As String
9 Private mBirthDate As CDay ‘ member object reference
10 Private mHireDate As CDay ‘ member object reference
11
12 ‘ CEmployee constructor
13 Public Sub New(ByVal firstNameValue As String, _
14 ByVal lastNameValue As String, _
15 ByVal birthMonthValue As Integer, _
16 ByVal birthDayValue As Integer, _
17 ByVal birthYearValue As Integer, _
18 ByVal hireMonthValue As Integer, _
19 ByVal hireDayValue As Integer, _
20 ByVal hireYearValue As Integer)
21
22 mFirstName = firstNameValue
23 mLastName = lastNameValue
24
25 ‘ create CDay instance for employee birthday
26 mBirthDate = New CDay(birthMonthValue, birthDayValue, _
27 birthYearValue)
28
29 ‘ create CDay instance for employee hire date
30 mHireDate = New CDay(hireMonthValue, hireDayValue, _
31 hireYearValue)
32 End Sub ‘ New
Fig. 8.9 CEmployee class encapsulates employee name, birthday and hire date
(part 1 of 2).
324 Object-Based Programming Chapter 8
8.9 Using the Me Reference
Every object can access a reference to itself via the Me reference. The Me reference is used
implicitly refer to instance variables, properties and methods of an object. We begin with
an example of using reference Me explicitly and implicitly to display the Private data of
an object.
Class CTime4 (Fig. 8.11) defines three Private instance variables—mHour, mMinute
and mSecond (line 5). The constructor (lines 8–14) receives three Integer arguments
to initialize a CTime4 object. Note that for this example, we have made the
constructor’s parameter names (lines 8–9) identical to the class’s instance variable names
(line 5). A method’s local variable that has the same name as a class’s instance variable hides
the instance variable in that method’s scope. However, the method can use reference Me to
refer to these instance variables explicitly. Lines 11–13 of Fig. 8.11 demonstrate this feature.
33
34 ‘ return employee information as standard-format String
35 Public Function ToStandardString() As String
36 Return mLastName & “, ” & mFirstName & ” Hired: ” _
37 & mHireDate.ToStandardString() & ” Birthday: ” & _
38 mBirthDate.ToStandardString()
39 End Function ‘ ToStandardString
40
41 End Class ‘ CEmployee
1 ‘ Fig. 8.10: CompositionTest.vb
2 ‘ Demonstrate an object with member object reference.
34
Imports System.Windows.Forms
56
Module modCompositionTest
78
Sub Main()
9 Dim employee As New CEmployee( _
10 “Bob”, “Jones”, 7, 24, 1949, 3, 12, 1988)
11
12 MessageBox.Show(employee.ToStandardString(), _
13 “Testing Class Employee”)
14 End Sub ‘ Main
15
16 End Module ‘ modCompositionTest
Fig. 8.10 Composition demonstration.
Fig. 8.9 CEmployee class encapsulates employee name, birthday and hire date
(part 2 of 2).
Chapter 8 Object-Based Programming 325
Method BuildString (lines 17–20) returns a String created by a statement that
uses the Me reference explicitly and implicitly. Line 18 uses the Me reference explicitly to
call method ToUniversalString, whereas line 19 uses the Me reference implicitly to
call method ToUniversalString. Note that both lines perform the same task (i.e., generate
identical output). Because of this, programmers usually do not use the Me reference
explicitly to reference methods.
Common Programming Error 8.6
For a method in which a parameter has the same name as an instance variable, use reference
Me to access the instance variable explicitly; otherwise, the method parameter is referenced. 8.6
Testing and Debugging Tip 8.3
Avoidance of method-parameter names that conflict with instance variable names helps prevent
certain subtle, hard-to-trace bugs. 8.3
Good Programming Practice 8.7
The explicit use of the Me reference can increase program clarity where Me is optional. 8.7
Module modMeTest (Fig. 8.12) runs the application that demonstrates the use of the
Me reference. Line 9 instantiates an instance of class CTime4. Lines 11–12 invoke method
BuildString, then display the results to the user in a MessageBox.
1 ‘ Fig. 8.11: CTime4.vb
2 ‘ Encapsulate time using Me reference.
34
Class CTime4
5 Private mHour, mMinute, mSecond As Integer
67
‘ CTime4 constructor
8 Public Sub New(ByVal mHour As Integer, _
9 ByVal mMinute As Integer, ByVal mSecond As Integer)
10
11 Me.mHour = mHour
12 Me.mMinute = mMinute
13 Me.mSecond = mSecond
14 End Sub ‘ New
15
16 ‘ create String using Me and implicit references
17 Public Function BuildString() As String
18 Return “Me.ToUniversalString(): ” & Me.ToUniversalString() _
19 & vbCrLf & “ToUniversalString(): ” & ToUniversalString()
20 End Function ‘ BuildString
21
22 ‘ convert to String in standard-time format
23 Public Function ToUniversalString() As String
24 Return String.Format(“{0:D2}:{1:D2}:{2:D2}”, _
25 mHour, mMinute, mSecond)
26 End Function ‘ ToUniversalString
27
28 End Class ‘ CTime4
Fig. 8.11 Class using Me reference.
326 Object-Based Programming Chapter 8
8.10 Garbage Collection
In previous examples, we have seen how a constructor method initializes data in an object
of a class after the object is created. Keyword New allocates memory for the object, then
calls that object’s constructor. The constructor might acquire other system resources, such
as network connections and database connections. Objects must have a disciplined way to
return memory and release resources when the program no longer uses those objects. Failure
to release such resources causes resource leaks.
Unlike C and C++, in which programmers must manage memory explicitly, Visual
Basic performs memory management internally. The .NET Framework performs garbage
collection of memory to return memory that is no longer needed back to the system. When
the garbage collector executes, it locates objects for which the application has no references.
Such objects can be collected at that time or in a subsequent execution of the garbage
collector. Therefore, the memory leaks that are common in such languages as C and C++,
where memory is not reclaimed automatically, are rare in Visual Basic.
Dependence on Visual Basic’s automatic garbage collection, however, might not be the
best way to manage resources. Certain resources, such as network connections, database connections
and file streams, are better handled explicitly by the programmer. One technique
employed to handle these resources (in conjunction with the garbage collector) is to define a
finalizer method that returns resources to the system. The garbage collector calls an object’s
finalizer method to perform termination housekeeping on that object just before the garbage
collector reclaims the object’s memory (this process is called finalization).
Class Object defines method Finalize, which is the finalizer method for all
Visual Basic objects. Because all Visual Basic classes inherit from class Object, they
1 ‘ Fig. 8.12: MeTest.vb
2 ‘ Demonstrates Me reference.
34
Imports System.Windows.Forms
56
Module modMeTest
78
Sub Main()

Tinggalkan Balasan

Please log in using one of these methods to post your comment:

Logo WordPress.com

You are commenting using your WordPress.com account. Logout / Ubah )

Gambar Twitter

You are commenting using your Twitter account. Logout / Ubah )

Foto Facebook

You are commenting using your Facebook account. Logout / Ubah )

Foto Google+

You are commenting using your Google+ account. Logout / Ubah )

Connecting to %s