5.6. switch Multiple-Selection
Statement
We discussed the if
single-selection statement and the if...else double-selection statement
in Chapter
4. C++ provides the switch
multiple-selection statement to perform many
different actions based on the possible values of a variable or expression. Each
action is associated with the value of a constant
integral expression (i.e., any
combination of character constants and integer constants that evaluates to a
constant integer value) to which the variable or expression may evaluate.
GradeBook Class with switch Statement to Count A, B, C, D and F
Grades
We now present an enhanced version of
the Grade Book class introduced in Chapter
3 and further developed in Chapter
4. The new version of the class asks the user to enter
a set of letter grades, then displays a summary of the number of students who
received each grade. The class uses a switch to
determine whether each grade entered is an A, B, C, D or F and to increment the
appropriate grade counter. Class GradeBook is defined in Fig. 5.9, and its member-function definitions appear in Fig. 5.10. Figure 5.11 shows sample inputs and
outputs of the main program that uses class GradeBook to
process a set of grades.
Fig. 5.9. GradeBook class
definition.
1 // Fig. 5.9: GradeBook.h
2 // Definition of class GradeBook that counts A, B, C, D and F grades.
3 // Member functions are defined in GradeBook.cpp
4
5 #include <string> // program uses C++ standard string class
6 using std::string;
7
8 // GradeBook class definition
9 class GradeBook
10 {
11 public:
12 GradeBook( string ); // constructor initializes course name
13 void setCourseName( string ); // function to set the course name
14 string getCourseName(); // function to retrieve the course name
15 void displayMessage(); // display a welcome message
16 void inputGrades(); // input arbitrary number of grades from user
17 void displayGradeReport(); // display a report based on the grades
18 private:
19 string courseName; // course name for this GradeBook
20 int aCount; // count of A grades
21 int bCount; // count of B grades
22 int cCount; // count of C grades
23 int dCount; // count of D grades
24 int fCount; // count of F grades
25 }; // end class GradeBook
|
Fig. 5.10. GradeBook class uses a
switch statement to count letter grades A, B, C, D and
F.
1 // Fig. 5.10: GradeBook.cpp
2 // Member-function definitions for class GradeBook that
3 // uses a switch statement to count A, B, C, D and F grades.
4 #include <iostream>
5 using std::cout;
6 using std::cin;
7 using std::endl;
8
9 #include "GradeBook.h" // include definition of class GradeBook
10
11 // constructor initializes courseName with string supplied as argument;
12 // initializes counter data members to 0
13 GradeBook::GradeBook( string name )
14 {
15 setCourseName( name ); // validate and store courseName
16 aCount = 0; // initialize count of A grades to 0
17 bCount = 0; // initialize count of B grades to 0
18 cCount = 0; // initialize count of C grades to 0
19 dCount = 0; // initialize count of D grades to 0
20 fCount = 0; // initialize count of F grades to 0
21 } // end GradeBook constructor
22
23 // function to set the course name; limits name to 25 or fewer characters
24 void GradeBook::setCourseName( string name )
25 {
26 if ( name.length() <= 25 ) // if name has 25 or fewer characters
27 courseName = name; // store the course name in the object
28 else // if name is longer than 25 characters
29 { // set courseName to first 25 characters of parameter name
30 courseName = name.substr( 0, 25 ); // select first 25 characters
31 cout << "Name \"" << name << "\" exceeds maximum length (25).\n"
32 << "Limiting courseName to first 25 characters.\n" << endl;
33 } // end if...else
34 } // end function setCourseName
35
36 // function to retrieve the course name
37 string GradeBook::getCourseName()
38 {
39 return courseName;
40 } // end function getCourseName
41
42 // display a welcome message to the GradeBook user
43 void GradeBook::displayMessage()
44 {
45 // this statement calls getCourseName to get the
46 // name of the course this GradeBook represents
47 cout << "Welcome to the grade book for\n" << getCourseName() << "!\n"
48 << endl;
49 } // end function displayMessage
50
51 // input arbitrary number of grades from user; update grade counter
52 void GradeBook::inputGrades()
53 {
54 int grade; // grade entered by user
55
56 cout << "Enter the letter grades." << endl
57 << "Enter the EOF character to end input." << endl;
58
59 // loop until user types end-of-file key sequence
60 while ( ( grade = cin.get() ) != EOF )
61 {
62 // determine which grade was entered
63 switch ( grade ) // switch statement nested in while
64 {
65 case 'A': // grade was uppercase A
66 case 'a': // or lowercase a
67 aCount++; // increment aCount
68 break; // necessary to exit switch
69
70 case 'B': // grade was uppercase B
71 case 'b': // or lowercase b
72 bCount++; // increment bCount
73 break; // exit switch
74
75 case 'C': // grade was uppercase C
76 case 'c': // or lowercase c
77 cCount++; // increment cCount
78 break; // exit switch
79
80 case 'D': // grade was uppercase D
81 case 'd': // or lowercase d
82 dCount++; // increment dCount
83 break; // exit switch
84
85 case 'F': // grade was uppercase F
86 case 'f': // or lowercase f
87 fCount++; // increment fCount
88 break; // exit switch
89
90 case '\n': // ignore newlines,
91 case '\t': // tabs,
92 case ' ': // and spaces in input
93 break; // exit switch
94
95 default: // catch all other characters
96 cout << "Incorrect letter grade entered."
97 << " Enter a new grade." << endl;
98 break; // optional; will exit switch anyway
99 } // end switch
100 } // end while
101 } // end function inputGrades
102
103 // display a report based on the grades entered by user
104 void GradeBook::displayGradeReport()
105 {
106 // output summary of results
107 cout << "\n\nNumber of students who received each letter grade:"
108 << "\nA: " << aCount // display number of A grades
109 << "\nB: " << bCount // display number of B grades
110 << "\nC: " << cCount // display number of C grades
111 << "\nD: " << dCount // display number of D grades
112 << "\nF: " << fCount // display number of F grades
113 << endl;
114 } // end function displayGradeReport
|
Fig. 5.11. Creating a GradeBook object and
calling its member functions.
1 // Fig. 5.11: fig05_11.cpp
2 // Create GradeBook object, input grades and display grade report.
3
4 #include "GradeBook.h" // include definition of class GradeBook
5
6 int main()
7 {
8 // create GradeBook object
9 GradeBook myGradeBook( "CS101 C++ Programming" );
10
11 myGradeBook.displayMessage(); // display welcome message
12 myGradeBook.inputGrades(); // read grades from user
13 myGradeBook.displayGradeReport(); // display report based on grades
14 return 0; // indicate successful termination
15 } // end main
|
Welcome to the grade book for
CS101 C++ Programming!
Enter the letter grades.
Enter the EOF character to end input.
a
B
c
C
A
d
f
C
E
Incorrect letter grade entered. Enter a new grade.
D
A
b
^Z
Number of students who received each letter grade:
A: 3
B: 2
C: 3
D: 2
F: 1
|
Like earlier versions of the class definition, the
GradeBook class definition (Fig. 5.9) contains function
prototypes for member functions setCourseName (line 13),
getCourseName (line 14) and displayMessage (line 15), as well
as the class's constructor (line 12). The class definition also declares
private data member courseName (line 19).
Class GradeBook (Fig. 5.9) now contains five
additional private data members (lines
20–24)—counter variables for each grade category (i.e., A, B, C, D and F). The
class also contains two additional public member functions—inputGrades and
displayGradeReport. Member function inputGrades (declared in line 16) reads an arbitrary number of
letter grades from the user using sentinel-controlled repetition and updates the
appropriate grade counter for each grade entered. Member function
displayGradeReport (declared in line 17) outputs
a report containing the number of students who received each letter grade.
Source-code file GradeBook.cpp (Fig. 5.10) contains the member-function definitions for class
GradeBook. Notice that lines 16–20 in the
constructor initialize the five grade counters to 0—when a
GradeBook object is first created, no
grades have been entered yet. As you'll soon see, these counters are incremented
in member function inputGrades as the
user enters grades. The definitions of member functions setCourseName,
getCourseName and displayMessage are
identical to those found in the earlier versions of class GradeBook.
Let's consider the new GradeBook member functions in detail.
Reading Character Input
The user enters letter grades for a course in member function
inputGrades (lines 52–101). Inside the
while header, in line 60, the
parenthesized assignment ( grade = cin.get() ) executes first. The
cin.get() function reads one character
from the keyboard and stores that character in integer variable grade (declared in line 54). Characters normally are
stored in variables of type char; however, characters can be stored in any integer data
type, because types short, int and long are
guaranteed to be at least as big as type char. Thus,
we can treat a character either as an integer or as a character, depending on
its use. For example, the statement
cout << "The character (" << 'a' << ") has the value "
<< static_cast< int > ( 'a' ) << endl;
prints the character a and its integer value as
follows:
The character (a) has the value 97
The integer 97 is the character's
numerical representation in the computer. Most computers today use the ASCII (American Standard Code for Information
Interchange) character set, in which
97 represents the lowercase letter 'a'. A
table of the ASCII characters and their decimal equivalents is presented in Appendix
B, ASCII Character Set.
Assignment statements as a whole have the
value that is assigned to the variable on the left side of the =. Thus, the value of the assignment expression
grade = cin.get() is the same as the value
returned by cin.get() and assigned to the
variable grade.
The fact that assignment
expressions have values can be useful for assigning the same value to several
variables. For example,
first evaluates the assignment c = 0 (because the
= operator associates from right to left). The variable b is then assigned the value of the assignment c = 0
(which is 0). Then, the variable a is assigned the
value of the assignment b = (c = 0) (which is also 0). In the program,
the value of the assignment grade = cin.get() is compared with the
value of EOF (a symbol whose acronym stands for "end-of-file"). We use
EOF (which normally has the value –1) as the sentinel value. However, you do not type the value
–1, nor do you type the letters EOF as the sentinel value. Rather, you type a system-dependent keystroke combination
that means "end-of-file" to indicate that you have no more data to enter.
EOF is a symbolic integer constant
defined in the <iostream> header
file. If the value assigned to grade is equal to
EOF, the while loop (lines 60–100)
terminates. We have chosen to represent the characters entered into this program
as ints, because EOF has type int.
On UNIX/Linux systems and many others, end-of-file is entered
by typing
<Ctrl> d
on a line by itself. This notation
means to press and hold down the Ctrl key, then
press the d key. On
other systems such as Microsoft Windows, end-of-file can be entered by
typing
<Ctrl> z
[Note: In some
cases, you must press Enter after the preceding
key sequence. Also, the characters ^Z sometimes appear on the screen to
represent end-of-file, as shown in Fig. 5.11.]
Portability Tip 5.2
|
The keystroke combinations for entering
end-of-file are system
dependent. |
Portability Tip 5.3
|
Testing for the symbolic constant
EOF rather than –1 makes programs more
portable. The ANSI/ISO C standard, from which C++ adopts the definition of
EOF, states that EOF is a negative integral value (but not necessarily
–1), so EOF could have different
values on different systems. |
In this program, the user enters grades
at the keyboard. When the user presses the Enter
(or Return) key, the
characters are read by the cin.get() function,
one character at a time. If the character entered is not end-of-file, the flow
of control enters the switch statement (lines
63–99), which increments the appropriate letter-grade counter based on the grade
entered.
switch Statement Details
The switch statement consists
of a series of case labels and an
optional default case. These are used in this example to determine which
counter to increment, based on a grade. When the flow of control reaches the
switch, the program evaluates the expression
in the parentheses (i.e., grade) following keyword switch (line 63). This is called the controlling expression. The switch statement compares the value of the controlling expression
with each case label. Assume the user enters
the letter C as a grade. The program
compares C to each case in the switch. If a match occurs
(case 'C': in line 75), the program executes the statements for that
case. For the letter C, line 77 increments cCount by
1. The break statement (line 78) causes program
control to proceed with the first statement after the switch—in this program, control transfers to line 100. This line
marks the end of the body of the while loop
that inputs grades (lines 60–100), so control flows to the while's
condition (line 60) to determine whether the loop should continue executing.
The cases in our switch explicitly test for the lowercase and uppercase versions
of the letters A, B, C, D and F. Note the cases
in lines 65–66 that test for the values 'A' and 'a' (both of which represent the grade A). Listing
cases consecutively in this manner with no
statements between them enables the cases to
perform the same set of statements—when the controlling expression evaluates to
either 'A' or 'a', the statements in
lines 67–68 will execute. Note that each case can have multiple
statements. The switch selection statement
differs from other control statements in that it does not require braces around
multiple statements in each case.
Without break statements, each time a match occurs in
the switch, the statements for that case and subsequent
cases execute until a break statement or the end of the
switch is encountered. This is often referred to
as "falling through" to the statements in subsequent cases.
Common Programming Error 5.8
|
Forgetting a break statement when one is needed in a switch
statement is a logic error. |
Common Programming Error 5.9
|
Omitting the space between the word
case and the integral value being tested in a switch statement
can cause a logic error. For example, writing case3: instead of
case 3: simply creates an unused label. In this situation, the
switch statement will not perform the appropriate actions when the
switch's controlling expression has a value of
3. |
Providing a default Case
If no match occurs between the controlling expression's value
and a case label, the default case (lines 95–98) executes. We
use the default case in this example to
process all controlling-expression values that are neither valid grades nor
newline, tab or space characters (we discuss how the program handles these
whitespace characters shortly). If no match occurs, the default case executes, and lines 96–97 print an error message
indicating that an incorrect letter grade was entered. If no match occurs in a
switch statement that does not contain a
default case, program control simply
continues with the first statement after the switch.
Good Programming Practice 5.6
|
Provide a default case in
switch statements. Cases not explicitly tested
in a switch statement without a default case are ignored.
Including a default case focuses you on
the need to process exceptional conditions. There are situations in which no
default processing is needed. Although the case clauses and
the default case clause in a switch statement can occur in any order, it is common
practice to place the default clause
last. |
Good Programming Practice 5.7
|
The last case in a
switch statement does not require a break
statement. Some programmers include this break for clarity and for
symmetry with other cases. |
Ignoring Newline, Tab and Blank
Characters in Input
Note that lines 90–93 in the
switch statement of Fig. 5.10 cause
the program to skip newline, tab and blank characters. Reading characters one at
a time can cause some problems. To have the program read the characters, we must
send them to the computer by pressing the Enter key on the keyboard. This places a newline character in the
input after the character we wish to process. Often, this newline character must
be specially processed to make the program work correctly. By including the
preceding cases in our switch
statement, we prevent the error message in the default case from being printed each time a newline, tab or
space is encountered in the input.
Common Programming Error 5.10
|
Not processing
newline and other whitespace characters in the input when reading characters one
at a time can cause logic
errors. |
Testing Class GradeBook
Figure
5.11 creates a GradeBook object (line 9). Line 11 invokes the its
displayMessage member function to output a
welcome message to the user. Line 12 invokes member function object's
inputGrades to read a set of grades from the
user and keep track of how many students received each grade. Note that the
output window in Fig.
5.11 shows an error message displayed in response
to entering an invalid grade (i.e., E). Line 13 invokes
GradeBook member function displayGradeReport (defined in lines
104–114 of Fig.
5.10), which outputs a report based on the grades
entered (as in the output in Fig. 5.11).
switch Statement UML Activity Diagram
Figure 5.12
shows the UML activity diagram for the general switch
multiple-selection statement. Most switch statements use a
break in each case to terminate the switch statement after processing the case. Figure 5.12
emphasizes this by including break
statements in the activity diagram. Without the break statement, control would not transfer to the first
statement after the switch statement after a case is
processed. Instead, control would transfer to the next case's
actions.

The diagram makes it clear that the break statement at
the end of a case causes control to exit the switch statement immediately. Again, note that (besides an
initial state, transition arrows, a final state and several notes) the diagram
contains action states and decisions. Also, note that the diagram uses merge
symbols to merge the transitions from the break statements to the final
state.
Imagine, again, that you have a bin of empty switch statement UML activity diagrams—as many as you might need to
stack and nest with the activity diagrams of other control statements to form a
structured implementation of an algorithm. You fill in the action states and
decision symbols with action expressions and guard conditions appropriate to the
algorithm. Note that, although nested control statements are common, it is rare
to find nested switch statements in a program.
When using the switch statement, remember that each
case can be used to test only a constant integral expression—any
combination of character constants and integer constants that evaluates to a
constant integer value. A character constant is represented as the specific
character in single quotes, such as 'A'. An
integer constant is simply an integer value. Also, each case label can specify only one constant integral
expression.
Common Programming Error 5.11
|
Specifying a nonconstant integral expression in a
switch statement's case label is a
syntax error. |
Common Programming Error 5.12
|
Providing
identical case labels in a switch statement
is a compilation error. Providing case labels containing different expressions
that evaluate to the same value also is a compilation error. For example,
placing case 4 + 1: and case 3 + 2: in the same
switch statement is a compilation error,
because these are both equivalent to case
5:. |
In Chapter
13, we present a more elegant way to implement
switch logic. We'll use a technique called
polymorphism to create programs that are often clearer, more concise, easier to
maintain and easier to extend than programs that use switch
logic.
Notes on Data Types
C++ has flexible data type sizes
(see Appendix
C, Fundamental Types). Different applications, for
example, might need integers of different sizes. C++ provides several data types
to represent integers. The range of integer values for each type depends on the
particular computer's hardware. In addition to the types int and
char, C++ provides the types short (an abbreviation of
short int) and long (an abbreviation of long int). The minimum range of values for short integers is –32,768 to 32,767. For the vast majority of integer
calculations, long integers are sufficient.
The minimum range of values for long integers is –2,147,483,648 to
2,147,483,647. On most computers, ints are equivalent either to
short or to long. The range of values for an int is
at least the same as that for short integers and no larger than that for long integers. The data
type char can be used to represent any of
the characters in the computer's character set. It also can be used to represent
small integers.
Portability Tip 5.4
|
Because ints can vary in size
between systems, use long integers if you
expect to process integers outside the range –32,768 to 32,767 and you would
like to run the program on several different computer
systems. |
Performance Tip 5.3
|
If memory is at
a premium, it might be desirable to use smaller integer
sizes. |
Performance Tip 5.4
|
Using smaller
integer sizes can result in a slower program if the machine's instructions for
manipulating them are not as efficient as those for the natural-size
integers—i.e., integers whose size equals the machine's word size (e.g., 32 bits
on a 32-bit machine, 64 bits on a 64-bit machine). Always test proposed
efficiency "upgrades" to be sure they really improve
performance. |