54
June 7, 1999 10:10 owltex Sheet number 17 Page number 99 magenta black 4 Control, Functions, and Classes If A equals success, then the formula is A = X + Y + Z. X is work. Y is play. Z is keep your mouth shut. Albert Einstein quoted in SIGACT News, Vol. 25, No. 1, March 1994 Your “if” is the only peacemaker; much virtue in “if.” William Shakespeare As You Like It, V, iv Leave all else to the gods. Horace Odes, Book I, Ode ix In the programs studied in Chapter 3, statements executed one after the other to produce output. This was true both when all statements were in main or when control was transferred from main to another function, as it was in SlicePrice in pizza.cpp, Program 3.5. However, code behind the scenes in gfly.cpp, Program 3.6, executed differently in response to the user’s input and to a simulated wind-shear effect. Many programs require nonsequential control. For example, transactions made at automatic teller machines (ATMs) process an identification number and present you with a screen of choices. The program controlling the ATM executes different code depending on your choice—for example, either to deposit money or to get cash. This type of control is called selection: a different code segment is selected and executed based on interaction with the user or on the value of a program variable. Another type of program control is repetition: the same sequence of C++ statements is repeated, usually with different values for some of the variables in the statements. For example, to print a yearly calendar your program could call a PrintMonth function twelve times: PrintMonth("January", 31); //... PrintMonth("November",30); PrintMonth("December",31); Here the name of the month and the number of days in the month are arguments passed to PrintMonth. Alternatively, you could construct the PrintMonth function to determine the name of the month as well as the number of days in the month given the year and the number of the month. This could be done for the year 2000 by repeatedly executing the following statement and assigning values of 1, 2,..., 12 to month: PrintMonth(month, 2000); 99

Control,Functions,and Classes 4 - Duke Computer Science · June 7, 1999 10:10 owltex Sheet number 22 Page number 104 magenta black 104 Chapter 4 Control, Functions, and Classes Program

  • Upload
    others

  • View
    2

  • Download
    0

Embed Size (px)

Citation preview

June 7, 1999 10:10 owltex Sheet number 17 Page number 99magentablack

4Control, Functions, andClasses

If A equals success, then the formula isA = X + Y + Z.X is work. Y is play. Z is keep your mouth shut.

Albert Einsteinquoted in SIGACT News, Vol. 25, No. 1, March 1994

Your “if” is the only peacemaker; much virtue in “if.”William Shakespeare

As You Like It, V, iv

Leave all else to the gods.Horace

Odes, Book I, Ode ix

In the programs studied in Chapter 3, statements executed one after the other to produceoutput. This was true both when all statements were inmain or when control wastransferred frommain to another function, as it was inSlicePrice in pizza.cpp,Program 3.5. However, code behind the scenes ingfly.cpp,Program 3.6, executeddifferently in response to the user’s input and to a simulated wind-shear effect. Manyprograms require nonsequential control. For example, transactions made at automaticteller machines (ATMs) process an identification number and present you with a screenof choices. The program controlling the ATM executes different code depending onyour choice—for example, either to deposit money or to get cash. This type of control iscalledselection:a different code segment is selected and executed based on interactionwith the user or on the value of a program variable.

Another type of program control isrepetition: the same sequence of C++ statementsis repeated, usually with different values for some of the variables in the statements. Forexample, to print a yearly calendar your program could call aPrintMonth functiontwelve times:

PrintMonth("January", 31);//...PrintMonth("November",30);PrintMonth("December",31);

Here the name of the month and the number of days in the month are arguments passedto PrintMonth . Alternatively, you could construct thePrintMonth function todetermine the name of the month as well as the number of days in the month given theyear and the number of the month. This could be done for the year 2000 by repeatedlyexecuting the following statement and assigning values of 1, 2, . . . , 12 tomonth :

PrintMonth(month, 2000);

99

June 7, 1999 10:10 owltex Sheet number 18 Page number 100magentablack

100 Chapter 4 Control, Functions, and Classes

In this chapter we’ll study methods for controlling how the statements in a programare executed and how this control is used in constructing functions and classes. To dothis we’ll expand our study of arithmetic operators, introduced in the last chapter, toinclude operators for other kinds of data. We’ll also study C++ statements that alter theflow of control within a program. Finally, we’ll see how functions and classes can beused as a foundation on which we’ll continue to build as we study how programs areused to solve problems. At the end of the chapter you’ll be able to write the functionPrintMonth but you’ll also see a class that encapsulates the function so you don’thave to write it.

4.1 The Assignment OperatorIn the next three sections we’ll use a program that makes change using U.S. coins tostudy relational and assignment statements and conditional execution. We’ll use thesame program as the basis for what could be a talking cash register.

A run ofchange.cpp,Program 4.1, shows how change is made using quarters, dimes,nickels, and pennies. The program shows how values can be stored in variables using theassignment operator,=. In previous programs the user entered values for variables, butvalues can also be stored using the assignment operator. The code below assigns valuesfor the circumference and area of a circle according to the radius’ value, then prints thevalues.1

double radius, area, circumference;cout << "enter radius: ";cin >> radius;area = 3.14159*radius*radius;circumference = 3.14159*2*radius;cout << "are a = " << area

<< " circumferenc e = " << circumference << endl;

The assignment operator in Program 4.1 has two purposes, it assigns the number ofeach type of coin needed to the appropriate variable (e.g.,quarters anddimes ) andit resets the value of the variableamount so that change will be correctly calculated.

Syntax: assignment operator =

variable= expression

The assignment operator= storesvalues in variables. The expres-sion on the right-hand side of the= is evaluated, and this value isstored in the memory location as-sociated with the variable named

on the left-hand side of the=. The use of the equal sign to assign values to vari-ables can cause confusion, especially if you say “equals” when you read an expressionlike quarters = amount/25 . Operationally, the value on the right is stored inquarters , and it would be better to writequarters ← amount / 25 . The as-signment statement can be read as“The memory location of the variable quarters is

1The formula for the area of a circle isπr2, the formula for circumference is 2πr wherer is the radius.

June 7, 1999 10:10 owltex Sheet number 19 Page number 101magentablack

4.1 The Assignment Operator 101

assigned the value of amount/25,”but that is cumbersome (at best). If you can bringyourself to say “gets” for=, you’ll find it easier to distinguish between= and== (theboolean equality operator). Verbalizing the process by saying “Quarters gets amountdivided by twenty-five” will help you understand what’s happening when assignmentstatements are executed.

Program 4.1 change.cpp

#include <iostream>

using namespace std;

// make change in U.S. coins

// Owen Astrachan, 03/17/99

int main()

{

int amount;

int quarters, dimes, nickels, pennies;

// input phase of program

cout << "make change in coins for what amount: ";

cin >> amount;

// calculate number of quarters, dimes, nickels, pennies

quarters = amount/25;

amount = amount − quarters ∗25;

dimes = amount/10;

amount = amount − dimes ∗10;

nickels = amount/5;

amount = amount − nickels ∗5;

pennies = amount;

// output phase of program

cout << "# quarters =\t" << quarters << endl;

cout << "# dimes =\t" << dimes << endl;

cout << "# nickels =\t" << nickels << endl;

cout << "# pennies =\t" << pennies << endl;

return 0;

} change.cpp

June 7, 1999 10:10 owltex Sheet number 20 Page number 102magentablack

102 Chapter 4 Control, Functions, and Classes

int amount;

87

Before execution

amount = amount - quarters*25;

int quarters;

After execution

int amount;

3

12

87 - 3*25

Figure 4.1 Updating a variable via assignment.

O U T P U T

prompt> changemake change in coins for what amount: 87# quarters = 3# dimes = 1# nickels = 0# pennies = 2prompt> changemake change in coins for what amount: 42# quarters = 1# dimes = 1# nickels = 1# pennies = 2

The statementamount = amount - quarters*25 updates the value of thevariableamount . The right-hand side of the statement is evaluated first. The valueof this expression,amount - quarters*25 , is stored in the variable on the left-hand side of the assignment statement—that is, the variableamount . This process isdiagrammed in Fig. 4.1 whenamount is 87.

A sequence of assignments can be chained together in one statement:

x = y = z = 13;

This statement assigns the value 13 to the variablesx , y , and z . The statement isinterpreted asx = (y = (z = 13)) . The value of the expression(z = 13) is13, the value assigned toz . This value is assigned toy , and the result of the assignmentto y is 13. This result of the expression(y = 13) is then assigned tox . Parenthesesaren’t needed in the statementx = y = z = 13 , because the assignment operator=is right-associative: in the absence of parentheses the rightmost= is evaluated first.

June 7, 1999 10:10 owltex Sheet number 21 Page number 103magentablack

4.2 Choices and Conditional Execution 103

Table 4.1 Escape sequences in C++

escape sequence name ASCII

\n newline NL (LF)\t horizontal tab HT\v vertical tab VT\b backspace BS\r carriage return CR\f form feed FF\a alert (bell) BEL\\ backslash \\? question mark ?\’ single quote (apostrophe) ’\" double quote "

In contrast, the subtraction operator isleft-associative,so the expression8 - 3 - 2is equal to 3, because it is evaluated as(8 - 3) - 2 rather than8 - (3 - 2) :here the leftmost subtraction is evaluated first. Most operators are left-associative; theassociativity of all C++ operators is shown in Table A.4 in Howto A.

Escape Sequences. The output ofchange.cppis aligned using a tab character’ \t’ .The tab character prints one tab position, ensuring that the amounts of each kind of coinline up. The backslash andt to print the tab character are an example of anescapesequence.Common escape sequences are given in Table 4.1. The table is repeated asTable A.5 in Howto A. Each escape sequence prints a single character. For example,the following statement prints the four-character string" \’" .

cout << "\"\\\’\"" << endl;

4.2 Choices and Conditional Execution

I shall set forth from somewhere, I shall make the reckless choiceRobert Frost

The Sound of the Trees

In this section we’ll alter Program 4.1 so that it only prints the coins used in giv-ing change. We’ll also move the output part of the program to a separate function.By parameterizing the output and using a function, we make it simpler to incorporatemodifications to the original program.

June 7, 1999 10:10 owltex Sheet number 22 Page number 104 magentablack

104 Chapter 4 Control, Functions, and Classes

Program Tip 4.1: Avoid duplicating the same code in several places inthe same program. Programs will be modified. If you need to make the samechange in more than one place in your code it is very likely that you will leave somechanges out, or make the changes inconsistently. In many programs more time is spent inprogram maintenancethan inprogram development. Often, moving duplicated codeto a function and calling the function several times helps avoid code duplication.

Program 4.2 change2.cpp

#include <iostream>#include <string>using namespace std;

// make change in U.S. coins// Owen Astrachan, 03/17/99

void Output(string coin, int amount){

if (amount > 0){ cout << "# " << coin << " =\t" << amount << endl;}

}

int main(){

int amount;int quarters, dimes, nickels, pennies;

// input phase of program

cout << "make change in coins for what amount: ";cin >> amount;

// calculate number of quarters, dimes, nickels, pennies

quarters = amount/25;amount = amount − quarters ∗25;

dimes = amount/10;amount = amount − dimes ∗10;

nickels = amount/5;amount = amount − nickels ∗5;

pennies = amount;

// output phase of program

Output("quarters",quarters);Output("dimes",dimes);

June 7, 1999 10:10 owltex Sheet number 23 Page number 105magentablack

4.2 Choices and Conditional Execution 105

Output("nickels",nickels);Output("pennies",pennies);

return 0;} change2.cpp

O U T P U T

prompt> change2make change in coins for what amount: 87# quarters = 3# dimes = 1# pennies = 2

In the functionOutput anif statement is used forconditional execution—that is,ifmakes the execution depend on the value ofamount . In the C++ statement

if (amount > 0){ cout << "# " << coin << " =\t" << amount << endl;}

thetest expression(amount > 0) controls thecout << statement so that outputappears only if the value of theint variableamount is greater than zero.

4.2.1 The if/else Statement

An if statement contains a test expression and abody: a group of statements withincurly braces{ and}. These statements are executedonly when the test expression, alsocalled acondition or aguard, is true. The testmust

Syntax: if statement

if ( test expression){

statement list;}

be enclosed by parentheses. Inthe next section we’ll explore op-erators that can be used in tests,including<, <=, >, and>=. Thebody of theif statement can con-tain any number of statements.The curly braces that are used todelimit the body of theif state-

ment aren’t needed when there’s only one statement in the body, but we’ll always usethem as part of adefensive programmingstrategy designed to ward off bugs beforethey appear.

June 7, 1999 10:10 owltex Sheet number 24 Page number 106magentablack

106 Chapter 4 Control, Functions, and Classes

Program 4.3 shows that anif statement can have anelse part, which also controls,or guards, a body of statements within curly braces{ and} that is executed when the testexpression is false. Any kind of statement can appear

Syntax: if/else statement

if ( test expression){

statement list;}else{

statement list;}

in the body of anif/else state-ment, including otherif/elsestatements. We’ll discuss format-ting conventions for writing suchcode after we explore the otherkinds of operators that can be usedin the test expressions that arepart of if statements. You mayfind yourself writing code withanempty if orelse body: onewith no statements. This can al-ways be avoided by changing the

test used with theif using rules of logic we’ll discuss in Section 4.7.In Program 4.3, if the value ofresponse is something other than"yes" , then the

cout << statements associated with theif section are not executed, and the statementsin theelse section of the program are executed instead. In particular, if the user enters"yeah" or "yup" , then the program takes the same action as when the user enters"no" . Furthermore, the answer"Yes" is also treated like the answer"no" rather than"yes" , because a capital letter is different from the equivalent lower-case letter. As wesaw in Program 4.1,change.cpp,the rules of C++ donot require anelse section foreveryif .

Program 4.3 broccoli.cpp

#include <iostream>#include <string>using namespace std;

// illustrates use of if-else statement

int main(){

string response;cout << "Do you like broccoli [yes/no]> ";cin >> response;if ("yes" == response){ cout << "Green vegetables are good for you" << endl;

cout << "Broccoli is good in stir-fry as well" << endl;}else{ cout << "De gustibus non disputandum" << endl;

cout << "(There is no accounting for taste)" << endl;}return 0;

} broccoli.cpp

June 7, 1999 10:10 owltex Sheet number 25 Page number 107magentablack

4.3 Operators 107

O U T P U T

prompt> broccoliDo you like broccoli [yes/no]> yesGreen vegetables are good for youBroccoli is good in stir-fry as well

prompt> broccoliDo you like broccoli [yes/no]> noDe gustibus non disputandum(There is no accounting for taste)

Theelse section in Program 4.3 could be removed, leaving the following:

int main(){

string response;cout << "Do you like broccoli [yes/no]> ";cin >> response;if ("yes" == response){ cout << "Green vegetables are good for you" << endl;

cout << "Broccoli is good in stir-fry as well" << endl;}return 0;

}

In this modified program, if the user enters any string other than"yes" , nothing isprinted.

ProgramTip 4.2: Use an if statement to guard a sequence of statementsand an if/else statement to choose between two sequences. The ifstatement solves the problem of guarding the sequence of statements in the body ofthe if so that these statements are executed only when a certain condition holds. Theif/else statement solves the problem of choosing between two different sequences.Later in the chapter we’ll see how to choose between more than two sequences usingcascadedif/else statements.

4.3 OperatorsWe’ve seen arithmetic operators such as+, * , %, the assignment operator=, and the<operator used inif /else statements. In this section we’ll study the other operatorsavailable in C++. You’ll use all these operators in constructing C++ programs.

June 7, 1999 10:10 owltex Sheet number 26 Page number 108magentablack

108 Chapter 4 Control, Functions, and Classes

Table 4.2 The relational operators

symbol meaning example

== equal to if ("yes" == response)> greater than if (salary > 30000)< less than if (0 < salary)! = not equal to if ("yes" != response)>= greater than or equal to≥ if (salary >= 10000)<= less than or equal to≤ if (20000 <= salary)

4.3.1 Relational Operators

Comparisons are odious.John Fortescue

De Laudibus Legum Angliae, 1471

The expressions that form the test of anif statement are built from different operators.In this section we’ll study therelational operators, which are used to determine therelationships between different values. Relational operators are listed in Table 4.2.

The parenthesized expression that serves as the test of anif statement can use anyof the relational operators shown in Table 4.2. The parenthesized expressions evaluate totrue or false and are calledbooleanexpressions, after the mathematician George Boole.Boolean expressions have one of two values:true or false. In C++ programs, anynonzero value is considered “true,” and zero-valued expressions are considered “false.”The C++ typebool is used for variables and expressions with one of two values:trueandfalse. Althoughbool was first approved as part of C++ in 1994, some older compilersdo not support it.2 We’ll use true andfalse as values rather than zero and one, butremember that zero is the value used for false in C++ .

The relational operators< and> behave as you might expect when used withintanddouble values. In the following statement the variablesalary can be anintor adouble . In either case the phrase about minimum wage is printed if the value ofsalary is less than 10.0.

2If you’re using a compiler that doesn’t supportbool as a built-in type, you can use the headerfile bool.h supplied with the code from this book via#include"bool.h" to get access to aprogrammer-defined version of typebool .

June 7, 1999 10:10 owltex Sheet number 27 Page number 109magentablack

4.3 Operators 109

if (salary < 10.0){ cout << "you make below minimum wage" << endl;}

Whenstring values are compared, the behavior of the inequality operators< and>is based on a dictionary order, sometimes calledlexicographical order:

string word;cout << "enter a word: ";cin >> word;if (word < "middle"){ cout << word << " comes before middle" << endl;}

In the foregoing code fragment, entering the word"apple" generates the followingoutput.

O U T P U T

apple comes before middle

Entering the word"zebra" would cause the test(word < "middle") to evalu-ate to false, so nothing is printed. The comparison of strings is based on the order in whichthe strings would appear in a dictionary, so that"A" comes before"Z" . Sometimesthe behavior of string comparisons is unexpected. Entering"Zebra" , for example,generates this output:

O U T P U T

Zebra comes before middle

This happens because capital letters come before lower-case letters in the orderingof characters used on most computers.3

To see how relational operators are evaluated, consider the output of these statements:

cout << (13 < 5) << endl;cout << ( 5 + 1 < 6 * 2) << endl;

3We’ll explore the ASCII character set, which is used to determine this ordering, in Chapter 9.

June 7, 1999 10:10 owltex Sheet number 28 Page number 110magentablack

110 Chapter 4 Control, Functions, and Classes

O U T P U T

01

The value of13 < 5 is false, which is zero; and the value of6 < 12 is true, whichis one. (In Howto B, a standard method for printing bool values astrue andfalse ,rather than 1 and 0, is shown.) In the last output statement, the arithmetic operations areexecuted first, because they have higher precedence than relational operators. You’veseen precedence used with arithmetic operators; for example, multiplication has higherprecedence than addition, so that 3+ 4× 2 = 11. You can use parentheses to bypassthe normal precedence rules. The expression(3+ 4)× 2 evaluates to 14 rather than 11.A table showing the relative precedence of all C++ operators can be found in Table A.4in Howto A.

Program Tip 4.3: When you write expressions in C++ programs, useparentheses liberally. Trying to uncover precedence errors in a complex expres-sion can be very frustrating. Looking for precedence errors is often the last place you’lllook when trying to debug a program. As part of defensive programming, use parenthesesrather than relying exclusively on operator precedence.

Because execution of anif statement depends only on whether the test is true orfalse (nonzero or zero), the following code is legal in C++ :

if (6 + 3 - 9){ cout << "great minds think alike" << endl;}else{ cout << "fools seldom differ" << endl;}

These statements cause the string “fools seldom differ” to be output, because the expres-sion(6+ 3− 9) evaluates to 0, which is false in C++ . Although this code is legal, it isnot necessarily good code. It is often better to make the comparison explicit, as in

if (x != 0){ DoSomething();}

rather than relying on the equivalence of “true” and any nonzero value:

if (x){ DoSomething();}

June 7, 1999 10:10 owltex Sheet number 29 Page number 111magentablack

4.3 Operators 111

which is equivalent in effect, but not in clarity. There are situations, however, in whichthe second style of programming is clearer. When such a situation arises, I’ll point itout.

4.3.2 Logical Operators

As we will see (for example, inusemath.cpp,Program 4.6, it can be necessary to checkthat a value you enter is in a certain range (e.g., not negative). Inchange.cpp,Program 4.1,the program should check to ensure that the user’s input is valid (e.g., between 0 and99). The following code implements this kind of check.

if (choice < 0){ cout << "illegal choice" << endl;}else if (choice > 99){ cout << "illegal choice" << endl;}else{ // choice ok, continue}

This code has the drawback of duplicating the code that’s executed when the user entersan illegal choice. Suppose a future version of the program will require the user to reenterthe choice. Modifying this code fragment would require adding new code in two places,making the likelihood of introducing an error larger. In addition, when code is duplicated,it is often difficult to make the same modifications everywhere the code appears. Logicaloperators allow boolean expressions to be combined, as follows:

if (choic e < 0 || choice > 99){ cout << "illegal choice" << endl;}else{ // choice ok, continue}

The test now reads, “If choice is less than zero or choice is greater than ninety-nine.”The test is true (nonzero) when eitherchoice < 0 or choice > 99 . The operator|| is the logical or operator. It evaluates to true when either or both of its booleanarguments is true. Thelogical and operator&& operates on two boolean expressionsand returns true only when both are true.

The preceding test for valid input can be rewritten using logical and as follows:

if (0 <= choice && choice <= 99){ // choice ok, continue}else{ cout << "illegal choice" << endl;}

June 7, 1999 10:10 owltex Sheet number 30 Page number 112magentablack

112 Chapter 4 Control, Functions, and Classes

Table 4.3 Truth table for logical operators

A B A || B A && B !Afalse false false false truefalse true true false truetrue false true false falsetrue true true true false

Be careful when translating English or mathematics into C++ code. The phrase“choice is between 0 and 99” is often written in mathematics as 0≤ choice≤ 99. InC++, relational operators are left-associative, so the followingif test, coded as it wouldbe in mathematics, will evaluate to true foreveryvalue ofchoice .

if (0 <= choice <= 99){ // choice ok, continue}

Since the leftmost<= is evaluated first (the relational operators, like all binary operators,are left associative), the test is equivalent to( (0 <= choice) <= 99 ) and thevalue of the expression(0 <= choice) is either false (0) or true (1), both of whichare less than or equal to 99, thus satisfying the second test.

There is also a unary operator! that works with boolean expressions. This is thelogical not operator. The value of!expression is false if the value ofexpressionis true, and true when the value ofexpression is false. The two expressions beloware equivalent.

x != y !(x == y)

Because! has a very high precedence, the parentheses in the expression on the right arenecessary (see Table A.4).

4.3.3 Short-Circuit Evaluation

The following statement is designed to print a message when a grade-point average ishigher than 90%:

if (scoreTotal/numScores > 0.90){ cout << "excellent! very good work" << endl;}

This code segment might cause a program to exit abnormally4 if the value ofnumScoresis zero, because the result of division by zero is not defined. The abnormal exit can beavoided by using anothernestedif statement (the approach required in languages suchas Pascal):

4The common phrase for such an occurrence isbomb,as in “The program bombed.” If you follow gooddefensive programming practices, your programs should not bomb.

June 7, 1999 10:10 owltex Sheet number 31 Page number 113magentablack

4.3 Operators 113

if (numScores != 0){

if (scoreTotal/numScores > 0.90){ cout << "excellent! very good work" << endl;}

}

However, in languages like C, C++, and Java another approach is possible:

if (numScores != 0 && scoreTotal/numScores > 0.90){ cout << "excellent! very good work" << endl;}

The subexpressions in an expression formed by the logical operators&& and || areevaluated from left to right. Furthermore, the evaluation automatically stops as soon asthe value of the entire test expression can be determined. In the present example, if theexpressionnumScores != 0 is false (so thatnumScores is equal to 0), the entireexpression must be false, because when&& is used to combine two boolean subexpres-sions, both subexpressions must be true (nonzero) for the entire expression to be true (seeTable 4.3). WhennumScores == 0 , the expressionscoreTotal/numScores> 0.90 will not be evaluated, avoiding the potential division by zero.

Similarly, when|| is used, the second subexpression will not be evaluated if the firstis true, because in this case the entire expression must be true—only one subexpressionneeds to be true for an entire expression to be true with|| . For example, in the code

if (choic e < 1 || choice > 3){ cout << "illegal choice" << endl;}

the expressionchoice > 3 is not evaluated whenchoice is 0. In this case,choice< 1 is true, so the entire expression must be true.

The termshort-circuit evaluation describes this method of evaluating boolean ex-pressions. The short circuit occurs when some subexpression is not evaluated becausethe value of the entire expression is already determined. We’ll make extensive use ofshort-circuit evaluation (also called “lazy evaluation”) in writing C++ programs.

4.3.4 Arithmetic Assignment Operators

C++ has several operators that serve as “contractions,” in the grammatical sense that“I’ve” is a contraction of “I have.” These operators aren’t necessary, but they cansimplify and shorten code that changes the value of a variable. For example, severalstatements inchange.cpp,Program 4.1, alter the value ofamount ; these statements aresimilar to the following:

amount = amount - quarters*25;

This statement can be rewritten using the operator-= .

amount -= quarters*25;

June 7, 1999 10:10 owltex Sheet number 32 Page number 114magentablack

114 Chapter 4 Control, Functions, and Classes

Table 4.4 Arithmetic assignment operators.

symbol example equivalent+= x += 1; x = x + 1;*= doub *= 2; doub = doub * 2;-= n -= 5; n = n - 5;/= third /= 3; third = third / 3;%= odd %= 2; odd = odd % 2;

Similarly, the statementnumber = number + 1 , which increments the value ofnumber by one, can be abbreviated using the+= operator: number += 1; . Ingeneral, the statementvariable= variable+ expression; has exactly the same effect asthe statementvariable+= expression;

Using such assignment operators can make programs easier to read. Often a longvariable name appearing on both sides of an assignment operator= will cause a lengthyexpression to wrap to the next line and be difficult to read. The arithmetic assignmentoperators summarized in Table 4.4 can alleviate this problem.

It’s not always possible to use an arithmetic assignment operator as a contractionwhen a variable appears on both the left and right sides of an assignment statement. Thevariable must occur as thefirst subexpression on the right side. For example, ifx hasthe value zero or one, the statementx = 1 - x changes the value from one to zeroand vice versa. This statement cannot be abbreviated using the arithmetic assignmentoperators.

4.4 Block Statements and DefensiveProgramming

Following certain programming conventions can lead to programs that are more under-standable (for you and other people reading your code) and more easily developed.

In this book we follow the convention of usingblock delimiters, { and}, for eachpart of anif /else statement. This is shown inchange2.cpp,Program 4.2. It is possibleto write theif statement in Program 4.2 without block delimiters:

if (amount > 0)cout << "# " << coin << " =\t" << amount << endl;

The test of theif statement controls the output statement so that it is executed onlywhenamount is greater than zero.

As we’ve seen, it is useful to group several statements together so that all are ex-ecuted precisely when the test of anif /else statement is true. To do this, ablock(or compound) statement is used. A block statement is a sequence of one or morestatements enclosed by curly braces, as shown in Program 4.2. If no braces are used, aprogram may compile and run, but its behavior might be other than expected. Considerthe following program fragment:

June 7, 1999 10:10 owltex Sheet number 33 Page number 115magentablack

4.4 Block Statements and Defensive Programming 115

int salary;cout << "enter salary ";cin >> salary;if (salary > 30000)

cout << salary << " is a lot to earn " << endl;cout << salary*0.55 << " is a lot of taxes << endl;

cout << "enter \# of hours worked ";...

Two sample runs of this fragment follow:

O U T P U T

enter salary 3100031000 is a lot to earn17050.00 is a lot of taxesenter # of hours worked…enter salary 150008250.00 is a lot of taxesenter # of hours worked…

Note that the indentation of the program fragment might suggest to someone readingStumbling Block

the program (but not to the compiler!) that the “lot of taxes” message should be printedonly when the salary is greater than 30,000. However, the taxation message isalwaysprinted. The compiler interprets the code fragment as though it were written this way:

int salary;cout << "enter salary ";cin >> salary;if (salary > 30000){ cout << salary << " is a lot to earn " << endl;}cout << salary*0.55 << " is a lot of taxes " << endl;cout << "enter # of hours worked ";

When 15000 is entered, the testsalary > 30000 evaluates to false, and the statementabout “a lot to earn” is not printed. The statement about a “lot of taxes”, however, isprinted, because it is not controlled by the test.

Indentation and spacing are ignored by the compiler, but they are important for peoplereading and developing programs. For this reason, we will always employ braces{} anda block statement when usingif /else statements, even if the block statement consistsof only a single statement.

June 7, 1999 10:10 owltex Sheet number 34 Page number 116magentablack

116 Chapter 4 Control, Functions, and Classes

4.4.1 Defensive Programming Conventions

This convention of always using braces is an example of adefensive programmingstrategy: writing code to minimize the potential for causing errors. Suppose you decideto add another statement to be controlled by the test of anif statement that is initiallywritten without curly braces. When the new statement is added, it will be necessaryto include the curly braces that delimit a block statement, but that is easy to forget todo. Since the missing braces can cause a hard-to-detect error, we adopt the policy ofincluding them even when there is only a single statement controlled by the test.

ProgramTip 4.4: Adopt coding conventions that make it easier to modifyprograms. You’ll rarely get a program right the first time. Once a program workscorrectly, it’s very likely that you’ll need to make modifications so that the program worksin contexts unanticipated when first designed and written. More time is spent modifyingprograms than writing them first, so strive to make modification as simple as possible.

Program 4.4 noindent.cpp

#include <iostream>

#include <string>

using namespace std;

int main() { string response; cout

<< "Do you like C++ programming [yes/no]> "; cin >> response;

if ("yes" == response) { cout <<

"It's more than an adventure, it can be a job"

<< endl; } else { cout

<< "Perhaps in time you will" << endl; } return 0;}noindent.cpp

In this book the left curly brace{ always follows anif /else on the next line afterthe line on which theif or else occurs. The right curly brace} is indented the samelevel as theif /else to which it corresponds. Other indentation schemes are possible;one common convention follows, this is calledK&R style after the originators of C,Kernighan and Ritchie.

if ("yes" == response) {cout << "Green vegetables are good for you" << endl;cout << "Broccoli is good in stir-fry as well" << endl;

}

You can adopt either convention, but your boss (professor, instructor, etc.) may requirea certain style. If you’re consistent, the particular style isn’t that important, although it’soften the cause of many arguments between supporters of different indenting styles.

June 7, 1999 10:10 owltex Sheet number 35 Page number 117magentablack

4.4 Block Statements and Defensive Programming 117

In this book we usually include the first statement between curly braces on the sameline as the first (left) brace. If you use this style of indenting, you will not press returnafter you type the left curly brace{ . However, we sometimes do press return, whichusually makes programs easier to read because of the extra white space5.

To see that indentation makes a difference, note thatnoindent.cpp,Program 4.4,compiles and executes without error but that no consistent indentation style is used.Notice that the program is much harder for people to read, although the computer “reads”it with no trouble.

Problems with = and ==. Typing= when you mean to type== can lead to hard-to-locateStumbling Block

bugs in a program. A coding convention outlined here can help to alleviate these bugs,but you must keep the distinction between= and== in mind when writing code. Somecompilers are helpful in this regard and issue warnings about “potentially unintendedassignments.”

The following program fragment is intended to print a message depending on aperson’s age:

string age;cout << "are you young or old [young/old]: ";cin >> age;if (age = "young"){ cout << "not for long, time flies when you’re having fun";}else{ cout << "hopefully you’re young at heart";}

If the user entersold , the message beginning “not for long…” is printed. Can you seewhy this is the case? The test of theif /else statement should be read as “if age getsyoung.” The string literal"young" is assigned toage , and the result of the assignmentis nonzero (it is"young" , the value assigned toage ). Because anything nonzero isregarded as true, the statement within the scope of theif test is executed.

You can often prevent such errors by putting constants on the left of comparisons asfollows:

if ("young" == age)// do something

If the assignment operator is used by mistake, as inif ("young" = age) , thecompiler will generate an error.6 It is much better to have the compiler generate an errormessage than to have a program with a bug in it.

Putting constants on the left in tests is a good defensive programming style that canhelp to trap potential bugs and eliminate them before they creep into your programs.

5In a book, space is more of a premium than it is on disk—hence the style of indenting that does notuse the return. You should make sure you follow the indenting style used by your boss, supervisor, orprogramming role model.6On one compiler the error message “error assignment to constant” is generated. On another, the lessclear message “sorry, not implemented: initialization of array from dissimilar array type” is generated.

June 7, 1999 10:10 owltex Sheet number 36 Page number 118magentablack

118 Chapter 4 Control, Functions, and Classes

4.4.2 Cascaded if /else Statements

Sometimes a sequence ofif /else statements is used to differentiate among severalpossible values of a single expression. Such a sequence is calledcascaded.An exampleis shown inmonthdays.cpp,Program 4.5.

Program 4.5 monthdays.cpp

#include <iostream>#include <string>using namespace std;

// illustrates cascaded if/else statements

int main(){

string month;int days = 31; // default value of 31 days/month

cout << "enter a month (lowercase letters): ";cin >> month;

// 30 days hath september, april, june, and november

if ("september" == month){ days = 30;}else if ("april" == month){ days = 30;}else if ("june" == month){ days = 30;}else if ("november" == month){ days = 30;}else if ("february" == month){ days = 28;}cout << month << " has " << days << " days" << endl;

return 0;} monthdays.cpp

It’s possible to write the code inmonthdays.cppusingnestedif /else statements asfollows. This results in code that is much more difficult to read than code using cascadedif / else statements. Whenever a sequence ofif /else statements like this is used totest the value of one variable repeatedly, we’ll use cascadedif /else statements. Therule of using a block statement after anelse is not (strictly speaking) followed, butthe code is much easier to read. Because a block statement follows theif , we’re notviolating the spirit of our coding convention.

June 7, 1999 10:10 owltex Sheet number 37 Page number 119magentablack

4.4 Block Statements and Defensive Programming 119

if ("april" == month){ days = 30;}else{

if ("june" == month){ days = 30;}else{

if ("november" == month){ days = 30;}else{

if ("february" == month){ days = 28;}

}}

}

O U T P U T

prompt> days4enter a month (lowercase letters): januaryjanuary has 31 daysprompt> days4enter a month (lowercase letters): aprilapril has 30 daysprompt> days4enter a month (lowercase letters): AprilApril has 31 days

4.1 The statements alteringamount in change.cpp,Program 4.1, can be written usingPause to Reflect

the mod operator%. If amount = 38 , thenamount/25 == 1 , andamount% 25 == 13, which is the same value as38 - 25*1 . Rewrite the programusing the mod operator. Try to use an arithmetic assignment operator.

4.2 Describe the output of Program 4.3 if the user enters the string"Yes" , the string"yup" , or the string"none of your business" .

4.3 Why is days given a “default” value of 31 inmonthdays.cpp,Program 4.5?

June 7, 1999 10:10 owltex Sheet number 38 Page number 120magentablack

120 Chapter 4 Control, Functions, and Classes

4.4 How canmonthdays.cpp,Program 4.5, be modified to take leap years into account?

4.5 Modify broccoli.cpp,Program 4.3, to include anif statement in theelse clauseso that the “taste” lines are printed only if the user enters the string"no" . Thusyou might have lines such as

if ("yes" == response){}else if ("no" == response){}

4.6 Using the previous modification, add a finalelse clause (with noif statement)so that the output might be as follows:

O U T P U T

prompt> broccoli

Do you like broccoli [yes/no]> no

De gustibus non disputandum

(There is no accounting for good taste)

prompt> broccoli

Do you like broccoli [yes/no]> nope

Sorry, only responses of yes and no are recognized

4.7 Write a sequence ofif /else statements using> and, perhaps,< that prints amessage according to a grade between 0 and 100, entered by the user. For example,high grades might get one message and low grades might get another message.

4.8 Explain why the output of the first statement below is 0, but the output of thesecond is 45:

cout << ( 9 * 3 < 4 * 5) << endl;cout << (9 * (3 < 4) * 5) << endl;

Why are the parentheses needed?

4.9 What is output by each of the following statements (why?)

cout << ( 9 * 5 < 45) << endl;cout << (9*5 < 45 < 30) << endl;

June 7, 1999 10:10 owltex Sheet number 39 Page number 121magentablack

4.4 Block Statements and Defensive Programming 121

4.10 Write a code fragment in which astring variablegrade is assigned one of threestates:"High Pass" , "Pass" , and"Fail" according to whether an inputinteger grade is between 80 and 100, between 60 and 80, or below 60, respectively.It may be useful to write the fragment so that a message is printed and then modifyit so that astring variable is assigned a value.

The Dangling Else Problem. Using the block delimiters{ and} in all cases when writingStumbling Block

if /else statements can prevent errors that are very difficult to find because the inden-tation, which conveys meaning to a reader of the program, is ignored by the compilerwhen code is generated. Using block delimiters also helps in avoiding a problem thatresults from a potential ambiguity in computer languages such as C++ that useif /elsestatements (C and Pascal have the same ambiguity, for example).

The following code fragment attempts to differentiate odd numbers less than zerofrom other numbers. The indentation of the code conveys this meaning, but the codedoesn’t execute as intended:

if (x % 2 == 1)if (x < 0)

cout << " number is odd and less than zero" << endl;else

cout << " number is even " << endl;

What happens if theint objectx has the value 13? The indentation seems to hint thatnothing will be printed. In fact, the string literal"number is even" will be printedif this code segment is executed whenx is 13. The segment is read by the compiler asthough it is indented as follows:

if (x % 2 == 1)if (x < 0)

cout << " number is odd and less than zero" << endl;else

cout << " number is even " << endl;

The use of braces makes the intended use correspond to what happens. Nothing is printedwhenx has the value 13 in

if (x % 2 == 1){ if (x < 0)

cout << " number is odd and less than zero" << endl;}else{ cout << " number is even " << endl;}

As we have noted before, the indentation used in a program is to assist the human reader.The computer doesn’t require a consistent or meaningful indentation scheme. Misleadingindentation can lead to hard-to-find bugs where the human sees what is intended ratherthan what exists.

June 7, 1999 10:10 owltex Sheet number 40 Page number 122magentablack

122 Chapter 4 Control, Functions, and Classes

One rule to remember from this example is that anelse always corresponds to themost recentif . Without this rule there is ambiguity as to whichif theelse belongs;this is known as thedangling-elseproblem. Always employ curly braces{ and} whenusing block statements withif /else statements (and later with looping constructs). Ifbraces are always used, there is no ambiguity, because the braces serve to delimit thescope of anif test.

Claude Shannon (b. 1916)

Claude Shannon foundedinformation theory —a subfield of computer sciencethat is used today in developing methods for encrypting information. Encryption

is used to store data in a secure manner sothat the information can be read only bydesignated people.

In his 1937 master’s thesis, Shannonlaid the foundation on which modern com-puters are built by equating Boolean logicwith electronic switches. This work en-abled hardware designers to design, build,and test circuits that could perform logi-cal as well as arithmetic operations. In aninterview in [Hor92], Shannon responds tothe comment that his thesis is “possibly themost important master’s thesis in the cen-tury” with “It just happened that no oneelse was familiar with both those fields atthe same time.” He then adds a wonderfulnon sequitur: “I’ve always loved that word‘Boolean.’ ” Shannon is fond of jugglingand riding unicycles. Among his inven-tions are a juggling “dummy” that looks

like W.C. Fields and a computer THROBAC: Thrifty Roman Numeral BackwardComputer.

Although much of Shannon’s work has led to significant advances in thetheory of communication, he says:

I’ve always pursued my interests without much regard for financial value orthe value to the world; I’ve spent lots of time on totally useless things.

Shannon’s favorite food is vanilla ice cream with chocolate sauce.Shannon received the National Medal of Science in 1966. For more information

see [Sla87, Hor92].

June 7, 1999 10:10 owltex Sheet number 41 Page number 123magentablack

4.5 Functions That ReturnValues 123

}

}

...

...

double

{

double value;

cin >> value;

cout << ... << sqrt(value) << endl;

cout << ... << 10.7238 << endl;

cin >> value;

sqrt(double x) 115.0

115.0Calling function sqrt(115.0)

Returning 10.7238 from sqrt(115.0)

}

return root;

// code to give root a value

double root;

Figure 4.2 Evaluating the function call sqrt115.0

4.5 FunctionsThat ReturnValues

Civilization advances by extending the numberof important operations which we can perform without thinking about them.

Alfred North WhiteheadAn Introduction to Mathematics

In Chapter 3 we studied programmer-defined functions, such asSlicePrice inpizza.cpp,Program 3.5, whose prototype is

void SlicePrice(int radius, double price)

The return type ofSlicePrice is void . Many programs require functions that haveother return types. You’ve probably seen mathematical functions on hand-held calcula-tors such as sin(x) or

√x. These functions are different from the functionSlicePrice

in that they return a value. For example, when you use a calculator, you might enter thenumber 115, then press the square-root key. This displays the value of

√115 or 10.7238.

The number 115 is anargument to the square root function. The value returned bythe function is the number 10.7238. Program 4.6 is a C++ program that processes in-formation in the same way: users enter a number, and the square root of the number isdisplayed.

Control flow fromusemath.cppis shown in Fig. 4.2. The value 115, entered by theuser and stored in the variablevalue , is copied into a memory location associated withthe parameterx in the functionsqrt . The square root of 115 is calculated, and areturnstatement in the functionsqrt returns this square root, which is used in place of theexpressionsqrt(value) in the cout statement. As shown in Fig. 4.2, the value10.7238 is displayed as a result.

June 7, 1999 10:10 owltex Sheet number 42 Page number 124magentablack

124 Chapter 4 Control, Functions, and Classes

The functionsqrt is accessible by including the header file<cmath> . Table 4.5lists some of the functions accessible from this header file. A more complete tableof functions is given as Table F.1 in Howto F. In the sample output ofusemath.cpp,Program 4.6, the square roots of floating-point numbers aren’t always exact. For example,√

100.001= 10.0000499998, but the value displayed is 10. Floating-point values cannotalways be exactly determined. Because of inherent limits in the way these values arestored in the computer, the values are rounded off to the most precise values that canbe represented in the computer. The resultingroundoff error illustrates the theme ofconceptualandformal models introduced in Chapter 1. Conceptually, the square root of100.001 can be calculated with as many decimal digits as we have time or inclination towrite down. In the formal model of floating-point numbers implemented on computers,the precision of the calculation is limited.

Program 4.6 usemath.cpp

#include <iostream>

#include <cmath>

using namespace std;

// illustrates use of math function returning a value

int main()

{

double value;

cout << "enter a positive number ";

cin >> value;

cout << "square root of " << value < < " = " << sqrt(value) << endl;

return 0;

} usemath.cpp

O U T P U T

prompt> usemathenter a positive number 115square root of 115 = 10.7238prompt> usemathenter a positive number 100.001square root of 100.001 = 10prompt> usemathenter a positive number -16square root of -16 = nan

June 7, 1999 10:10 owltex Sheet number 43 Page number 125magentablack

4.5 Functions That ReturnValues 125

Table 4.5 Some functions in <cmath>

function name prototype returns

double fabs (double x) absolute value of xdouble log (double x) natural log of xdouble log10 (double x) base-ten log of xdouble sin (double x) sine of x (x in radians)double cos (double x) cosine of x (x in radians)double tan (double x) tangent of x (x in radians)double asin (double x) arc sine of x [−π/2, π/2]double acos (double x) arc cosine of x [0, π ]double atan (double x) arc tangent of x [−π/2, π/2]double pow (double x, xy

double y)double sqrt (double x)

√x, square root of x

double floor (double x) largest integer value≤ xdouble ceil (double x) smallest integer value≥ x

Finally, although the program prompts for positive numbers, there is no check toensure that the user has entered a positive number. In the output shown, the symbolnan stands for “not a number.”7 Not all compilers will display this value. In particular,on some computers, trying to take the square root of a negative number may cause themachine to lock up. It would be best to guard the callsqrt(value) using anifstatement such as the following one:

if (0 <= value){ cout << "square root of " << value < < " = "

<< sqrt(value) << endl;}else{ cout << "nonpositive number " << value

<< " entered" << endl;}

Alternatively, we couldcomposethe functionsqrt with the functionfabs , whichcomputes absolute values.

cout << "square root of " << value < < " = "<< sqrt(fabs(value)) << endl;

The result returned by the functionfabs is used as an argument tosqrt . Since thereturn type offabs is double (see Table 4.5), the argument ofsqrt has the righttype.

7Some compilers printNaN, others crash rather than printing an error value.

June 7, 1999 10:10 owltex Sheet number 44 Page number 126 magentablack

126 Chapter 4 Control, Functions, and Classes

4.5.1 The Math Library <cmath>

In C and C++ several mathematical functions are available by accessing a math libraryusing #include <cmath> .8 Prototypes for some of these functions are listed inTable 4.5, and a complete list is given as Table F.1 in Howto F.

All of these functions returndouble values and havedouble parameters. Integervalues can be converted todouble s, so the expressionsqrt(125) is legal (andevaluates to 11.18033). The functionpow is particularly useful, because there is nobuilt-in exponentiation operator in C++. For example, the statement

cout << pow(3,13) << endl}

outputs the value of 313: three to the thirteenth.The functions declared in<cmath> are tools that can be used in any program. As

programmers, we’ll want to develop functions that can be used in the same way. Onoccasion, we’ll develop functions that aren’t useful as general-purpose tools but makethe development of one program simpler. For example, inpizza.cpp,Program 3.5, theprice per square inch of pizza is calculated and printed by the functionSlicePrice .If the value were returned by the function rather than printed, it could be used to de-termine which of several pizzas was the best buy. This is shown inpizza2.cpp,Pro-gram 4.7. Encapsulating the calculation of the price per square inch in a function,as opposed to using the expressionsmallPrice/(3.14159 * smallRadius *smallRadius) , avoids errors that might occur in copying or retyping the expressionfor a large pizza. Using a function also makes it easier to include other sizes of pizza inthe same program. If it develops that we’ve made a mistake in calculating the price persquare inch, isolating the mistake in one function makes it easier to change than findingall occurrences of the calculation and changing each one.

Program 4.7 pizza2.cpp

#include <iostream>using namespace std;

// find the price per square inch of pizza// to compare large and small sizes for the best value//// Owen Astrachan// March 29, 1999//

double Cost(double radius, double price)// postcondition: returns the price per sq. inch{

return price/(3.14159 ∗radius ∗radius);}

8The namecmath is the C++ math library, but with many older compilers you will need to usemath.hrather thancmath .

June 7, 1999 10:10 owltex Sheet number 45 Page number 127magentablack

4.5 Functions That ReturnValues 127

int main(){

double smallRadius, largeRadius;double smallPrice, largePrice;double smallCost,largeCost;

// input phase of computation

cout << "enter radius and price of small pizza ";cin >> smallRadius >> smallPrice;

cout << "enter radius and price of large pizza ";cin >> largeRadius >> largePrice;

// process phase of computation

smallCost = Cost(smallRadius,smallPrice);largeCost = Cost(largeRadius,largePrice);

// output phase of computation

cout << "cost of small pizz a = " << smallCost << " per sq.inch" << endl;cout << "cost of large pizz a = " << largeCost << " per sq.inch" << endl;

if (smallCost < largeCost){ cout << "SMALL is the best value " << endl;}else{ cout << "LARGE is the best value " << endl;}

return 0;}

pizza2.cpp

O U T P U T

prompt> pizza2enter radius and price of small pizza 6 6.99enter radius and price of large pizza 8 10.99cost of small pizza = 0.0618052 per sq.inchcost of large pizza = 0.0546598 per sq.inchLARGE is the best value

From the user’s point of view, Program 3.5 and Program 4.7 exhibit similar, thoughnot identical, behavior. When two programs exhibit identical behavior, we describe thissameness by saying that the programs are identical asblack boxes.We cannot see the

June 7, 1999 10:10 owltex Sheet number 46 Page number 128magentablack

128 Chapter 4 Control, Functions, and Classes

inside of a black box; the behavior of the box is discernible only by putting values intothe box (running the program) and noting what values come out (are printed by theprogram). A black box specifies input and output, but not how the processing step takesplace. Theballoon class and the math functionsqrt are black boxes; we don’t knowhow they are implemented, but we can use them in programs by understanding theirinput and output behavior.

4.5.2 Pre- and Post-conditions

In the functionSlicePrice of pizza2.cpp,Program 4.7, a comment is given in theform of apostcondition. A postcondition of a function is a statement that is true when thefunction finishes executing. Each function in this book will include a postcondition thatdescribes what the function does. Some functions havepreconditions. A preconditionstates what parameter values can be passed to the function. Together a function’s pre-condition and postcondition provide a contract for programmers who call the function:if the precondition is true the postcondition will be true. For example, a precondition ofthe functionsqrt might be that the function’s parameter is non-negative.

Program Tip 4.5: When calling functions, read postconditions carefully.When writing functions, provide postconditions. When possible, provide aprecondition as well as a postcondition since preconditions provide programmers withinformation about what range of values can be passed to each parameter of a function.

In themain function ofpizza2.cpp,the extraction operator>> extracts two valuesin a single statement. Just as the insertion operator<< can be used to put several itemson the output streamcout , the input streamcin continues to flow so that more thanone item can be extracted.

4.11 Write program fragments or complete programs that convert degrees Celsius toPause to Reflect

degrees Fahrenheit, British thermal units (Btu) to joules (J), and knots to miles perhour. Note thatx degrees Celsius equals(9/5)x + 32 degrees Fahrenheit; thatxJ equals 9.48× 10−4(x)Btu; and that 1 knot= 101.269 ft/min (and that 5,280 ft= 1 mile). At first do thiswithoutusing assignment statements, by incorporatingthe appropriate expressions in output statements. Then define variables and useassignment statements as appropriate. Finally, write functions for each of theconversions.

4.12 Modify pizza2.cpp,Program 4.7, to use the functionpow to squareradius inthe functionCost .

4.13 If a negative argument to the functionsqrt causes an error, for what values ofxdoes the following code fragment generate an error?

if (x >= 0 && sqrt(x) > 100)cout << "big number" << endl;

June 7, 1999 10:10 owltex Sheet number 47 Page number 129magentablack

4.5 Functions That ReturnValues 129

4.14 Heron’s formula gives the area of a triangle in terms of the lengths of the sides ofthe triangle:a, b, andc .

area= √s · (s − a) · (s − b) · (s − c) (4.1)

wheres is the semiperimeter, or half the perimetera+b+ c of the triangle. Writea functionTriangleArea that returns the area of a triangle. The sides of thetriangle should be parameters toTriangleArea .

4.15 The law of cosines gives the length of one side of a triangle,c, in terms of theother sidesa andb and the angleC formed by the sidesa andb:

c2 = a2+ b2− 2 · a · b cos(C)

Write a functionSideLength that computes the length of one side of a triangle,given the other two sides and the angle (in radians) between the sides as parametersto SideLength .

4.16 The following code fragment allows a user to enter three integers:

int a,b,c;cout << "enter three integers ";cin >> a >> b >> c;

Add code that prints the average of the three values read. Does it make a differenceif the type is changed fromint to double ? Do you think that>> has the samekind of associativity as=, the assignment operator?

4.5.3 Function ReturnTypes

The functionssqrt andSlicePrice used in previous examples both returneddoublevalues. In this section we’ll see that other types can be returned.

Determining Leap Years. Leap years have an extra day (February 29) not present innonleap years. We use arithmetic and logical operators to determine whether a year is aleap year. Although it’s common to think that leap years occur every four years, the rulesfor determining leap years are somewhat more complicated, because the period of theEarth’s rotation around the Sun is not exactly 365.25 days but approximately 365.2422days.

If a year is evenly divisible by 400, then it is a leap year.

Otherwise, if a year is divisible by 100, then it isnot a leap year.

The only other leap years are evenly divisible by 4.9

9These rules correspond to a year length of 365.2425 days. In theNew York Timesof January 2, 1996(page B7, out-of-town edition), a correction to the rules used here is given. The year 4000 isnot a leapyear, nor will any year that’s a multiple of 4000 be a leap year. Apparently this rule, corresponding to ayear length of 365.24225 days, will have to be modified too, but we probably don’t need to worry thatour program will be used beyond the year 4000.

June 7, 1999 10:10 owltex Sheet number 48 Page number 130 magentablack

130 Chapter 4 Control, Functions, and Classes

For example, 1992 is a leap year (it is divisible by 4), but 1900 is not a leap year (it isdivisible by 100), yet 2000 is a leap year, because, although it is divisible by 100, it isalso divisible by 400.

The boolean-valued functionIsLeapYear in Program 4.8 uses multiplereturnstatements to implement this logic.

Recall that in the expression(a % b) the modulus operator%evaluates to theremainder whena is divided byb. Thus, 2000 % 400 == 0 , since there is noremainder when 2000 is divided by 400.

The sequence of cascadedif statements inIsLeapYear tests the value of theparameteryear to determine whether it is a leap year. Consider the first run shown,whenyear has the value 1996. The first test,year % 400 == 0 , evaluates to false,because 1996 is not divisible by 400. The second test evaluates to false, because 1996is not divisible by 100. Since 1996= 4× 499, the third test,(yea r % 4 == 0) , istrue, so the valuetrue is returned from the functionIsLeapYear . This makes theexpressionIsLeapYear(1996) in main true, so the message is printed indicatingthat 1996 is a leap year. You may be tempted to write

if (IsLeapYear(year) == true)

rather than using the form shown inisleap.cpp.This works, but thetrue is redundant,because the functionIsLeapYear is boolean-valued: it is either true or false.

The comments for the functionIsLeapYear are given in the form of apreconditionand a postcondition. For our purposes, a precondition is what must be satisfied forthe function to work as intended. The “as intended” part is what is specified in thepostcondition. These conditions are acontractfor the caller of the function to read: if theprecondition is satisfied, the postcondition will be satisfied. In the case ofIsLeapYearthe precondition states that the function works for any year greater than 0. The functionis not guaranteed to work for the year 0 or if a negative year such as−10 is used toindicate the year 10B.C.

It is often possible to implement a function in many ways so that its postconditionis satisfied. Program 4.9 shows an alternative method for writingIsLeapYear . Us-ing a black-box test, this version is indistinguishable from theIsLeapYear used inProgram 4.8.

Program 4.8 isleap.cpp

#include <iostream>using namespace std;

// illustrates user-defined function for determining leap years

bool IsLeapYear(int year)// precondition: year > 0// postcondition: returns true if year is a leap year, else returns false{

if (year % 400 == 0) // divisible by 400{ return true;}

June 7, 1999 10:10 owltex Sheet number 49 Page number 131magentablack

4.5 Functions That ReturnValues 131

else if (year % 100 == 0) // divisible by 100{ return false;}else if (yea r % 4 == 0) // divisible by 4{ return true;}return false;

}

int main(){

int year;cout << "enter a year ";cin >> year;if (IsLeapYear(year)){ cout << year << " has 366 days, it is a leap year" << endl;}else{ cout << year << " has 365 days, it is NOT a leap year" << endl;}return 0;

} isleap.cpp

O U T P U T

prompt> isleapenter a year 19961996 has 366 days, it is a leap year

prompt> isleapenter a year 19001900 has 365 days, it is NOT a leap year

Program 4.9 isleap2.cpp

bool IsLeapYear(int year)// precondition: year > 0// postcondition: returns true if year is a leap year, else false{

return (year % 400 == 0) || ( year % 4 == 0 && year % 100 != 0 );} isleap2.cpp

A boolean value is returned fromIsLeapYear because the logical operators&&and || return boolean values. For example, the expressionIsLeapYear(1974)causes the following expression to be evaluated by substituting 1974 foryear :

June 7, 1999 10:10 owltex Sheet number 50 Page number 132 magentablack

132 Chapter 4 Control, Functions, and Classes

(1974 % 400 == 0) || ( 197 4 % 4 == 0 && 1974 % 100 != 0 );

Since the logical operators are evaluated left to right to support short-circuit evaluation,the subexpression1974 % 400 == 0 is evaluated first. This subexpression is false,because1974 % 400 is 374. The rightmost parenthesized expression is then evaluated,and its subexpression1974 % 4 == 0 is evaluated first. Since this subexpression isfalse, the entire&&expression must be false (why?), and the expression1974 % 100!= 0 is not evaluated. Since both subexpressions of|| are false, the entire expressionis false, andfalse is returned.

Boolean-valued functions such asIsLeapYear are often calledpredicates.Predi-cate functions often begin with the prefixIs . For example, the functionIsEven mightbe used to determine whether a number is even; the functionIsPrime might be used todetermine whether a number is prime (divisible by only 1 and itself, e.g., 3, 17); and thefunctionIsPalindrome might be used to determine whether a word is a palindrome(reads the same backward as forward, e.g., mom, racecar).

Program Tip 4.6: Follow conventions when writing programs. Conven-tions make it easier for other people to read and use your programs and for you to readthem long after you write them. One common convention is using the prefixIs forpredicate/boolean-valued functions.

Converting Numbers to English. We’ll explore a program that converts some integersto their English equivalent. For example, 57 is “fifty-seven” and 14 is “fourteen.”Such a program might be the basis for a program that works as a talking cash register,speaking the proper coins to give as change. With speech synthesis becoming cheaper oncomputers, it’s fairly common to encounter a computer that “speaks.” The number youhear after dialing directory assistance is often spoken by a computer. There are manyhome finance programs that print checks; these programs employ a method of convertingnumbers to English to print the checks. In addition to using arithmetic operators, theprogram shows that functions can return strings as well as numeric and boolean types,and it emphasizes the importance of pre- and postconditions.

Program 4.10 numtoeng.cpp

#include <iostream>#include <string>using namespace std;

// converts two digit numbers to English equivalent// Owen Astrachan, 3/30/99

string DigitToString(int num)// precondition: 0 <= num < 10// postcondition: returns english equivalent, e.g., 1->one,...9->nine

June 7, 1999 10:10 owltex Sheet number 51 Page number 133 magentablack

4.5 Functions That Return Values 133

{if (0 == num) return "zero";else if (1 == num) return "one";else if (2 == num) return "two";else if (3 == num) return "three";else if (4 == num) return "four";else if (5 == num) return "five";else if (6 == num) return "six";else if (7 == num) return "seven";else if (8 == num) return "eight";else if (9 == num) return "nine";else return "?";

}

string TensPrefix(int num)// precondition: 10 <= num <= 99 and num % 10 == 0// postcondition: returns ten, twenty, thirty, forty, etc.// corresponding to num, e.g., 50->fifty{

if (10 == num) return "ten";else if (20 == num) return "twenty";else if (30 == num) return "thirty";else if (40 == num) return "forty";else if (50 == num) return "fifty";else if (60 == num) return "sixty";else if (70 == num) return "seventy";else if (80 == num) return "eighty";else if (90 == num) return "ninety";else return "?";

}

string TeensToString(int num)// precondition: 11 <= num <= 19// postcondition: returns eleven, twelve, thirteen, fourteen, etc.// corresponding to num, e.g., 15 -> fifteen{

if (11 == num) return "eleven";else if (12 == num) return "twelve";else if (13 == num) return "thirteen";else if (14 == num) return "fourteen";else if (15 == num) return "fifteen";else if (16 == num) return "sixteen";else if (17 == num) return "seventeen";else if (18 == num) return "eighteen";else if (19 == num) return "nineteen";else return "?";

}

string NumToString(int num)// precondition: 0 <= num <= 99// postcondition: returns english equivalent, e.g., 1->one, 13->thirteen{

if (0 <= num && num < 10){ return DigitToString(num);}

June 7, 1999 10:10 owltex Sheet number 52 Page number 134magentablack

134 Chapter 4 Control, Functions, and Classes

else if (10 < num && num < 20)

{ return TeensToString(num);

}

else if (num % 10 == 0)

{ return TensPrefix(num);

}

else

{ // concatenate ten’s digit with one’s digit

return TensPrefix(10 ∗ (num/10)) + "-" + DigitToString(num % 10);

}

}

int main()

{

int number;

cout << "enter number between 0 and 99: ";

cin >> number;

cout << number < < " = " << NumToString(number) << endl;

return 0;

} numtoeng.cpp

O U T P U T

prompt> numtoengenter number between 0 and 99: 2222 = twenty-two

prompt> numtoengenter number between 0 and 99: 1717 = seventeen

prompt> numtoengenter number between 0 and 99: 103103 = ?-three

The code in theDigitToString function does not adhere to the rule of using blockstatements in everyif /else statement. In this case, using{} delimiters would make theprogram unnecessarily long. It is unlikely that statements will be added (necessitatingthe use of a block statement), and the form used here is clear.

June 7, 1999 10:10 owltex Sheet number 53 Page number 135magentablack

4.5 Functions That ReturnValues 135

Program Tip 4.7: White space usually makes a program easier to readand clearer. Block statements used with if /else statements usuallymake a program more robust and easier to change. However, there areoccasions when these rules are not followed. As you become a more practiced program-mer, you’ll develop your own aesthetic sense of how to make programs more readable.

A new use of the operator+ is shown in functionNumToString . In the finalelsestatement, three strings are joined together using the+ operator:

return TensPrefix(10*(num/10))+ "-" + DigitToString(num%10);

When used withstring values, the+ operator joins orconcatenates(sometimes“catenates”) thestring subexpressions into a newstring . For example, the value of"apple" + "sauce" is a newstring , "applesauce" . This is another exampleof operator overloading; the+ operator has different behavior forstring , double ,andint values.

Robust Programs. In the sample runs shown, the final input of 103 does not result inthe display ofone hundred three . The value of 103 violates the precondition ofNumToString , so there is no guarantee that the postcondition will be satisfied.Robustprograms and functions do not bomb in this case, but either return some value thatindicates an error or print some kind of message telling the user that input values aren’tvalid. The problem occurs in this program because"?" is returned by the function callTensPrefix(10 * (num/10)) . The value of the argument toTensPrefix is10×(103/10)== 10×10== 100. This value violates the precondition ofTensPrefix .If no finalelse were included to return a question mark, then nothing would be returnedfrom the functionTensPrefix when it was called with 103 as an argument. Thissituation makes the concatenation of “nothing” with the hyphen and the value returnedby DigitToString(num % 10) problematic, and the program would terminate,because there is nostring to join with the hyphen.

Many programs likenumtoeng.cppprompt for an input value within a range. Afunction that ensures that input is in a specific range by reprompting would be veryuseful. A library of three related functions is specified inprompt.h. We’ll study thesefunctions in the next chapter, and you can find information about them in Howto G. Hereis a modified version ofmain that usesPromptRange :

int main(){

int number = PromptRange("enter a number",0,99);cout << number < < " = " << NumToString(number) << endl;

return 0;}

June 7, 1999 10:10 owltex Sheet number 54 Page number 136magentablack

136 Chapter 4 Control, Functions, and Classes

O U T P U T

prompt> numtoengenter number between 0 and 99: 103enter a number between 0 and 99: 100enter a number between 0 and 99: -1enter a number between 0 and 99: 9999 = ninety-nine

You don’t have enough programming tools to know how to writePromptRange(you need loops, studied in the next chapter), but the specifications of each functionmake it clear how the functions are called. You can treat the functions as black boxes,just as you treat the square-root functionsqrt in <cmath> as a black box.

4.17 Write a functionDaysInMonth that returns the number of days in a monthPause to Reflect

encoded as an integer with 1= January, 2= February,…, 12= December. Theyear is needed, because the number of days in February depends on whether theyear is a leap year. In writing the function, you can callIsLeapYear . Thespecification for the function is

int DaysInMonth(int month,int year)// pre: month coded as : 1 = january, ..., 12 = december// post: returns # of days in month in year

4.18 Why are parentheses needed in the expressionTensPrefix(10*(num/10)) ?For example, ifTensPrefix(10*num/10) is used, the program generates anon-number when the user enters 22.

4.19 Write a predicate functionIsEven that evaluates to true if itsint parameter isan even number. The function should work for positive and negative integers. Tryto write the function using only one statement:return expression.

4.20 Write a functionDayNamewhose header is

string DayName(int day)// pre: 0 <= day <= 6// post: returns string representing day, with// 0 = "Sunday" , 1 = "Monday", ... , 6 = "Saturday"

so that the statementcout << DayName(3) << endl; printsWednesday .

4.21 Describe how to modify the functionNumToString in numtoeng.cpp,Pro-gram 4.10, so that it works with three-digit numbers.

June 7, 1999 10:10 owltex Sheet number 55 Page number 137 magentablack

4.6 Class Member Functions 137

4.22 An Islamic yeary is a leap year if the remainder, when 11y + 14 is divided by30, is less than 11. In particular, the 2nd, 5th, 7th, 10th, 13th, 16th, 18th, 21st,24th, 26th, and 29th years of a 30-year cycle are leap years. Write a functionIsIslamicLeapYear that works with this definition of leap year.

4.23 In the Islamic calendar [DR90] there are also 12 months, which strictly alternatebetween 30 days (odd-numbered months) and 29 days (even-numbered months),except for the twelfth month,Dhu al-Hijjah,which in leap years has 30 days. Writea functionDaysInIslamicMonth for the Islamic calendar that uses only threeif statements.

4.6 Class Member FunctionsSection 3.4 discusses a class namedBalloon for simulating hot-air balloons. We’veused the classstring extensively in our examples, but we haven’t used all of thefunctionality provided by strings themselves. Recall from Section 3.4 that functionsprovided by a class are calledmember functions. In this section we’ll study threestring member functions, and many more are explained in Howto C. We’ll also havea sneak preview at the classDate which is covered more extensively in the next chapter.We’ll show just one example program using the class, but the program provides a glimpseof the power that classes bring to programming.

4.6.1 string Member Functions

The functions we’ve studied so far, like those in<cmath> , are calledfree functionsbecause they do not belong to a class. Member functions are part of a class and areinvoked by applying a function to an object with the dot operator. Program 4.11 showsthestring member functionslength andsubstr . The functionlength returnsthe number of characters in a string, the functionsubstr returns asubstringof a stringgiven a starting position and a number of characters.

Program 4.11 strdemo.cpp

#include <iostream>#include <string>using namespace std;

// illustrates string member functions length() and substr()

int main(){

string s;cout << "enter string: ";cin >> s;int len = s.length();cout << s << " has " << len << " characters" << endl;cout << "first char is " << s.substr(0, 1) << endl;

June 7, 1999 10:10 owltex Sheet number 56 Page number 138magentablack

138 Chapter 4 Control, Functions, and Classes

cout << "last char is " << s.substr(s.length() −1, 1) << endl;cout << endl << "all but first is " << s.substr(1,s.length()) << endl;return 0;

} strdemo.cpp

O U T P U T

prompt> strdemoenter string: theatertheater has 7 charactersfirst char is tlast char is rall but first is heaterprompt> strdemoenter string: slaughtertheater has 9 charactersfirst char is slast char is rall but first is laughter

The first position orindex of a character in a string is zero, so the last index in a stringof 11 characters is 10. The prototypes for these functions are given in Table 4.6.

Eachstring member function used in Program 4.11 is invoked using an objectand the dot operator. For example,s.length() returns the length ofs . When I readcode, I read this as “s dot length”, and think of the length function as applied to the objects, returning the number of characters in s.

Table 4.6 Three string member functions

function prototype and description

int length()postcondition: returns the number of characters in the string

string substr(int pos, int len)precondition: 0 <= pos < length()postcondition: returns substring oflen characters beginning at positionpos(as many characters as possible if len too large, but error if pos is out of range)

int find(string s)postcondition: returns first position/index at which string s begins(returnsstring::npos if s does not occur)

June 7, 1999 10:10 owltex Sheet number 57 Page number 139magentablack

4.6 Class Member Functions 139

Program Tip 4.8: Ask not what you can do to an object, ask what anobject can do to itself. When you think about objects, you’ll begin to think aboutwhat an object can tell you about itself rather than what you can tell an object to do.

In the last use ofsubstr in Program 4.11 more characters are requested than canbe supplied by the arguments in the calls.substr(1, s.length()) . Startingat index 1, there are onlys.length()-1 characters ins . However, the functionsubstr “does the right thing” when asked for more characters than there are, and givesas many as it can without generating an error. For a full description of this and otherstring functions see Howto C. Although the string returned bysubstr is printed instrdemo.cpp, the returned value could be stored in a string variable as follows:

string allbutfirst = s.substr(1,s.length());

The string Member Function find . The member functionfind returns the indexin a string at which another string occurs. For example,"plant" occurs at index threein the string"supplant" , at index five in"transplant" , and does not occur in"vegetable" . Program 4.12,strfind.cppshows howfind works. The return valuestring::npos indicates that a substring does not occur. Your code should not dependonstring::npos having any particular value10.

Program 4.12 strfind.cpp

#include <iostream>#include <string>using namespace std;

int main(){

string target = "programming is a creative process";string s;cout << "target string: " << target << endl;cout << "search for what substring: ";cin >> s;int index = target.find(s);if (index != string::npos){ cout << "found at " << index << endl;}else{ cout << "not found" << endl;}return 0;

} strfind.cpp

10Actually, the value ofstring::npos is the largest positive index, see Howto C.

June 7, 1999 10:10 owltex Sheet number 58 Page number 140magentablack

140 Chapter 4 Control, Functions, and Classes

O U T P U T

prompt> strfindtarget string: programming is a creative processsearch for what substring: profound at 0prompt> strfindtarget string: programming is a creative processsearch for what substring: gramfound at 3prompt> strfindtarget string: programming is a creative processsearch for what substring: createnot found

The double colon:: used instring::npos separates the value, in this casenpos , from the class in which the value occurs, in this casestring . The:: is calledthescope resolution operator, we’ll study it in more detail in the next chapter.

4.6.2 Calling and Writing Functions

When you first begin to use functions that return values, you may forget to processthe return value. All non-void functions return a value that should be used in a C++expression (e.g., printed, stored in a variable, used in an arithmetic expression). Thefollowing C++ statements show how three of the functions studied in this chapter (sqrt ,NumToString , andIsLeap ) are used in expressions so that the values returned bythe functions aren’t ignored.

double hypotenuse = sqrt{side1*side1 + side2*side2);cout << NumToString(47) << endl;bool millenniumLeaps = IsLeap(2000) || IsLeap(3000);

It doesn’t make sense, for example, to write the following statements in which the valuereturned bysqrt is ignored.

double s1, s2;cout << "enter sides: ";cin >> s1 >> s2;double root;sqrt(s1*s1 + s2*s2);

The programmer may have meant to store the value returned by the function call tosqrtin the variableroot , but the return value from the function call in the last statement isignored.

June 7, 1999 10:10 owltex Sheet number 59 Page number 141magentablack

4.6 Class Member Functions 141

Whenever you call a function, think carefully about the function’s prototype and itspostcondition. Be sure that if the function returns a value that you use the value.11

ProgramTip 4.9: Do not ignore the value returned by non-void functions.Think carefully about each function call you make when writing programs and do

something with the return value that makes sense in the context of your program and thatis consistent with the type and value returned.

Write Lots of Functions. When do you write a function? You may be writing a programlike pizza2.cpp, Program 4.7, where the functionCost is used to calculate how much asquare inch of pizza costs. The function is reproduced here.

double Cost(double radius, double price)// postcondition: returns the price per sq. inch{

return price/(3.14159*radius*radius);}

Is it worth writing another function calledCircleArea like this?

double CircleArea(double radius)// postcondition: return area of circle with given radius{

return radius*radius*3.14159;}

In general, when should you write a function to encapsulate a calculation or sequence ofstatements? There is no simple answer to this question, but there are a few guidelines.

Program Tip 4.10: Functions encapsulate abstractions and lead to codethat’s often easier to read and modify. Do not worry about so-called executiontime “overhead” in the time it takes a program to execute a function call. Make yourprograms correct and modifiable before worrying about making them fast.

As an example, it’s often easier to write a complex boolean expression as a functionthat might includeif/else statements, and then call the function, than to determinewhat the correct boolean expression is. In the next section we’ll study a tool from logicthat helps in writing correct boolean expressions, but writing functions are useful whenyou’re trying to develop appropriate loop tests. For example, if you need to determine

11Some functions return a value but are called because they cause some change in program state separatefrom the value returned. Such functions are said to haveside-effectssince they cause an effect “on theside,” or in addition to the value returned by the function. In some cases the returned value of a functionwith side-effects is ignored.

June 7, 1999 10:10 owltex Sheet number 60 Page number 142magentablack

142 Chapter 4 Control, Functions, and Classes

if a one-character string represents a consonant, it’s probably easier to write a functionIsVowel and use that function to writeIsConsonant , or to use!IsVowel() whenyou need to determine if a string is a consonant.

bool IsVowel(string s)// pre: s is a one-character string// post: returns true if s is a vowel, return false{

if (s.length() != 1){ return false;}return s == "a" || s == "e" || s == "i" ||

s == "o" || s == "u";}

The return Statement. In the functionIsVowel() there are tworeturn state-ments and anif without anelse . When areturn statement executes, the functionbeing returned from immediately exits. InIsVowel() , if the string parameters hasmore than one character, the function immediately returnsfalse . Since the functionexits, there is no need for anelse body, though some programmers prefer to use anelse . Some programmers prefer to have a singlereturn statement in every function.To do this requires introducing a local variable and using anelse body as follows.

bool IsVowel(string s)// pre: s is a one-character string// post: returns true if s is a vowel, else return false{

bool retval = false; // assume falseif (s.length() == 1){ retval = (s == "a" || s == "e" || s == "i" ||

s == "o" || s == "u");}return retval;

}

You should try to get comfortable with the assignment toretval inside theif state-ment. It’s often easier to think of the assignment using this code.

if (s == "a"|| s == "e"|| s == "i"|| s == "o"|| s == "u"){ retval = true;}else{ retval = false;}

This style of programming uses more code. It’s just as efficient, however, and it’s ok touse it though the single assignment toretval is more terse and, to many, more elegant.

June 7, 1999 10:10 owltex Sheet number 61 Page number 143magentablack

4.6 Class Member Functions 143

4.6.3 The Date class

At the beginning of this chapter we discussed writing a functionPrintMonth that printsa calendar for a month specified by a number and a year. As described, printing a calendarfor January of the year 2001 could be done with the callPrintMonth(1,2001) . Youcould write this function with the tools we’ve studied in this chapter though it wouldbe cumbersome to make a complete calendar. However, using the classDate makes itmuch simpler to write programs that involve dates and calendars than writing your ownfunctions likeIsLeap . In general, it’s easier to use classes that have been developedand debugged than to develop your own code to do the same thing, though it’s not alwayspossible to find classes that serve your purposes.

We won’t discuss this class in detail until the next chapter, but you can see howvariables of typeDate are defined, and two of theDate member functions used inProgram 4.13. More information about the class is accessible in Howto G. To useDateobjects you’ll need to add#include"date.h" to your programs.

Program 4.13 datedemo.cpp

#include <iostream>

using namespace std;

#include "date.h"

// simple preview of using the class Date

int main()

{

int month, year;

cout << "enter month (1-12) and year ";

cin >> month >> year;

Date d(month, 1, year);

cout << "that day is " << d << ", it i s a " << d.DayName() << endl;

cout << "the month has " << d.DaysIn() << " days in it " << endl;

return 0;

} datedemo.cpp

After examining the program and the output on the next page, you should be thinkabout how you would use the classDate to solve the following problems, each can besolved with just a few lines of code.

4.24 Determine if a year the user enters is a leap year.Pause to Reflect

4.25 Determine the day of the week of any date (month, day, year) the user enters.

4.26 Determine the day of the week your birthday falls on in the year 2002.

June 7, 1999 10:10 owltex Sheet number 62 Page number 144magentablack

144 Chapter 4 Control, Functions, and Classes

O U T P U T

prompt> datedemoenter month (1-12) and year 9 1999that day is September 1 1999, it is a Wednesdaythe month has 30 days in itprompt> datedemoenter month (1-12) and year 2 2000that day is February 1 2000, it is a Tuesdaythe month has 29 days in it

4.7 Using Boolean Operators: De Morgan’sLaw

Many people new to the study of programming have trouble developing correct expres-sions used for the guard of anif statement. For example, suppose you need to print anerror message if the value of anint variable is either 7 or 11.

if (value == 7 || value == 11){ cout << "**error** illegal value: " << value << endl;}

The statement above prints an error message for the illegal values of 7 and 11 only andnot for other, presumably legal, values. On the other hand, suppose you need to print anerror message if the value is anything other than 7 or 11 (i.e., 7 and 11 are the only legalvalues). What do you do then? Some beginning programmers recognize the similaritybetween this and the previous problem and write code like the following.

if (value == 7 || value == 11){ // do nothing, value ok}else{ cout << "**error** illegal value: " << value << endl;}

This code works correctly, but the empty block guarded by theif statement is not thebest programming style. One simple way to avoid the empty block is to use the logicalnegation operator. In the code below the operator! negates the expression that followsso that an error message is printed when the value is anything other than 7 or 11.

if ( ! (value == 7 || value == 11) ){ cout << "**error** illegal value: " << value << endl;}

June 7, 1999 10:10 owltex Sheet number 63 Page number 145magentablack

4.7 Using Boolean Operators: De Morgan’s Law 145

Table 4.7 De Morgan’s Laws for logical operators

expression logical equivalent by De Morgan’s law

! (a && b) (!a) || (!b)! (a || b) (!a) && (!b)

Alternatively, we can use De Morgan’s law12 to find the logical negation, or opposite,of an expression formed with the logical operators&& and || . De Morgan’s laws aresummarized in Table 4.7.

The negation of an&& expression is an|| expression, and vice versa. We can useDe Morgan’s law to develop an expression for printing an error message for any valueother than 7 or 11 by using the logical equivalent of the guard in theif statement above.

if ( (value != 7 && (value != 11) ){ cout << "**error** illegal value: " << value << endl;}

De Morgan’s law can be used to reason effectively about guards when you read code.For example, if the code below prints an error message for illegal values, what are thelegal values?

if (s != "rock" && s != "paper" && s != "scissors"){ cout << "** error** illegal value: " << s << endl;}

By applying De Morgan’s law twice, we find the logical negation of the guard whichtells us the legal values (what would be an else block in the statement above.)

if (s == "rock" || s == "paper" || s == "scissors") //legal

This shows the legal values are “rock” or “paper” or “scissors” and all other stringsrepresent illegal values.

12Augustus De Morgan (1806–1871), first professor of mathematics at University College, London, aswell as teacher to Ada Lovelace (see Section 2.5.2.)

June 7, 1999 10:10 owltex Sheet number 64 Page number 146magentablack

146 Chapter 4 Control, Functions, and Classes

Richard Stallman (b. 1953)

Richard Stallman is hailed by many as “the world’s best programmer.” Before theterm hacker became a pejorative, he used it to describe himself as “someone

fascinated with howthings work, [whowould see a broken ma-chine and try to fix it].”

Stallman believesthat software shouldbe free, that moneyshould be made byadapting software andexplaining it, but notby writing it. Of soft-ware he says, “I’m go-ing to make it free evenif I have to write it all

myself.” Stallman uses the analogy that for software he means “free as in freespeech, not as in free beer.” He is the founder of the GNU software project, whichcreates and distributes free software tools. The GNUg++ compiler, used to de-velop the code in this book, is widely regarded as one of the best compilers in theworld. The free operating systemGnu/Linux has become one of the most widelyused operating systems in the world. In 1990 Stallman received a MacArthur “ge-nius” award of $240,000 for his dedication and work. He continues this worktoday as part of the League for Programming Freedom, an organization that fightsagainst software patents (among other things). In an interview after receiving theMacArthur award, Stallman had a few things to say about programming freedom:

I disapprove of the obsession with profit that tempts people to throw awaytheir ideas of good citizenship.…businesspeople design software and maketheir profit by obstructing others’ understanding. I made a decision not todo that. Everything I do, people are free to share. The only thing that makesdeveloping a program worthwhile is the good it does.

4.8 Chapter Review

In this chapter we discussed using and building functions. Changing the flow of controlwithin functions is important in constructing programs. Encapsulating information infunctions that return values is an important abstraction technique and a key concept inbuilding large programs.

The if/else statement can be used to alter the flow of control in a program.

June 7, 1999 10:10 owltex Sheet number 65 Page number 147magentablack

4.8 Chapter Review 147

You can write programs that respond differently to different inputs by usingif/elsestatements. The test in anif statement uses relational operators to yield a booleanvalue whose truth determines what statements are executed. In addition to relationaloperators, logical (boolean), arithmetic, and assignment operators were discussed andused in several different ways.

The following C++ and general programming features were covered in this chapter:

The if/else statement is used for conditional execution of code. Cascadedifstatements are formatted according to a convention that makes them more readable.

A function’s return type is the type of value returned by the function. For example,the functionsqrt returns adouble . Functions can return values of any type.

The library whose interface is specified in<cmath> supplies many useful math-ematical functions.

Boolean expressions and tests have values of true or false and are used as the teststhat guard the body of code inif/else statements. The typebool is a built-intype in C++ with values oftrue andfalse .

A block (compound) statement is surrounded by{ and} delimiters and is used togroup several statements together.

Relational operators are used to compare values. For example,3 < 4 is a rela-tional expression using the< operator. Relational operators include==, != , <, >,<=, >=. Relational expressions have boolean values.

Logical operators are used to combine boolean expressions. The logical operatorsare || , &&, ! . Both || and && (logical or and logical and, respectively) areevaluated usingshort-circuit evaluation.

Boolean operators in C++ use short-circuit evaluation so that only as much ofan expression is evaluated from left-to-right as needed to determine whether theexpression is true (or false).

Defensive programming is a style of programming in which care is taken to preventerrors from occurring rather than trying to clean up when they do occur.

Pre- and postconditions are a method of commenting functions; if the preconditionsare true when a function is called, the postconditions will be true when the functionhas finished executing. These provide a kind of contractual arrangement betweena function and the caller of a function.

Severalmember functions of the string class can be used to determine thelength of a string and to find substrings of a given string. Non-member functionsare calledfree functions.Functions encapsulate abstractions like when a leap year occurs and in calculatinga square root. Functions should be used with regularity in programs.

Classes encapsulate related functions together. The classstring encapsulatesfunctions related to manipulating strings and the classDate encapsulates functionsrelated to calendar dates.

De Morgan’s laws are useful in developing boolean expressions for use inifstatements, and in reasoning about complex boolean expressions.

June 7, 1999 10:10 owltex Sheet number 66 Page number 148magentablack

148 Chapter 4 Control, Functions, and Classes

4.9 Exercises

4.1 Write a program that prompts the user for a person’s first and last names (be careful;more than onecin >> statement may be necessary). The program should print amessage that corresponds to the user’s names. The program should recognize at leastfour different names. For example:

O U T P U T

enter your first name> Owenenter your last name> AstrachanHi Owen, your last name is interesting.enter your first name> Daveenter your last name> ReedHi Dave, your last name rhymes with thneed.

4.2 Write a function whose specification is

string IntToRoman(int num)// precondition: 0 <= num <= 10// postcondition: returns Roman equivalent of num

so thatcout << IntToRoman(7) << endl; would cause"VII" to be printed.Note the precondition. Write a program to test that the function works.

4.3 Write a function with prototypeint Min2(int,int) that returns the minimumvalue of its parameters. Then use this function to write another function with prototypeint Min3(int,int,int) that returns the minimum of its three parameters.Min3can be written with a single line:

int Min3(int x, int y, int z)// post: returns minimum of x, y, and z{

return Min2( );}

where the two-parameter function is called with appropriate actual parameters. Write atest program to test both functions.You can then rewrite the minimum functions, naming them bothMin . In C++, func-tions can have the same name, if their parameters differ (this is another example ofoverloading).

4.4 Write a program in which the user is prompted for a real number (of typedouble )and a positive integer and that prints the double raised to the integer power. Use thefunctionpow from <cmath> . For example:

June 7, 1999 10:10 owltex Sheet number 67 Page number 149magentablack

4.9 Exercises 149

O U T P U T

enter real number 3.5enter positive power 53.5 raised to the powe r 5 = 525.218

4.5 Write a program that is similar tonumtoeng.cpp,Program 4.1, but that prints an Englishequivalent for any number less than one million. If you know a language other thanEnglish (e.g., French, Spanish, Arabic), use that language instead of English.

4.6 Use the functionsqrt from the math library13 to write a functionPrintRoots thatprints the roots of a quadratic equation whose coefficients are passed as parameters.

PrintRoots(1,-5,6);

might cause the following to be printed, but your output doesn’t have to look exactlylike this.

O U T P U T

roots of equation 1*xˆ2 - 5* x + 6 are 2.0 and 3.0

4.7 (from [Coo87]) The surface area of a person is given by the formula

7.184−3 × weight0.452× height0.725 (4.2)

where weight is in kilograms and height is in centimeters. Write a program that promptsfor height and weight and then prints the surface area of a person. Use the functionpowfrom <cmath> to raise a number to a power.

4.8 Write a program using the classDate that prints the day of the week on which yourbirthday occurs for the next seven years.

4.9 Write a program using ideas from the head-drawing programparts.cpp,Program 2.4,that could be used as a kind of police sketch program. A sample run could look like thefollowing.

13On some systems you may need to link the math library to get access to the square root function.

June 7, 1999 10:10 owltex Sheet number 68 Page number 150magentablack

150 Chapter 4 Control, Functions, and Classes

O U T P U T

prompt> sketchChoices of hair style follow

(1) parted(2) brush cut(3) balding

enter choice: 1Choices of eye style follow

(1) beady-eyed(2) wide-eyed(3) wears glasses

enter choice: 3Choices of mouth style follow

(1) smiling(2) straightfaced(3) surprised

enter choice: 3

||||||||////////| || --- --- ||---|o|--|o|---|| --- --- |

_| |_|_ _|

| o || |

4.10Write a function that allows the user to design different styles of T-shirts. You shouldallow choices for the neck style, the sleeve style, and the phrase or logo printed on theT-shirt. For example,

June 7, 1999 10:10 owltex Sheet number 69 Page number 151magentablack

4.9 Exercises 151

O U T P U T

prompt> teedesignChoices of neck style follow

(1) turtle neck(2) scoop neck (rounded)(3) vee neck

enter choice: 1Choices of sleeve style follow

(1) short(2) sleeveless(3) long

enter choice: 2Choices of logo follow

(1) logo once(2) logo three times(3) logo slanted

enter choice: 3+------+| |

------- ------/ \

/ \-- --

| || || |

-- --| F || O || O || || |

4.11 (from[KR96]) The wind chill temperature is given according to a somewhat complexformula derived empirically. The formula converts a temperature (in degrees Fahren-heit) and a wind speed to an equivalent temperature (eqt) as follows:

eqt=

temp if wind≤ 4a − (b + c ×√wind− d × wind)× (a − temp)/e if temp≤ 451.6 ∗ temp− 55.0 otherwise

(4.3)

June 7, 1999 10:10 owltex Sheet number 70 Page number 152magentablack

152 Chapter 4 Control, Functions, and Classes

Wherea = 91.4, b = 10.45, c = 6.69, d = 0.447, e = 22.0. Write a program thatprompts for a wind speed and a temperature and prints the corresponding wind chilltemperature. Use a functionWindChill with the following prototype:

double WindChill(double temperature, double windSpeed)// pre: temperature in degrees Fahrenheit// post: returns wind-chill index/// comparable temperature

4.12 (also from [KR96]) The U.S. CDC (Centers for Disease Control—this time, not ControlData Corporation) determine obesity according to a “body mass index,” computed by

index= weight in kilograms

(height in meters)2(4.4)

An index of 27.8 or greater for men or 27.3 or greater for nonpregnant women isconsidered obese. Write a program that prompts for height, weight, and sex and thatdetermines whether the user is obese. Write a function that returns the body mass indexgiven the height and weight in inches and pounds, respectively. Note that one meter is39.37 inches, one inch is 2.54 centimeters, one kilogram is 2.2 pounds, and one poundis 454 grams.

4.13Write a program that converts a string to its Pig-Latin equivalent. To convert a stringto Pig-Latin use the following algorithm:

1. If the string begins with a vowel, add"way" to the string. For example, Pig-Latinfor “apple” is “appleway.”

2. Otherwise, find the first occurrence of a vowel, move all the characters before thevowel to the end of the word, and add"ay" . For example, Pig-Latin for “strong”is “ongstray” since the characters “str” occur before the first vowel.

Assume that vowels are a, e, i, o, and u. You’ll find it useful to write several functions tohelp in converting a string to its Pig-Latin equivalent. You’ll need to use string memberfunctionssubstr , find , andlength . You’ll also need to concatenate strings using+. Finally, to find the first vowel, you may find it useful to write a function that returnsthe minimum of two values. You’ll need to be careful with the valuestring::nposreturned by the string member functionfind . Sample output for the program follows.

O U T P U T

prompt> pigifyenter string: strengthstrength = engthstrayprompt> pigifyenter string: alphaalpha = alphawayprompt> pigifyenter string: frzzlfrzzl = frzzlay