Previous: 4.3 New Control Constructs
Up: 4.3 New Control Constructs
Next: 4.3.2 The break Statement
Previous Page: 4.3 New Control Constructs
In a switch statement, the value of an integer valued expression determines an alternate path to be executed. The syntax of the switch statement is:
Each statement, except the last, starts with a case label which consists of the keyword case followed by a constant expression, followed by a colon. The constant expression, (whose value must be known at compile time) is called a case expression. An optional default label is also allowed after all the case labels. Executable statements appear after the labels as shown.
The semantics of the switch statement is as follows:
The expression, <expression> is evaluated to an integer value,
and control then passes to the first
case label whose case expression value matches the value of the switch
expression. If no case expression value matches,
control passes to the statement with the default label, if present.
This control flow is shown in Figure 4.17.
Labels play no role other than to serve as markers for transferring control to the appropriate statements. Once control passes to a labeled statement, the execution proceeds from that point and continues to process each of the subsequent statements until the end of the switch statement.
As an example,
we use the switch statement to write a function that tests if a character
is a vowel (the vowels are 'a', 'e', 'i', 'o', and 'u' in upper or lower case).
If a character passed to this function, which we will call vowelp()
(for vowel predicate),
is one of the above vowels, the function returns True; otherwise,
it returns False.
We add the function to our file chrutil.c, and the code is shown in
Figure 4.18.
If c matches any of the cases, control passes to the appropriate case label. For many of these cases, the <stmt> is empty, and the first non-empty statement is the return TRUE statement, which, when executed, immediately returns control to the calling function. If c is not a vowel, control passes to the default label, where the return FALSE statement is executed. While there is no particular advantage in doing so, the above function could be written with a return statement at every case label to return TRUE. The function vowelp() is much clearer and cleaner using the switch statement than it would have been using nested if statements or an if statement with a large, complex condition expression.
Remember, in a switch statement, control flow passes to the statement associated with the matching case label, and continues from there to all subsequent statements in the compound statement. Sometimes this is not the desired behavior. Consider the task of encrypting text in a very simple way, such as:
read characters until end of file if a char is a letter print the next letter in the circular alphabet else print the characterImplementation is straight forward as shown in Figure 4.19.
The program reads characters until end of file. Each character is tested to see if it is a letter using a function, letterp(). If it is a letter, print_next() is called to print the next character in the alphabet; otherwise, the character is printed as is. The function letterp() checks if a character passed as an argument is an alphabetic letter and returns True or False. The function is shown below and is added to our utility file, chrutil.c (and its prototype is assumed to be added to the file chrutil.h).
/* File: chrutil.c - continued */ /* Function tests if c is an alphabetic letter. */ int letterp(char c) { if (IS_LOWER(c) || IS_UPPER(c)) return TRUE; return FALSE; }It uses the macros IS_LOWER() and IS_UPPER(). We have already define IS_LOWER() in chrutil.h; IS_UPPER() is similar:
#define IS_UPPER(c) ((c) >= 'A' && (c) <= 'Z')and is added to chrutil.h.
Let us consider the function, print_next(), which is passed a single alphabetic letter as an argument. It should print an altered letter, that is the next letter in a circular alphabet. The altered letter is the next letter in the alphabet, unless the argument is the last letter in the alphabet. If the argument is 'z' or 'Z', then the altered letter is the first letter of the alphabet, 'a' or 'A' respectively. There are two possible instances of the character c for which we must take special action, viz. when c is 'z' or c is 'Z'. The default case is any other letter, when the function should print c + 1, which is the ASCII value of the next letter.
We need a three way decision based on the value of a character c: is c the character 'z', or 'Z', or some other character? If it is 'z' print 'a'; else if it is 'Z' print 'A'; otherwise, print c + 1. We can easily implement this multiway decision using an if ... else ... construct.
if (c == 'z') printf("%c", 'a'); else if (c == 'Z') printf("%c", 'A'); else printf("%c", c + 1);Such multiway branches can also be implemented using the switch construct. Suppose we wrote:
switch(c) { case 'z': printf("%c", 'a'); case 'Z': printf("%c", 'A'); default: printf("%c", c + 1);Will this do what we want? If c has the value 'z', the above switch statement would match the first case label and print 'a'. However, by the semantics of switch, it would then print 'A' followed by '{' (the character after 'z' in the ASCII table) --- not what we want. Can we salvage this approach to multiway branching?