CONTENTS

Chapter 6. BRANCHING STATEMENTS AND LOGICAL OPERATORS

In this chapter you learn

One of the keys to designing intelligent programs is to give them the ability to make decisions. Chapter 5, "Loops and Relational Expressions," shows you one kind of decision making條ooping梚n which a program decides whether or not to continue looping. Now you investigate how C++ lets you use branching statements to decide among alternative actions. Which vampire-protection scheme (garlic or cross) should the program use? What menu choice has the user selected? Did the user enter a zero? C++ provides the if and switch statements to implement decisions, and they are this chapter's main topics. You also look at the conditional operator, which provides another way to make a choice, and the logical operators, which let you combine two tests into one.

The if Statement

When a C++ program must choose whether or not to take a particular action, you usually implement the choice with an if statement. The if comes in two forms: if and if else. Let's investigate the simple if first. It's modeled after ordinary English, as in "If you have a Captain Cookie card, you get a free cookie." The if statement directs a program to execute a statement or statement block if a test condition is true and to skip that statement or block if the condition is false. Thus, an if statement lets a program decide whether a particular statement should be executed.

The syntax is similar to the while syntax:

if (test-condition)
    statement

A true test-condition causes the program to execute statement, which can be a single statement or a block. A false test-condition causes the program to skip statement. (See Figure 6.1.) As with loop test conditions, an if test condition is typecast to a bool value, so zero becomes false and nonzero becomes true. The entire if construction counts as a single statement.

Figure 6.1. The if statement.

graphics/06fig01.gif

Most often, test-condition is a relational expression such as those used to control loops. Suppose, for example, you want a program that counts the spaces in the input as well as the total number of characters. You can use cin.get(char) in a while loop to read the characters and then use an if statement to identify and count the space characters. Listing 6.1 does just that, using the period to recognize the end of a sentence.

Listing 6.1 if.cpp
// if.cpp -- using the if statement
#include <iostream>
using namespace std;
int main()
{
    char ch;
    int spaces = 0;
    int total = 0;
    cin.get(ch);
    while (ch != '.')   // quit at end of sentence
    {
        if (ch == ' ')  // check if ch is a space
            spaces++;
        total++;        // done every time
        cin.get(ch);
    }
    cout << spaces << " spaces, " << total;
    cout << " characters total in sentence\n";
    return 0;
}

Here's some sample output:

The balloonist was an airhead
with lofty goals.
6 spaces, 46 characters total in sentence

As the comments indicate, the spaces++; statement is executed only when ch is a space. Because it is outside the if statement, the total++; statement is executed every loop cycle. Note that the total count includes the newline character generated by pressing Enter.

The if else Statement

While the if statement lets a program decide whether a particular statement or block is executed, the if else statement lets a program decide which of two statements or blocks is executed. It's an invaluable statement for creating alternative courses of action. The C++ if else is modeled after simple English, as in "If you have a Captain Cookie card, you get a Cookie Plus Plus, else you just get a Cookie d'Ordinaire." The if else statement has this general form:

if (test-condition)
    statement1
else
    statement2

If test-condition is true or nonzero, the program executes statement1 and skips over statement2. Otherwise, when test-condition is false or zero, the program skips statement1 and executes statement2 instead. So the code fragment

if (answer == 1492)
    cout << "That's right!\n";
else
      cout << "You'd better review Chapter 1 again.\n";

prints the first message if answer is 1492 and prints the second message otherwise. Each statement can be either a single statement or a statement block delimited by braces. (See Figure 6.2.) The entire if else construct counts syntactically as a single statement.

Figure 6.2. The if else statement.

graphics/06fig02.gif

For example, suppose you want to alter incoming text by scrambling the letters while keeping the newline character intact. That way, each line of input is converted to an output line of equal length. This means you want the program to take one course of action for newline characters and a different course of action for all other characters. As Listing 6.2 shows, if else makes this task easy.

Listing 6.2 ifelse.cpp
// ifelse.cpp -- using the if else statement
#include <iostream>
using namespace std;
int main()
{
    char ch;

    cout << "Type, and I shall repeat.\n";
    cin.get(ch);
    while (ch != '.')
    {
        if (ch == '\n')
            cout << ch;     // done if newline
        else
            cout << ++ch;   // done otherwise
        cin.get(ch);
    }
// try ch + 1 instead of ++ch for interesting effect
    cout << "\nPlease excuse the slight confusion.\n";
    return 0;
}

Here's some sample output:

Type, and I shall repeat.
I am extraordinarily pleased
J!bn!fyusbpsejobsjmz!qmfbtfe
to use such a powerful computer.
up!vtf!tvdi!b!qpxfsgvm!dpnqvufs
Please excuse the slight confusion.

Note that one of the program comments suggests that changing ++ch to ch+1 has an interesting effect. Can you deduce what it will be? If not, try it out and then see if you can explain what's happening. (Hint: Think about how cout handles different types.)

Formatting Your if else Statements

Keep in mind that the two if else alternatives must be single statements. If you need more than one statement, use braces to collect them into a single block statement. Unlike some languages, such as BASIC or FORTRAN, C++ does not automatically consider everything between if and else a block, so you have to use braces to make the statements a block. The following code, for example, produces a compiler error. The compiler sees it as a simple if statement that ends with the zorro++; statement. Then there is a cout statement. So far, so good. But then there is what the compiler perceives as an unattached else, and that is flagged as a syntax error.

if (ch == 'Z')
    zorro++;      // if ends here
    cout << "Another Zorro candidate\n";
else               // wrong
    dull++;
    cout << "Not a Zorro candidate\n";

Add the braces to convert the code to what you want:

if (ch == 'Z')
{                        // if true block
    zorro++;
    cout << "Another Zorro candidate\n";
}
else
{                       // if false block
    dull++;
    cout << "Not a Zorro candidate\n";
}

Because C++ is a free-form language, you can arrange the braces as you like, as long as they enclose the statements. The preceding code shows one popular format. Here's another:

if (ch == 'Z') {
    zorro++;
    cout << "Another Zorro candidate\n";
    }
else {
    dull++;
    cout << "Not a Zorro candidate\n";
    }

The first form emphasizes the block structure for the statements, whereas the second form more closely ties the blocks to the keywords if and else. Either style is clear and consistent and should serve you well; however, you may encounter an instructor or employer with strong and specific views on the matter.

The if else if else Construction

Computer programs, like life, might present you with a choice of more than two selections. You can extend the C++ if else statement to meet that need. The else, you've seen, should be followed by a single statement, which can be a block. Because an if else statement itself is a single statement, it can follow an else:

if (ch == 'A')
    a_grade++;               // alternative # 1
else
    if (ch == 'B')           // alternative # 2
        b_grade++;          // subalternative # 2a
    else
        soso++;             // subalternative # 2b

If ch is not 'A', the program goes to the else. There, a second if else subdivides that alternative into two more choices. C++'s free formatting enables you to arrange these elements into an easier-to-read format:

if (ch == 'A')
    a_grade++;              // alternative # 1
else if (ch == 'B')
    b_grade++;              // alternative # 2
else
    soso++;                 // alternative # 3

This looks like a new control structure梐n if else if else structure. But actually it is one if else contained within a second. This revised format looks much cleaner, and it enables you to skim through the code to pick out the different alternatives. This entire construction still counts as one statement.

Listing 6.3 uses this preferred formatting to construct a modest quiz program.

Listing 6.3 ifelseif.cpp
// ifelseif.cpp -- using if else if else
#include <iostream>
using namespace std;
const int Fave = 27;
int main()
{
    int n;
    cout << "Enter a number in the range 1-100 to find ";
    cout << "my favorite number: ";
    do
    {
        cin >> n;
        if (n < Fave)
            cout << "Too low -- guess again: ";
        else if (n > Fave)
            cout << "Too high -- guess again: ";
        else
            cout << Fave << " is right!\n";
    } while (n != Fave);
    return 0;
}

Here's some sample output:

Enter a number in the range 1-100 to find my favorite number: 50
Too high -- guess again: 25
Too low -- guess again: 37
Too high -- guess again: 31
Too high -- guess again: 28
Too high -- guess again: 27
27 is right!

Real World Note: Conditional Operators and Bug Prevention

graphics/common.gif

Many programmers reverse the more intuitive expression variable == value to value == variable in order to catch errors where the equality is mistyped as an assignment operator. For example, entering the conditional as

if (3 == myNumber)

is valid and will work properly. However, if you happen to mistype

if (3 = myNumber)

the compiler will generate an error message, as it believes you are attempting to assign a value to a literal (3 always equals 3, and can't be assigned another value). Suppose you made a similar mistake made using the former notation:

if (myNumber = 3)

The compiler will simply assign the value 3 to myNumber, and the block within the if will run?a very common error, and a difficult error to find. As a general rule, writing code that allows the compiler to find errors is much easier than repairing the causes of mysterious faulty results.

Logical Expressions

Often you must test for more than one condition. For example, for a character to be a lowercase letter, its value must be greater than or equal to 'a' and less than or equal to 'z'. Or, if you ask a user to respond with a y or an n, you want to accept uppercase (Y and N) as well as lowercase. To meet this kind of need, C++ provides three logical operators to combine or modify existing expressions. The operators are logical OR, written ||; logical AND, written &&; and logical NOT, written !. Examine them now.

The Logical OR Operator: ||

In English, the word or can indicate when one or both of two conditions satisfy a requirement. For example, you can go to the MegaMicro company picnic if you or your spouse work for MegaMicro, Inc. The C++ equivalent is the logical OR operator, written ||. This operator combines two expressions into one. If either or both of the original expressions are true, or nonzero, the resulting expression has the value true. Otherwise the expression has the value false. Here are some examples:

5 ==5 || 5 == 9    // true because first expression is true
5 > 3 || 5 > 10    // true because first expression is true
5 > 8 || 5 < 10    // true because second expression is true
5 < 8 || 5 > 2     // true because both expressions are true
5 > 8 || 5 < 2     // false because both expressions are false

Because the || has a lower precedence than the relational operators, you don't need to use parentheses in these expressions. Table 6.1 summarizes how the || operator works.

C++ provides that the || operator is a sequence point. That is, any value changes indicated in the left side take place before the right side is evaluated. For example, consider the following expression:

i++ < 6 || i == j

Suppose i originally has the value 10. By the time the comparison with j takes place, i has the value 11. Also, C++ won't bother evaluating the expression on the right if the expression on the left is true, for it only takes one true expression to make the whole logical expression true. (The semicolon and the comma operator also are sequence points.)

Listing 6.4 uses the || operator in an if statement to check for both uppercase and lowercase versions of a character. Also, it uses C++'s string concatenation feature (see Chapter 4, "Compound Types") to spread a single string over three lines.

Table 6.1. The || Operator
The Value of expr1 || expr2
  expr1 == true expr1 == false
expr2 == true true true
expr2 == false true false
Listing 6.4 or.cpp
// or.cpp -- use logical OR operator
#include <iostream>
using namespace std;
int main()
{
    cout << "This program may reformat your hard disk\n"
            "and destroy all your data.\n"
            "Do you wish to continue? <y/n> ";
    char ch;
    cin >> ch;
    if (ch == 'y' || ch == 'Y')             // y or Y
        cout << "You were warned!\a\a\n";
    else if (ch == 'n' || ch == 'N')        // n or N
        cout << "A wise choice ... bye\n";
    else
        cout << "That wasn't a y or an n, so I guess I'll "
                "trash your disk anyway.\n";
    return 0;
}

Here is a sample run:

This program may reformat your hard disk
and destroy all your data.
Do you wish to continue? <y/n> N
A wise choice ... bye

The program reads just one character, so only the first character in the response matters. That means the user could have replied NO! instead of N. The program would just read the N. But if the program tried to read more input later, it would start at the O.

The Logical AND Operator: &&

The logical AND operator, written &&, also combines two expressions into one. The resulting expression has the value true only if both of the original expressions are true. Here are some examples:

5 == 5 && 4 == 4   // true because both expressions are true
5 == 3 && 4 == 4   // false because first expression is false
5 > 3 && 5 > 10    // false because second expression is false
5 > 8 && 5 < 10    // false because first expression is false
5 < 8 && 5 > 2     // true because both expressions are true
5 > 8 && 5 < 2     // false because both expressions are false

Because the && has a lower precedence than the relational operators, you don't need to use parentheses in these expressions. Like the || operator, the && operator acts as a sequence point, so the left side is evaluated and any side effects are carried out before the right side is evaluated. If the left side is false, the whole logical expression must be false, so C++ doesn't bother evaluating the right side in that case. Table 6.2 summarizes how the && operator works.

Table 6.2. The && Operator
The Value of expr1 && expr2
  expr1 == true expr1 == false
expr2 == true true false
expr2 == false false false

Listing 6.5 shows how to use && to cope with a common situation, terminating a while loop, for two different reasons. In the listing, a while loop reads values into an array. One test (i < ArSize) terminates the loop when the array is full. The second test (temp >= 0) gives the user the option of quitting early by entering a negative number. The && operator lets you combine the two tests into a single condition. The program also uses two if statements, an if else statement, and a for loop, so it demonstrates several topics from this and the preceding chapter.

Listing 6.5 and.cpp
// and.cpp -- use logical AND operator
#include <iostream>
using namespace std;
const int ArSize = 6;
int main()
{
    float naaq[ArSize];
    cout << "Enter the NAAQs (New Age Awareness Quotients) "
         << "of\nyour neighbors. Program terminates "
         << "when you make\n" << ArSize << " entries "
         << "or enter a negative value.\n";

    int i = 0;
    float temp;
    cin >> temp;
    while (i < ArSize && temp >= 0) // 2 quitting criteria
    {
        naaq[i++] = temp;
        if (i < ArSize)             // room left in the array,
            cin >> temp;            // so get next value
    }
    if (i == 0)
        cout << "No data--bye\n";
    else
    {
        cout << "Enter your NAAQ: ";
        float you;
        cin >> you;
        int count = 0;
        for (int j = 0; j < i; j++)
            if (naaq[j] > you)
                count++;
        cout << count;
        cout << " of your neighbors have greater awareness of\n"
             << "the New Age than you do.\n";
    }
    return 0;
}

Note that the program places input into a temporary variable temp. Only after it verifies that the input is valid does the program assign the value to the array.

Here are a couple of sample runs. One terminates after six entries, and the second terminates after a negative value is entered:

Enter the NAAQs (New Age Awareness Quotients) of
your neighbors. Program terminates when you make
6 entries or enter a negative value.
28 72 19
6
130 145
Enter your NAAQ: 50
3 of your neighbors have greater awareness of
the New Age than you do.

Enter the NAAQs (New Age Awareness Quotients) of
your neighbors. Program terminates when you make
6 entries or enter a negative value.
123 119
4
89
-1
Enter your NAAQ: 123.027
0 of your neighbors have greater awareness of
the New Age than you do.
Program Notes

Look at the input part of the program:

cin >> temp;
while (i < ArSize && temp >= 0)      // 2 quitting criteria
{
      naaq[i++] = temp;
      if (i < ArSize)                // room left in the array,
            cin >> temp;             // so read next value
}

The program begins by reading the first input value into a temporary variable called temp. Then, the while test condition checks to see if there still is room left in the array (i < ArSize) and if the input value is nonnegative (temp >= 0). If so, it copies the temp value to the array and increases the array index by 1. At this point, because array numbering starts at 0, i equals the total number of entries to date. That is, if i starts out at 0, the first cycle through the loop assigns a value to naaq[0] and then sets i to 1.

The loop terminates when the array is filled or when the user enters a negative number. Note that the loop reads another value into temp only if i is less than ArSize, that is, only if there still is room left in the array.

After it gets data, the program uses an if else statement to comment if no data were entered (that is, if the first entry was a negative number) and to process the data if any is present.

Setting Up Ranges with &&

The && operator also lets you set up a series of if else if else statements with each choice corresponding to a particular range of values. Listing 6.6 illustrates the approach. It also shows a useful technique for handling a series of messages. Just as a pointer-to-char variable can identify a single string by pointing to its beginning, an array of pointers-to-char can identify a series of strings. Simply assign the address of each string to a different array element. Listing 6.6 uses the qualify array to hold the addresses of four strings. For example, qualify[1] holds the address of the string "mud tug-of-war\n". The program then can use qualify[1] like any other pointer to a string梖or example, with cout or with strlen() or strcmp(). Using the const qualifier protects these strings from accidental alterations.

Listing 6.6 more_and.cpp
// more_and.cpp -- use logical AND operator
#include <iostream>
using namespace std;
const char * qualify[4] =       // an array of pointers
{                                // to strings
    "10,000-meter race.\n",
    "mud tug-of-war.\n",
    "masters canoe jousting.\n",
    "pie-throwing festival.\n"
};
int main()
{
    int age;
    cout << "Enter your age in years: ";
    cin >> age;
    int index;

    if (age > 17 && age < 35)
        index = 0;
    else if (age >= 35 && age < 50)
        index = 1;
    else if (age >= 50 && age < 65)
        index = 2;
    else
        index = 3;
    cout << "You qualify for the " << qualify[index];
    return 0;
}

Compatibility Note

graphics/hands.gif

You might recall that some C++ implementations require that you use the keyword static in an array declaration in order to make it possible to initialize that array. That restriction, as Chapter 9, "Memory Models and Namespaces," discusses, applies to arrays declared inside a function body. When an array is declared outside a function body, as is qualify in Listing 6.6, it's termed an external array and can be initialized even in pre-ANSI C implementations.

Here is a sample run:

Enter your age in years: 87
You qualify for the pie-throwing festival.

The entered age didn't match any of the test ranges, so the program set index to 3 and then printed the corresponding string.

Program Notes

The expression age > 17 && age < 35 tests for ages between the two values, that is, ages in the range 18?4. The expression age >= 35 && age < 50 uses the <= operator to include 35 in its range, which is 35?9. If the program had used age > 35 && age < 50, the value 35 would have been missed by all the tests. When you use range tests, you should check that the ranges don't have holes between them and that they don't overlap. Also, be sure to set up each range correctly; see the note on Range Tests.

The if else statement serves to select an array index, which, in turn, identifies a particular string.

Range Tests

graphics/common.gif

Note that each part of a range test should use the AND operator to join two complete relational expressions:

if (age > 17 && age < 35)   // OK

Don't borrow from mathematics and use the following notation:

if (17 < age < 35)          // Don't do this!

If you make this error, the compiler won't catch it, for it still is valid C++ syntax. The < operator associates from left to right, so the previous expression means the following:

if ( (17 < age) < 35)

But 17 < age is either true, or 1, or else false, or 0. In either case, the expression 17 < age is less than 35, so the entire test is always true!

The Logical NOT Operator: !

The ! operator negates, or reverses the truth value of, the expression that follows it. That is, if expression is true, then !expression is false, and vice versa. More precisely, if expression is true or nonzero, then !expression is false. Incidentally, many people call the exclamation point bang, making !x bang-exe and !!x bang-bang-exe.

Usually you more clearly can express a relationship without using this operator:

if (!(x > 5))                 // if (x <= 5) is clearer

But the ! operator can be useful with functions that return true-false values or values that can be interpreted that way. For example, strcmp(s1,s2) returns a nonzero (true) value if the two strings s1 and s2 are different from each other and a zero value if they are the same. This implies that !strcmp(s1,s2) is true if the two strings are equal.

Listing 6.7 uses this technique (applying the ! operator to a function return value) to screen numeric input for suitability to be assigned to type int. The user-defined function is_int(), which we discuss further in a moment, returns true if its argument is within the range of values assignable to type int. The program then uses the test while(!is_int(num)) to reject values that don't fit in the range.

Listing 6.7 not.cpp
// not.cpp -- using the not operator
#include <iostream>
#include <climits>
using namespace std;
bool is_int(double);
int main()
{
    double num;

    cout << "Yo, dude! Enter an integer value: ";
    cin >> num;
    while (!is_int(num))    // continue while num is not int-able
    {
        cout << "Out of range -- please try again: ";
        cin >> num;
    }
    int val = num;
    cout << "You've entered the integer " << val << "\nBye\n";
    return 0;
}

bool is_int(double x)
{
    if (x <= INT_MAX && x >= INT_MIN)   // use climits values
        return true;
    else
        return false;
}

Compatibility Note

graphics/hands.gif

If your system doesn't provide climits, use limits.h.

Here is a sample run on a system with a 32-bit int:

Yo, dude! Enter an integer value: 6234128679
Out of range -- please try again: -8000222333
Out of range -- please try again: 99999
You've entered the integer 99999
Bye
Program Notes

If you enter a too-large value to a program reading a type int, many implementations simply truncate the value to fit without informing you that data was lost. This program avoids that by first reading the potential int as a double. The double type has more than enough precision to hold a typical int value, and its range is much greater.

The Boolean function is_int() uses the two symbolic constants (INT_MAX and INT_MIN) defined in the climits file (discussed in Chapter 3, "Dealing with Data") to determine whether its argument is within the proper limits. If so, the program returns a value of true; otherwise, it returns false.

The main() program uses a while loop to reject invalid input until the user gets it right. You could make the program friendlier by displaying the int limits when the input is out of range. Once the input has been validated, the program assigns it to an int variable.

Logical Operator Facts

As we mentioned, the C++ logical OR and logical AND operators have a lower precedence than relational operators. That means an expression such as

x > 5 && x < 10

is read this way:

(x > 5) && (x < 10)

The ! operator, on the other hand, has a higher precedence than any of the relational or arithmetic operators. Therefore, to negate an expression, you should enclose the expression in parentheses:

!(x > 5)     // is it false that x is greater than 5
!x > 5       // is !x greater than 5

The second expression, incidentally, is always false, for !x only can have the values true or false, which get converted to 1 or 0.

The logical AND operator has a higher precedence than the logical OR operator. Thus the expression

age > 30 && age < 45 || weight > 300

means the following:

(age > 30 && age < 45) || weight > 300

That is, one condition is that age be in the range 31 to 44, and the second condition is that weight be greater than 300. The entire expression is true if one or the other or both of these conditions are true.

You can, of course, use parentheses to tell the program the interpretation you want. For example, suppose you want to use && to combine the condition that age be greater than 50 or weight be greater than 300 with the condition that donation be greater than 1000. You have to enclose the OR part within parentheses:

(age > 50 || weight > 300) && donation > 1000

Otherwise, the compiler combines the weight condition with the donation condition instead of with the age condition.

Although the C++ operator precedence rules often make it possible to write compound comparisons without using parentheses, the simplest course of action is to use parentheses to group the tests, whether or not the parentheses are needed. It makes the code easier to read, it doesn't force someone else to look up some of the less commonly used precedence rules, and it reduces the chance of making errors because you don't quite remember the exact rule that applies.

C++ guarantees that when a program evaluates a logical expression, it evaluates it from left to right and stops evaluation as soon as it knows what the answer is. Suppose, for example, you have this condition:

x != 0  && 1.0 / x > 100.0

If the first condition is false, then the whole expression must be false. That's because for this expression to be true, each individual condition must be true. Knowing the first condition is false, the program doesn't bother evaluating the second condition. That's fortunate in this example, for evaluating the second condition would result in dividing by 0, which is not in a computer's realm of possible actions.

Alternative Representations

Not all keyboards provide all the symbols used for the logical operators, so the C++ standard provides alternative representations, as shown in Table 6.3. The identifiers and, or, and not are C++ reserved words, meaning you can't use them as names for variables, etc. They are not considered keywords because they are alternative representations of existing language features. Incidentally, these are not reserved words in C, but a C program can use them as operators providing it includes the iso646.h header file. C++ does not require using a header file.

Table 6.3. Logical Operators: Alternative Representations
Operator Alternative Representation
&& and
|| or
! not

The cctype Library of Character Functions

C++ has inherited from C a handy package of character-related functions, prototyped in the cctype header file (ctype.h, in the older style), that simplify such tasks as determining whether a character is an uppercase letter or a digit or punctuation, and the like. For example, the isalpha(ch) function returns a nonzero value if ch is a letter and a zero value otherwise. Similarly, the ispunct(ch) returns a true value only if ch is a punctuation character, such as a comma or period. (These functions have return type int rather than bool, but the usual bool conversions allow you to treat them as type bool.)

Using these functions is more convenient than using the AND and OR operators. For example, here's how you might use AND and OR to test if a character ch is an alphabetic character:

if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))

Compare that to using isalpha():

if (isalpha(ch))

Not only is isalpha() easier to use, it is more general. The AND, OR form assumes that character codes for A through Z are in sequence, with no other characters having codes in that range. This assumption is true for the ASCII code, but it need not be true in general.

Listing 6.8 demonstrates some functions from this family. In particular, it uses isalpha(), which tests for alphabetic characters; isdigits(), which tests for digit characters, such as 3; isspace(), which tests for white-space characters, such as newlines, spaces, and tabs; and ispunct(), which tests for punctuation characters. The program also reviews the if else if structure and using a while loop with cin.get(char).

Listing 6.8 cctypes.cpp
// cctypes.cpp--use ctype.h library
#include <iostream>
#include <cctype>              // prototypes for character functions
using namespace std;
int main()
{
    cout << "Enter text for analysis, and type @"
            " to terminate input.\n";
    char ch;
    int whitespace = 0;
    int digits = 0;
    int chars = 0;
    int punct = 0;
    int others = 0;

    cin.get(ch);                // get first character
    while(ch != '@')            // test for sentinal
    {
        if(isalpha(ch))         // is it an alphabetic character?
            chars++;
        else if(isspace(ch))    // is it a whitespace character?
            whitespace++;
        else if(isdigit(ch))    // is it a digit?
            digits++;
        else if(ispunct(ch))    // is it punctuation?
            punct++;
        else
            others++;
        cin.get(ch);            // get next character
    }
    cout << chars << " letters, "
         << whitespace << " whitespace, "
         << digits << " digits, "
         << punct << " punctuations, "
         << others << " others.\n";
    return 0;
}

Here is a sample run; note that the white-space count includes newlines:

Enter text for analysis, and type @ to terminate input.
Jody "Java-Java" Joystone, noted restaurant critic,
celebrated her 39th birthday with a carafe of 1982
Chateau Panda.@
89 letters, 16 whitespace, 6 digits, 6 punctuations, 0 others.

Table 6.4 summarizes the functions available in the cctype package. Some systems may lack some of these functions or have additional ones.

Table 6.4. The cctype Character Functions
Function name Return value
isalnum() True if argument is alphanumeric, i.e., a letter or a digit
isalpha() True if argument is alphabetic
iscntrl() True if argument is a control character
isdigit() True if argument is a decimal digit (0?)
isgraph() True if argument is any printing character other than a space
islower() True if argument is a lowercase letter
isprint() True if argument is any printing character, including a space
ispunct() True if argument is a punctuation character
isspace() True if argument is a standard white-space character, i.e., a space, formfeed, newline, carriage return, horizontal tab, or vertical tab
isupper() True if argument is an uppercase letter
isxdigit() True if argument is a hexadecimal digit character, i.e., 0?, a杅, or A朏
tolower() If the argument is an uppercase character, tolower() returns the lowercase version of that character; otherwise, it returns the argument unaltered
toupper() If the argument is a lowercase character, toupper() returns the uppercase version of that character; otherwise, it returns the argument unaltered

The ?: Operator

C++ has an operator that often can be used instead of the if else statement. This operator is called the conditional operator, written ?:, and, for you trivia buffs, it is the only C++ operator that requires three operands. The general form looks like this:

expression1 ? expression2 : expression3

If expression1 is true, then the value of the whole conditional expression is the value of expression2. Otherwise, the value of the whole expression is the value of expression3. Here are two examples showing how the operator works:

5 > 3 ? 10 : 12  // 5 > 3 is true, so expression value is 10
3 == 9? 25 : 18  // 3 == 9 is false, so expression value is 18

We can paraphrase the first example this way: If 5 is greater than 3, the expression evaluates to 10; otherwise, it evaluates to 12. In real programming situations, of course, the expressions would involve variables.

Listing 6.9 uses the conditional operator to determine the larger of two values.

Listing 6.9 condit.cpp
// condit.cpp -- using the conditional operator
#include <iostream>
using namespace std;
int main()
{
    int a, b;
    cout << "Enter two integers: ";
    cin >> a >> b;
    cout << "The larger of " << a << " and " << b;
    int c = a > b ? a : b;   // c = a if a > b, else c = b
    cout << " is " << c << "\n";
    return 0;
}

Here is a sample run:

Enter two numbers: 25 27
The larger of 25 and 27 is 27

The key part of the program is this statement:

int c = a > b ? a : b;

It produces the same result as the following statements:

int c;
if (a > b)
    c = a;
else
    c = b;

Compared to the if else sequence, the conditional operator is more concise but, at first, less obvious. One difference between the two approaches is that the conditional operator produces an expression and hence a single value that can be assigned or be incorporated into a larger expression, as the program did when it assigned the value of the conditional expression to the variable c. The conditional operator's concise form, unusual syntax, and overall weird appearance make it a great favorite among programmers who appreciate those qualities. One favorite trick for the reprehensible goal of concealing the purpose of code is to nest conditional expressions within one another, as the following mild example shows:

const char x[2] [20] = {"Jason ","at your service\n"};
const char * y = "Quillstone ";

for (int i = 0; i < 3; i++)
    cout << ((i < 2)? !i ? x [i] : y : x[1]);

This is merely an obscure (but, by no means, maximally obscure) way to print the three strings in the following order:

Jason Quillstone at your service

In terms of readability, the conditional operator is best suited for simple relationships and simple expression values:

x = (x > y) ? x : y;

If the code becomes more involved, it probably can be expressed more clearly as an if else statement.

The switch Statement

Suppose you create a screen menu that asks the user to select one of five choices, for example, Cheap, Moderate, Expensive, Extravagant, and Excessive. You can extend an if else if else sequence to handle five alternatives, but the C++ switch statement more easily handles selecting a choice from an extended list. Here's the general form for a switch statement:

switch (integer-expression)
{
      case label1 : statement(s)
      case label2 : statement(s)
     ...
      default     : statement(s)
}

A C++ switch statement acts as a routing device that tells the computer which line of code to execute next. On reaching a switch, the program jumps to the line labeled with the value corresponding to the value of integer-expression. For example, if integer-expression has the value 4, the program goes to the line having a case 4: label. The value integer-expression, as the name suggests, must be an expression that reduces to an integer value. Also, each label must be an integer constant expression. Most often, labels are simple int or char constants, such as 1 or 'q', or enumerators. If integer-expression doesn't match any of the labels, the program jumps to the line labeled default. The default label is optional. If you omit it and there is no match, the program jumps to the next statement following the switch. (See Figure 6.3.)

Figure 6.3. The switch statement.

graphics/06fig03.gif

The switch statement is different from similar statements in languages such as Pascal in a very important way. Each C++ case label functions only as a line label, not as a boundary between choices. That is, after a program jumps to a particular line in a switch, it then sequentially executes all the statements following that line in the switch unless you explicitly direct it otherwise. Execution does NOT automatically stop at the next case. To make execution stop at the end of a particular group of statements, you must use the break statement. This causes execution to jump to the statement following the switch.

Listing 6.10 shows how to use switch and break together to implement a simple menu for executives. The program uses a showmenu() function to display a set of choices. A switch statement then selects an action based on the user's response.

Compatibility Note

graphics/hands.gif

Some implementations treat the \a escape sequence (used in case 1 in Listing 6.10) as silent.

Listing 6.10 switch.cpp
// switch.cpp -- use the switch statement
#include <iostream>
using namespace std;
void showmenu();   // function prototypes
void report();
void comfort();
int main()
{
    showmenu();
    int choice;
    cin >> choice;
    while (choice != 5)
    {
        switch(choice)
        {
            case 1  :   cout << "\a\n";
                        break;
            case 2  :   report();
                        break;
            case 3  :   cout << "The boss was in all day.\n";
                        break;
            case 4  :   comfort();
                        break;
            default :   cout << "That's not a choice.\n";
        }
        showmenu();
        cin >> choice;
    }
    cout << "Bye!\n";
    return 0;
}

void showmenu()
{
    cout << "Please enter 1, 2, 3, 4, or 5:\n"
            "1) alarm           2) report\n"
            "3) alibi           4) comfort\n"
            "5) quit\n";
}
void report()
{
    cout << "It's been an excellent week for business.\n"
        "Sales are up 120%. Expenses are down 35%.\n";
}
void comfort()
{
    cout << "Your employees think you are the finest CEO\n"
        "in the industry. The board of directors think\n"
        "you are the finest CEO in the industry.\n";
}

Here is a sample run of the executive menu program:

Please enter 1, 2, 3, 4, or 5:
1) alarm           2) report
3) alibi           4) comfort
5) quit
4
Your employees think you are the finest CEO
in the industry. The board of directors think
you are the finest CEO in the industry.
Please enter 1, 2, 3, 4, or 5:
1) alarm           2) report
3) alibi           4) comfort
5) quit
2
It's been an excellent week for business.
Sales are up 120%. Expenses are down 35%.
Please enter 1, 2, 3, 4, or 5:
1) alarm           2) report
3) alibi           4) comfort
5) quit
6
That's not a choice.
Please enter 1, 2, 3, 4, or 5:
1) alarm           2) report
3) alibi           4) comfort
5) quit
5
Bye!

The while loop terminates when the user enters a 5. Entering 1 through 4 activates the corresponding choice from the switch list, and entering 6 triggers the default statements.

As noted before, this program needs the break statements to confine execution to a particular portion of a switch. To see that this is so, you can remove the break statements from Listing 6.10 and see how it works afterwards. You'll find, for example, that entering 2 causes the program to execute all the statements associated with case labels 2, 3, 4, and the default. C++ works this way because that sort of behavior can be useful. For one thing, it makes it simple to use multiple labels. For example, suppose you rewrote Listing 6.10 using characters instead of integers as menu choices and switch labels. Then, you could use both an uppercase and a lowercase label for the same statements:

char choice;
cin >> choice;
while (choice != 'Q' && choice != 'q')
{
    switch(choice)
    {
        case 'a':
        case 'A': cout << "\a\n";
                  break;
        case 'r':
        case 'R': report();
                  break;
        case 'l':
        case 'L': cout << "The boss was in all day.\n";
                  break;
        case 'c'
        case 'C': comfort();
                  break;
        default : cout << "That's not a choice.\n";
    }
    showmenu();
    cin >> choice;
}

Because there is no break immediately following case 'a', program execution passes on to the next line, which is the statement following case 'A'.

Using Enumerators as Labels

Listing 6.11 illustrates using enum to define a set of related constants and then using the constants in a switch. In general, cin doesn't recognize enumerated types (it can't know how you will define them), so the program reads the choice as an int. When the switch statement compares the int value to an enumerator case label, it promotes the enumerator to int. Also, the enumerators are promoted to type int in the while loop test condition.

Listing 6.11 enum.cpp
// enum.cpp -- use enum
#include <iostream>
using namespace std;
// create named constants for 0 - 6
enum {red, orange, yellow, green, blue, violet, indigo};

int main()
{
    cout << "Enter color code (0-6): ";
    int code;
    cin >> code;
    while (code >= red && code <= indigo)
    {
        switch (code)
        {
            case red     : cout << "Her lips were red.\n"; break;
            case orange  : cout << "Her hair was orange.\n"; break;
            case yellow  : cout << "Her shoes were yellow.\n"; break;
            case green   : cout << "Her nails were green.\n"; break;
            case blue    : cout << "Her sweatsuit was blue.\n"; break;
            case violet  : cout << "Her eyes were violet.\n"; break;
            case indigo  : cout << "Her mood was indigo.\n"; break;
        }
        cout << "Enter color code (0-6): ";
        cin >> code;
    }
    cout << "Bye\n";
    return 0;
}

Here's a sample output:

Enter color code (0-6): 3
Her nails were green.
Enter color code (0-6): 5
Her eyes were violet.
Enter color code (0-6): 2
Her shoes were yellow.
Enter color code (0-6): 8
Bye

switch and if else

Both the switch statement and the if else statement let a program select from a list of alternatives. The if else is the more versatile of the two. For example, it can handle ranges, as in the following:

if (age > 17 && age < 35)
    index = 0;
else if (age >= 35 && age < 50)
    index = 1;
else if (age >= 50 && age < 65)
    index = 2;
else
    index = 3;

The switch, however, isn't designed to handle ranges. Each switch case label must be a single value. Also, that value must be an integer (which includes char), so a switch won't handle floating-point tests. And the case label value must be a constant. If your alternatives involve ranges or floating-point tests or comparing two variables, use if else.

If, however, all the alternatives can be identified with integer constants, you can use a switch or an if else statement. Because that's precisely the situation that the switch statement is designed to process, the switch statement usually is the more efficient choice in terms of code size and execution speed, unless there are only a couple of alternatives from which to choose.

Tip

graphics/bulb.gif

If you can use either an if else if sequence or a switch statement, the usual rule is to use a switch if you have three or more alternatives.

The break and continue Statements

The break and continue statements enable a program to skip over parts of the code. You can use the break statement in a switch statement and in any of the loops. It causes program execution to pass to the next statement following the switch or the loop. The continue statement is used in loops and causes a program to skip the rest of the body of the loop and then start a new loop cycle. (See Figure 6.4.)

Figure 6.4. The break and continue statements.

graphics/06fig04.gif

Listing 6.12 shows how the two statements work. The program lets you enter a line of text. The loop echoes each character and uses break to terminate the loop if the character is a period. This shows how you can use break to terminate a loop from within when some condition becomes true. Next the program counts spaces, but not other characters. The loop uses continue to skip over the counting part of the loop when the character isn't a space.

Listing 6.12 jump.cpp
// jump.cpp -- using continue and break
#include <iostream>
using namespace std;
const int ArSize = 80;
int main()
{
    char line[ArSize];
    int spaces = 0;

    cout << "Enter a line of text:\n";
    cin.get(line, ArSize);
    for (int i = 0; line[i] != '\0'; i++)
    {
        cout << line[i];    // display character
        if (line[i] == '.') // quit if it's a period
            break;
        if (line[i] != ' ') // skip rest of loop
            continue;
        spaces++;
    }
    cout << "\n" << spaces << " spaces\n";
    cout << "Done.\n";
    return 0;
}

Here's a sample run:

Let's do lunch today. You can pay!
Let's do lunch today.
3 spaces
Done.

Program Notes

Note that whereas the continue statement causes the program to skip the rest of the loop body, it doesn't skip the loop update expression. In a for loop, the continue statement makes the program skip directly to the update expression and then to the test expression. For a while loop, however, continue makes the program go directly to the test expression. So any update expression in a while loop body following the continue would be skipped. In some cases, that could be a problem.

This program didn't have to use continue. Instead, it could have used this code:

if (line[i] == ' ')
    spaces++;

However, the continue statement can make the program more readable when several statements follow the continue. That way, you don't need to make all those statements part of an if statement.

C++, like C, also has a goto statement. A statement like

goto paris

means to jump to the location bearing paris: as a label. That is, you can have code like this:

char ch;
cin >> ch;
if (ch == 'P')
      goto paris;
cout << ...
...
paris: cout << "You've just arrived at Paris.\n";

In most circumstances, using a goto is a bad hack, and you should use structured controls, such as if else, switch, continue, and the like, to control program flow.

Number-Reading Loops

You're preparing a program to read a series of numbers into an array. You want to give the user the option to terminate input before filling the array. One way is utilize how cin behaves. Consider the following code:

int n;
cin >> n;

What happens if the user responds by entering a word instead of a number? Four things occur in such a mismatch:

The fact that the method returns false means that you can use non-numeric input to terminate a number-reading loop. The fact that non-numeric input sets an error flag means that you have to reset the flag before the program can read more input. The clear() method, which also resets the end-of-file condition (see Chapter 5), resets the bad input flag. (Either bad input or end-of-file can cause cin to return false. Chapter 17, "Input, Output, and Files," discusses how to distinguish between the two cases.) Let's look at a couple of examples illustrating these techniques.

You want to write a program to calculate the average weight of your day's catch of fish. There's a five-fish limit, so a five-element array can hold all the data, but it's possible that you could catch fewer fish. Listing 6.13 uses a loop that terminates if the array is full or if you enter non-numeric input.

Listing 6.13 cinfish.cpp
// cinfish.cpp -- non-numeric input terminates loop
#include <iostream>
using namespace std;
const int Max = 5;
int main()
{
// get data
    double fish[Max];
    cout << "Please enter the weights of your fish.\n";
    cout << "You may enter up to " << Max
            << " fish <q to terminate>.\n";
    cout << "fish #1: ";
    int i = 0;
    while (i < Max && cin >> fish[i]) {
        if (++i < Max)
            cout << "fish #" << i+1 << ": ";
    }
// calculate average
    double total = 0.0;
    for (int j = 0; j < i; j++)
        total += fish[j];
// report results
    if (i == 0)
        cout << "No fish\n";
    else
        cout << total / i << " = average weight of "
            << i << " fish\n";
    cout << "Done.\n";
    return 0;
}

Compatibility Note

graphics/hands.gif

Some older Borland compilers give a warning about

cout << "fish #" << i+1 << ": ";

to the effect that ambiguous operators need parentheses. Don't worry. They're just warning about a possible grouping error if << is used in its original meaning as a left-shift operator.

The expression cin >> fish[i] really is a cin method function call, and the function returns cin. If cin is part of a test condition, it's converted to type bool. The conversion value is true if input succeeds and false otherwise. A false value for the expression terminates the loop. By the way, here's a sample run:

Please enter the weights of your fish.
You may enter up to 5 fish <q to terminate>.
fish #1: 30
fish #2: 35
fish #3: 25
fish #4: 40
fish #5: q
32.5 = average weight of 4 fish
Done.

Note the following line of code:

while (i < Max && cin >> fish[i]) {

Recall that C++ doesn't evaluate the right side of a logical AND expression if the left side is false. In this case, evaluating the right side means using cin to place input into the array. If i does equal Max, the loop terminates without trying to read a value into a location past the end of the array.

The last example didn't attempt to read any input after non-numeric input. Let's look at a case that does. Suppose you are required to submit exactly five golf scores to a C++ program to establish your average. If a user enters non-numeric input, the program should object, insisting on numeric input. As you've seen, you can use the value of a cin input expression to test for non-numeric input. Suppose you find the user did enter the wrong stuff. You need to take three steps:

Note that you have to reset cin before getting rid of the bad input. Listing 6.14 shows how these tasks can be accomplished.

Listing 6.14 cingolf.cpp
// cingolf.cpp -- non-numeric input skipped
#include <iostream>
using namespace std;
const int Max = 5;
int main()
{
// get data
    int golf[Max];
    cout << "Please enter your golf scores.\n";
    cout << "You must enter " << Max << " rounds.\n";
    int i;
    for (i = 0; i < Max; i++)
    {
        cout << "round #" << i+1 << ": ";
        while (!(cin >> golf[i])) {
            cin.clear();     // reset input
            while (cin.get() != '\n')
                continue;    // get rid of bad input
            cout << "Please enter a number: ";
        }
    }
// calculate average
    double total = 0.0;
    for (i = 0; i < Max; i++)
        total += golf[i];
// report results
    cout << total / Max << " = average score "
            << Max << " rounds\n";
    return 0;
}

Compatibility Note

graphics/hands.gif

Some older Borland compilers give a warning about

cout << "round #" << i+1 << ": ";

to the effect that ambiguous operators need parentheses. Don't worry. They're just warning about a possible grouping error if << is used in its original meaning as a left-shift operator.

Here is a sample run:

Please enter your golf scores.
You must enter 5 rounds.
round #1: 88
round #2: 87
round #3: must i?
Please enter a number: 103
round #4: 94
round #5: 86
91.6 = average score 5 rounds

Program Notes

The heart of the error-handling code is the following:

while (!(cin >> golf[i])) {
    cin.clear();     // reset input
    while (cin.get() != '\n')
        continue; // get rid of bad input
    cout << "Please enter a number: ";
}

If the user enters 88, the cin expression is true, a value is placed in the array, the expression !(cin >> golf[i]) is false, and this inner loop terminates. But if the user enters must i?, the cin expression is false, nothing is placed into the array, the expression !(cin >> golf[i]) is true, and the program enters the inner while loop. The first statement in the loop uses the clear() method to reset input. If you omit this statement, the program refuses to read any more input. Next, the program uses cin.get() in a while loop to read the remaining input through the end of the line. This gets rid of the bad input along with anything else on the line. Another approach is to read to the next white space, which would get rid of bad input one word at a time instead of one line at a time. Finally, the program tells the user to enter a number.

Summary

Programs and programming become more interesting when you introduce statements that guide the program through alternative actions. (Whether this also makes the programmer more interesting is a point we've not fully researched.) C++ provides the if statement, the if else statement, and the switch statements as means for managing choices. The C++ if statement lets a program execute a statement or statement block conditionally. That is, the program executes the statement or block if a particular condition is met. The C++ if else statement lets a program select from two choices which statement or statement block to execute. You can append additional if elses to the statement to present a series of choices. The C++ switch statement directs the program to a particular case in a list of choices.

C++ also provides operators to help in decision making. Chapter 5 discusses the relational expressions, which compare two values. The if and if else statements typically use relational expressions as test conditions. By using C++'s logical operators (&&, ||, and !), you can combine or modify relational expressions, constructing more elaborate tests. The conditional operator (?:) provides a compact way to choose from two values.

The cctype library of character functions provides a convenient and powerful set of tools for analyzing character input.

With C++'s loops and decision-making statements, you have the tools for writing interesting, intelligent, and powerful programs. But we've only begun to investigate the real powers of C++. Next, we look at functions.

Review Questions

1:

Consider the following two code fragments for counting spaces and newlines:

// Version 1
while (cin.get(ch))    // quit on eof
{
      if (ch == ' ')
             spaces++;
      if (ch == '\n')
            newlines++;
}
// Version 2
while (cin.get(ch))    // quit on eof
{
      if (ch == ' ')
            spaces++;
      else if (ch == '\n')
            newlines++;
}

What advantages, if any, does the second form have over the first?

2:

In Listing 6.2, what is the effect of replacing ++ch with ch+1?

3:

Consider carefully the following program:

#include <iostream>
using namespace std;
int main()
{
    char ch;
    int ct1, ct2;
    ct1 = ct2 = 0;
    while ((ch = cin.get()) != '$')
    {
        cout << ch;
        ct1++;
        if (ch = '$')
            ct2++;
        cout << ch;
    }
    cout <<"ct1 = " << ct1 << ", ct2 = " << ct2 << "\n";
    return 0;
}

Suppose we provide the following input, where graphics/ccc.gif represents pressing Enter:

Hi!
Send $10 or $20 now!

What is the output? (Recall that input is buffered.)

4:

Construct logical expressions to represent the following conditions:

  1. weight is greater than or equal to 115 but less than 125.

  2. ch is q or Q.

  3. x is even but is not 26.

  4. x is even but is not a multiple of 26.

  5. donation is in the range 1000?000 or guest is 1.

  6. ch is a lowercase letter or an uppercase letter (assume the lowercase letters are coded sequentially and that the uppercase letters are coded sequentially but that there is a gap in the code between uppercase and lowercase).

5:

In English the statement "I will not not speak" means the same as "I will speak." In C++, is !!x the same as x?

6:

Construct a conditional expression that is equal to the absolute value of a variable. That is, if a variable x is positive, the value of the expression is just x, but if x is negative, the value of the expression is -x, which is positive.

7:

Rewrite the following fragment using switch:

if (ch == 'A')
    a_grade++;
else if (ch == 'B')
    b_grade++;
else if (ch == 'C')
    c_grade++;
else if (ch == 'D')
    d_grade++;
else
    f_grade++;
8:

In Listing 6.10, what advantage would there be in using character labels, such as a and c, instead of numbers for the menu choices and switch cases? (Hint: Think about what happens if the user types q in either case and what happens if the user types 5 in either case.)

9:

Consider the following code fragment:

int line = 0;
char ch;
while (cin.get(ch))
{
    if (ch == 'Q')
           break;
    if (ch != '\n')
           continue;
    line++;
}

Rewrite this code without using break or continue.

Programming Exercises

1:

Write a program that reads keyboard input to the @ symbol and that echoes the input except for digits, converting each uppercase character to lowercase, and vice versa. (Don't forget the cctype family.)

2:

Write a program that reads up to ten donation values into an array of double. The program should terminate input on non-numeric input. It should report the average of the numbers and also report how many numbers in the array are larger than the average.

3:

Write a precursor to a menu-driven program. The program should display a menu offering four choices, each labeled with a letter. If the user responds with a letter other than one of the four valid choices, the program should prompt the user to enter a valid response until the user complies. Then, the program should use a switch to select a simple action based on the user's selection. A program run could look something like this:

Please enter one of the following choices:
c) carnivore           p) pianist
t) tree                g) game
f
Please enter a c, p, t, or g: q
Please enter a c, p, t, or g: t
A maple is a tree.
4:

When you join the Benevolent Order of Programmers, you can be known at BOP meetings by your real name, your job title, or by your secret BOP name. Write a program that can list members by real name, by job title, by secret name, or by a member's preference. Base the program on the following structure:

// Benevolent Order of Programmers name structure
struct bop {
    char fullname[strsize]; // real name
    char title[strsize];    // job title
    char bopname[strsize];  // secret BOP name
    int preference;         // 0 = fullname, 1 = title, 2 = bopname
};

In the program, create a small array of such structures and initialize it to suitable values. Have the program run a loop that lets the user select from different alternatives:

a. display by name     b. display by title
c. display by bopname  d. display by preference
q. quit

Note that "display by preference" does not mean display the preference member; it means display the member corresponding to the preference number. For instance, if preference is 1, choice d would display the programmer's job title. A sample run may look something like the following:

Benevolent Order of Programmers Report
a. display by name     b. display by title
c. display by bopname  d. display by preference
q. quit
Enter your choice: a
Wimp Macho
Raki Rhodes
Celia Laiter
Hoppy Hipman
Pat Hand
Next choice: d
Wimp Macho
Junior Programmer
MIPS
Analyst Trainee
LOOPY
Next choice: q
Bye!
5:

The Kingdom of Neutronia, where the unit of currency is the tvarp, has the following income tax code:

first 5000 tvarps: 0% tax

next 10000 tvarps: 10% tax

next 20000 tvarps: 15% tax

tvarps after 35000: 20% tax

For example, someone earning 38000 tvarps would owe 5000 x 0.00 + 10000 x 0.10 + 20000 x 0.15 + 3000 x 0.20, or 4600 tvarps. Write a program that uses a loop to solicit incomes and to report tax owed. The loop terminates when the user enters a negative number or nonnumeric input.

6:

Your task is to put together a program that keeps track of monetary contributions to the Society for the Preservation of Rightful Influence. It should ask the user to enter the number of contributors, then solicit the user to enter the name and contribution of each contributor. The information should be stored in a dynamically allocated array of structures. Each structure should have two members: a character array to store the name and a double member to hold the amount of the contribution. After reading all the data, the program should then display the names and amounts donated for all donors who contributed $10,000 or more. This list should be headed by a label indicating that the following donors are Grand Patrons. After that, the program should list the remaining donors. That list should be headed Patrons. If there are no donors in one of the categories, the program should print the word "none." Aside from displaying two categories, the program need do no sorting.

CONTENTS