Main Page

Previous Page
Next Page

[Page 199 (continued)]

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) that the variable or expression on which the switch is based may assume.

[Page 200]

GradeBook Class with switch Statement to Count A, B, C, D and F Grades

In the next example, we present an enhanced version of the GradeBook 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.

Figure 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
 5  #include <string> // program uses C++ standard string class
 6  using std::string;
 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

Figure 5.10. GradeBook class uses switch statement to count letter grades A, B, C, D and F.
(This item is displayed on pages 201 - 203 in the print version)

 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;
 9   #include "GradeBook.h" // include definition of class GradeBook
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
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
36   // function to retrieve the course name
37   string GradeBook::getCourseName()
38   {
39      return courseName;
40   } // end function getCourseName
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
51   // input arbitrary number of grades from user; update grade counter
52   void GradeBook::inputGrades()
53   {
54      int grade; // grade entered by user
56      cout << "Enter the letter grades." << endl
57         << "Enter the EOF character to end input." << endl;
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            
70            case 'B': // grade was uppercase B               
71            case 'b': // or lowercase b                      
72               bCount++; // increment bCount                 
73               break; // exit switch                         
75            case 'C': // grade was uppercase C               
76            case 'c': // or lowercase c                      
77               cCount++; // increment cCount                 
78               break; // exit switch                         
80            case 'D': // grade was uppercase D               
81            case 'd': // or lowercase d                      
82               dCount++; // increment dCount                 
83               break; // exit switch                         
85            case 'F': // grade was uppercase F               
86            case 'f': // or lowercase f                      
87               fCount++; // increment fCount                 
88               break; // exit switch                         
90            case '\n': // ignore newlines,                   
91            case '\t': // tabs,                              
92            case ' ': // and spaces in input                 
93               break; // exit switch                         
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
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

Figure 5.11. Creating a GradeBook object and calling its member functions.
(This item is displayed on pages 206 - 207 in the print version)

 1  // Fig. 5.11: fig05_11.cpp
 2  // Create GradeBook object, input grades and display grade report.
 4  #include "GradeBook.h" // include definition of class GradeBook
 6  int main()
 7  {
 8     // create GradeBook object
 9     GradeBook myGradeBook( "CS101 C++ Programming" );
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.
 Incorrect letter grade entered. Enter a new grade.

 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 2024)counter variables for each grade category (i.e., A, B, C, D and F). The class also contains two additional public member functionsinputGrades 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 1620 in the constructor initialize the five grade counters to 0when a GradeBook object is first created, no grades have been entered yet. As you will 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.

[Page 203]

Reading Character Input

The user enters letter grades for a course in member function inputGrades (lines 52101). Inside the while header, at 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 they are represented as 1-byte integers in the computer. 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.

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 statements have values can be useful for assigning the same value to several variables. For example,

a = b = c = 0;

[Page 204]

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 60100) terminates. We have chosen to represent the characters entered into this program as ints, because EOF has an integer value.

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 is 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 6399), 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': at 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 switchin this program, control transfers to line 100. This line marks the end of the body of the while loop that inputs grades (lines 60100), so control flows to the while's condition (line 60) to determine whether the loop should continue executing.

[Page 205]

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 at lines 6566 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 statementswhen the controlling expression evaluates to either 'A' or 'a', the statements at lines 6768 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. (This feature is perfect for writing a concise program that displays the iterative song "The Twelve Days of Christmas" in Exercise 5.28.)

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 writing case 3: simply creates an unused label. We will say more about this in Appendix E, C Legacy Code Topics. 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 9598) 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 white-space characters shortly). If no match occurs, the default case executes, and lines 9697 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.10

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 the programmer 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.11

In a switch statement that lists the default clause last, the default clause does not require a break statement. Some programmers include this break for clarity and for symmetry with other cases.

[Page 206]

Ignoring Newline, Tab and Blank Characters in Input

Note that lines 9093 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 white-space 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 object's displayMessage member function to output a welcome message to the user. Line 12 invokes the object's inputGrades member function to read a set of grades from the user and keep track of the number of students who received each grade. Note that the input/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 104114 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.

Figure 5.12. switch multiple-selection statement UML activity diagram with break statements.
(This item is displayed on page 208 in the print version)

[Page 207]

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 the programmer has a bin of empty switch statement UML activity diagramsas many as the programmer might need to stack and nest with the activity diagrams of other control statements to form a structured implementation of an algorithm. The programmer fills 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 it can be used only for testing a constant integral expressionany 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 an expression including variables (e.g., a + b) in a switch statement's case label is a syntax error.

[Page 208]

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 will 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.

[Page 209]

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.

Previous Page
Next Page