Vous êtes sur la page 1sur 21

Chapter 3

Function Basics

0. Introduction

This chapter shows how to use standard functions provided by the development system libraries, then shows the student how to write functions to take care of situations not covered by library functions. During this last task, the chapter shows how to use local variables and value parameters. Reference parameters are deferred to the next chapter. Finally, scope rules are treated. The idea of function is central to programming, whether Object Oriented Programming or Procedure Oriented Programming. If the paradigm is Procedure Oriented Programming, the algorithm at hand is decomposed into a hierarchical set of functions. If paradigm is Object Oriented Programming, the function members of the classes still must be coded. The material in this chapter will be familiar to anyone who has programmed in any other language. The differences between functions in C++ and other languages will be treated in Chapter 4.

1. Outline of topics in the chapter

3.1 Predefined Functions Predefined Functions That Return a Value Predefined void functions A Random Number Generator 3.2 Programmer-Defined Functions

Instructors Resource Manual for Savitch Absolute C++ 08/06/12 Chapter 3 Function Basics Defining Functions that Return a Value Alternate Form for Function Declaration Functions Calling Functions Functions that Return a Boolean Value Defining void Functions Return Statements in void Functions Preconditions and Postconditions main is a function Recursive Functions 3.3 Scope Rules Local Variables Procedural Abstraction Global Constants and Global Variables Blocks Nested Scopes Variables Declared in a for Loop

Page 2

2. General remarks on the chapter

In this chapter, the student begins to learn the tools that will be used to build the members of the classes, that is, the actions that the classes will take. This involves the tool of divide and conquer, or stepwise refinement. This tool involves, in its simplest form, determining subproblems of a nature that, once the subproblems are solved, all that remains of the original problem is fitting the solutions to the subproblems together. The top down design tool shows how to recognize subproblems and solve them in such a way that they fit together automatically, making the last step trivial.

Instructors Resource Manual for Savitch Absolute C++ 08/06/12 Chapter 3 Function Basics
Procedural Abstraction and Information Hiding

Page 3

David L. Parnas, circa 1972, introduced the notion of information hiding. In this chapter, we see information hiding in the notion of procedural abstraction. Procedural abstraction is probably the most important idea in this chapter. If the student does not internalize the notion that how a task is done should be hidden, with only what is done being revealed, that student, as a programmer, is crippled. Code written by such a programmer is likely to be difficult to read and unmaintainable.
Predefined Functions.

C++ requires that every object used in a program be declared prior to any use of the object. Hence, all functions must be declared prior to use. Predefined (library) functions are declared in standard header files. Use of predefined (library) functions requires inclusion of the header files that contain the declarations of these functions. Function declaration is the C++ name for what ANSI C calls 'prototype'. We will use the term function declaration, though there is much literature that refers to function declarations as prototypes.
Potential Problems with Header Files

It is important that the student understand that the #include commands are carried out by the preprocessor, a part of the C++ compiler that is not smart. The command #include <filename> expects the name of the file to contain exactly the characters between the < and the >, including any spaces. In this include statement, #include < iostream> the preprocessor thinks the file name begins with a space followed by the characters of the name iostream. The preprocessor does not find the header file (no header file has a name that starts with a space.) This another of the hard to find errors that look right. If you have used the .h header files in C or early C++, you will find that the older header files have been replaced. The files that did have a .h extension have been replaced by files

Instructors Resource Manual for Savitch Absolute C++ 08/06/12 Chapter 3 Function Basics

Page 4

with the name composed of the old name with the .h stripped off and prefixed by a c. For example, the math.h file has been replaced in C++ by cmath, and stdlib.h has been replaced by cstdlib. The files specific to C++ such as iostream.h and iomanip.h are now iostream and iomanip. The C++ Standard specifies that implementers should arrange for header files without the .h to put their names into namespace std and the header files without the .h should put their names into the global namespace. Some caveats: Not all implementations follow the standard in this respect. Not all implementations have the new files. Most implementations retain the older files (with the .h extension, names in the global namespace) to avoid breaking older software. I strongly recommend using the newer C++ features.
Some Possible Errors:

A type of problem my students have is computing an arithmetic average using integer division (which truncates). Student code typically does the integer division first, then casts the integer quotient to double.: double average; int sum, count; average = static_cast<double>(sum / count); instead of this double average; int sum, count; average = static_cast<double>(sum) / count; It is hard for the student programmer to see this error, as it looks right. Encourage the students to help debug each other's code. While there is the very real risk of the student copying code from one another, in my opinion, the enhancement to learning from the debugging effort is worth the risk. Another problem the student may encounter is writing a prototype with different return values but having the same signature such as: int avg(int s1, int s2, int s3, int s4); and double avg(int s1, int s2, int s3, int s4);

Instructors Resource Manual for Savitch Absolute C++ 08/06/12 Chapter 3 Function Basics conflict is between the return types: g++ Prb.cc In function `double avg(int, int, int, int)':

Page 5

The following error message from g++ is clearer than most compiler messages. The

38: conflicting types for `double avg(int, int, int, int)' 10: previous declaration as `int avg(int, int, int, int)' Compilation exited abnormally with code 1 Encourage the student to learn the messages your compilers give for the various kinds of errors.
Increment Operators and Order of Evaluation

Side effects can be evil, particularly when the same variable is affected by a side effect and the result depends on the order of evaluation. There are only three places in C++ (that I know of) where the order of evaluation is guaranteed, regardless of side effects. The arguments to the && operator, the || operator and the comma operator are guaranteed by the C++ Standard to be evaluated left to right. (But be careful. Your compiler may not comply with the standard in this regard.) The C++ Standard states that code written that depends on the order of evaluation of terms in an expression, or of function arguments, is incorrect. Most compilers do not catch this error. The code will work until you compile your code with another compiler that evaluates the expressions in a different order. Then you may find that the program gives different results than you expect. If you are fortunate, you will find this during testing. If not, a client who is using your code on the alternate platform will get bad answers. Example: //sideEffect.cpp #include <iostream> using namespace std; int main() { int x = 2, y;

y = ++x + (++x)*(++x); cout << " y " << y << endl;

Instructors Resource Manual for Savitch Absolute C++ 08/06/12 Chapter 3 Function Basics return 0; }

Page 6

When compiled with either the MS VC++ 6.0 or BCC 5.5 command line compiler, the output is 30. This is unreasonable. I do not know why, except that this is illegal code and the compiler is permitted to do literally anything the compiler author wishes.
Predefined void functions

From the outset it is important that the students understand several points about void functions. A void function does not return a value. While a return; statement is allowed, a return; statement is not necessary, and a return; statement cannot have an argument in void functions. The call to a void function is an executable statement. The result of a call to a void function may not be assigned to a variable. (Technically, a void function's value at execution is not an r-value.) Execution of a return; statement terminates the function, with control being returned to the caller. Finally, any code after a return statement is not executed. A call to a function with no arguments must have the parentheses following the function name, in contrast to Pascal, where the function name is sufficient. For details, read the sections 7.2 and 7.4 of Ellis and Stroustrup, The Annotated C++ Reference Manual, Addison Wesley, 1991, reprinted with corrections 1994, ISBN 0-201-5149-1, and sections 11.3.1-11.3.3 in Stroustrup, The design and Evolution of C++ Addison Wesley, 1994 reprinted with corrections, May 1994, or Stroustrup, The C++ Programming Language, 3rd edition Addison Wesley Longman, 1997.
Other Issues

ISO/ANSI C++ Language Standard uses the term "argument" to mean the object that appears in parentheses following the function name in a function call. The Standard uses the term "parameter" to mean the placeholder that appears in the declaration (prototype)

Instructors Resource Manual for Savitch Absolute C++ 08/06/12 Chapter 3 Function Basics

Page 7

and in the definition of a function. The text uses "formal parameter" where the Standard uses parameter and "argument" as the Standard does. The author's experience, and mine, is that students definitely do better when terminology is used consistently. We recommend that regardless of the usage the instructor chooses, that on tests and exams, instructors should be sure to make the usage clear by using "argument" AND whatever term they normally use. For example, "formal parameter (argument)" or "argument (formal parameter)" or something appropriate to your usage. It is our desire that the text and this IRM support the instructor, not to impose any particular terminology on the instructor. While formal parameter names are not necessary in the declaration, these names should be provided by any student writing at this level.
3. Solutions to, and remarks on, selected Programming Projects

1. Miles per gallon.

//1 liter = 0.264179 gallons //Input: Number of liters consumed and Number of miles traveled. //Output: Miles per gallon. Allow repeats //Do MPG in a function, use global const gallons/liter #include <iostream> using namespace std; const double GAL_PER_LITER = 0.264179;

// Input: liters consumed, miles traveled // Returns miles per gallon. // requires global constant GAL_PER_LITER double mpg(double miles, double liters); int main() { double liters; double miles;

Instructors Resource Manual for Savitch Absolute C++ 08/06/12 Chapter 3 Function Basics
char ans; do { cout << "Enter the number of liters used: "; cin >> liters; cout <<"Enter the number of miles driven: "; cin >> miles; cout << "Your vehicle gave you " << mpg(miles, liters) << " miles per gallon\n";

Page 8

cout << "Enter Y/y to do another calculation, anything else quits." << endl; cin >> ans; } while( ans == 'Y' || ans == 'y'); } double mpg(double m, double l) { //convert l liters to gallons double g = l * GAL_PER_LITER; return m/g; } A typical run is: Enter the number of liters used: 39 Enter the number of miles driven: 310 Your vehicle gave you 30.0884 miles per gallon Enter Y/y to do another calculation, anything else quits. y Enter the number of liters used: 25 Enter the number of miles driven: 210 Your vehicle gave you 31.7966 miles per gallon Enter Y/y to do another calculation, anything else quits. n

2. Inflation Rate.
//Input: price of an item (hot dog or diamond) 1yr ago and today //Output: estimate of inflation = (newPrice - oldPrice)/oldPrice //Use a function to compute inflation rate. Output inflation as //double in form of a percentage, as in 6.7 for 6.7% //Repeat ad libitum

Instructors Resource Manual for Savitch Absolute C++ 08/06/12 Chapter 3 Function Basics
#include <iostream> using namespace std;

Page 9

//Pre: Prices in dollar amounts //Post: Output inflation as double in form of a // percentage, as in 6.7 for 6.7%

double inflation(double oldCost, double newCost);

int main() { double oldPrice; double newPrice; char ans;

cout.setf(ios::showpoint); cout.setf(ios::fixed); cout.precision(1); //one decimal place is enough

do { cout << "Enter price from a year ago of the item in dollars.\n"; cin >> oldPrice; cout << "Old Price is " << oldPrice << endl; cout << "Enter current price of the item in dollars.\n"; cin >> newPrice; cout << "New Price is " << newPrice << endl << endl; cout << "Your prices indicate an inflation rate of " << inflation(oldPrice, newPrice) << " percent.\n"; cout << "Another calculate again? Y/y repeats, other quits.\n"; cin >> ans; cout << "You answered " << ans << endl << endl; } while(ans == 'y' || ans == 'Y'); return 0; }

double inflation(double oldCost, double newCost) {

Instructors Resource Manual for Savitch Absolute C++ 08/06/12 Chapter 3 Function Basics
return 100.0 * (newCost - oldCost) / oldCost; } /*

Page 10

I tested this on the DOS command line with the following command, where the file, data is listed at the bottom of this comment. $ch2Prob2 < data

Output from a typical run is:

Enter price from a year ago of the item in dollars. Old Price is 100.0 Enter current price of the item in dollars. New Price is 107.8

Your prices indicate an inflation rate of 7.8 percent. Another calculate again? Y/y repeats, other quits. You answered y

Enter price from a year ago of the item in dollars. Old Price is 16200.0 Enter current price of the item in dollars. New Price is 18095.0

Your prices indicate an inflation rate of 11.7 percent. Another calculate again? Y/y repeats, other quits. You answered n

The data is: 100.00 107.80 y 16200 18095 n */

Instructors Resource Manual for Savitch Absolute C++ 08/06/12 Chapter 3 Function Basics
3. (Enhanced 2.) Inflation Rate.

Page 11

In addition the problem as stated in #2, this program should print out an estimates, based on the calculated inflation rate, of the price of the item one and two years hence. Define a second function that returns the estimate. Arguments should be the inflation rate, the current cost of the item, and the inflation rate.
//Input: price of an item (hot dog or diamond) 1yr ago and today //Output: estimate of inflation = (newPrice - oldPrice)/oldPrice //Estimate of inflated price one and two years hence. //Use a function to compute inflated price. Arguments are inflation rate //and current cost of the item. //Use a function to compute inflation rate. Output inflation rate //as double in form of a percentage, as in 6.7 for 6.7% //Repeat ad libitum

#include <iostream> using namespace std;

//Pre: Prices in dollar amounts //Post: Output inflation as double in form of a // percentage, as in 6.7 for 6.7%

double inflation(double oldCost, double newCost);

//Function to determine inflated cost //Pre: Price is in a dollar amount, inflation rate is a percent as //6.7 (per cent) for 0.067. //Post: Output is inflated price double inflatedPrice(double cost, double inflationRate, int years);

int main() { double oldPrice; double newPrice; char ans;

cout.setf(ios::showpoint); cout.setf(ios::fixed);

Instructors Resource Manual for Savitch Absolute C++ 08/06/12 Chapter 3 Function Basics
cout.precision(1); //one decimal place is enough

Page 12

do { cout << "Enter price from a year ago of the item in dollars.\n"; cin >> oldPrice; cout << "Old Price is " << oldPrice << endl; cout << "Enter current price of the item in dollars.\n"; cin >> newPrice; cout << "New Price is " << newPrice << endl << endl; double inflationRate = inflation(oldPrice, newPrice) ; cout << "Your prices indicate an inflation rate of " << inflationRate << " percent.\n"; cout << "Estimated price of item 1 year hence: " << inflatedPrice(newPrice, inflationRate, 1) << endl; cout << "Estimated price of item 2 years hence: " << inflatedPrice(newPrice, inflationRate, 2) << endl; cout << "Another calculate again? Y/y repeats, other quits.\n"; cin >> ans; cout << "You answered " << ans << endl << endl; } while(ans == 'y' || ans == 'Y'); return 0; }

double inflatedPrice(double cost, double inflationRate, int years) { return cost * (1 + years * inflationRate / 100); } double inflation(double oldCost, double newCost) { return 100.0 * (newCost - oldCost) / oldCost; }

I tested this on the DOS command line, where the file, data is listed at the bottom of this.
ch2Prob2 < data

Output from a typical run is:

Instructors Resource Manual for Savitch Absolute C++ 08/06/12 Chapter 3 Function Basics

Page 13

Enter price from a year ago of the item in dollars. Old Price is 100.0 Enter current price of the item in dollars. New Price is 107.8

Your prices indicate an inflation rate of 7.8 percent. Estimated price of item 1 year hence: 116.2 Estimated price of item 2 years hence: 124.6 Another calculate again? Y/y repeats, other quits. You answered y

Enter price from a year ago of the item in dollars. Old Price is 16200.0 Enter current price of the item in dollars. New Price is 18095.0

Your prices indicate an inflation rate of 11.7 percent. Estimated price of item 1 year hence: 20211.7 Estimated price of item 2 years hence: 22328.3 Another calculate again? Y/y repeats, other quits. You answered n The data is: 100.00 107.80 y 16200 18095 n

4. Gravitational Attraction

We do not provide a solution to this problem.

Instructors Resource Manual for Savitch Absolute C++ 08/06/12 Chapter 3 Function Basics
5. Clothes size calculation

Page 14

The biggest problem students have in this, as in many word problems, is determining the formulas from the problem statement. Given height, weight, age, compute clothes sizes:
hatSize = weight (lbs.) / height (in.) 2.9 jacketSize (chest size, in.) = height * weight / 288 +(1/8)(age-30)/10

Note carefully that the adjustment only occurs for complete 10 year interval after age 30, i.e., if age < 40, there is no adjustment!
40 <= age < 49 gets 1/8 in. adjustment, etc. waist (in.) = weight / 5.7 + (1/10) * (age - 28)/2 NB: adjustment only occurs for complete 2-year interval after 28 age = 29, no adjustment 30 <= age < 32, 1/10 inch adjustment.

Use a function for each calculation. Allow repetition at user option. Now let's make some declarations:
int height; // inches int weight; // lbs int age; // years

double jacketSize; // inches at chest double waist; // inches at waist double hatSize;

Hat Size Calculation: hat size = 2.9 * double(weight) / height;

The cast is clearer, but is not strictly necessary. The weight would be promoted automatically when multiplication by 2.9 occurs. (This is why the 2.9 is first!)
Jacket Size Calculation: jacket = double(height) * weight / 288

if (age > 40) jacket = jacket + (age - 30)/10 * 0.125;

Instructors Resource Manual for Savitch Absolute C++ 08/06/12 Chapter 3 Function Basics

Page 15

This depends on the behavior of the C/C++ language to obtain the results required. The (age-30/10) arithmetic will be done as int, since there is nothing to require type change. The int result will be then converted to double in the multiplication by the 0.125 (which is 1/8 as a decimal.)

Waist Size Calculation: size = weight/5.7; if (age>=30) size = size + (age - 28)/2 * 0.1;

Again, the weight will be converted to double in the division by 5.7. The expression, (age - 28)/2, will be computed as an int, then be promoted to double in the multiplication by 0.1.

//problem: Clothes size calculation: //given height (inches) weight (pounds) and age (years) //compute jacket size, waist size, in inches, and hat size: //returns hat size in standard hat size units

#include <iostream> using namespace std;

double hatSize (int height, int weight) { return 2.9 * double(weight) / height; }

//returns jacketSize in inches at the chest double jacketSize (int height, int weight, int age) { double jacket = double(height) * weight / 288; if (age > 40) jacket = jacket + (age - 30)/10 * 0.125; return jacket; }

Instructors Resource Manual for Savitch Absolute C++ 08/06/12 Chapter 3 Function Basics
// returns waist size in inches double waistSize (int height, int weight, int age) { double size = weight/5.7; if (age >= 30) size = size + (age - 28)/2 * 0.1; return size; }

Page 16

int main() { int height, weight, age; double hat, jacket, waist; char ans; do { cout << "Give me your height in inches, weight in " << "pounds, and age in years" << endl << "and I will give you your hat size, jacket " << " size(inches at chest)" << endl << "and your waist size in inches." << endl; cin >> height >> weight >> age; hat = hatSize (height, weight); jacket = jacketSize (height, weight, age); waist = waistSize (height, weight, age); cout.setf(ios::showpoint); cout.setf(ios::fixed); cout.precision(2); cout << "hat size = " << hat << endl; cout << "jacket size = " << jacket << endl; cout << "waist size = " << waist << endl; cout << endl << "enter Y or y to repeat, << any other character ends." << endl; cin >> ans; } while ('Y' == ans || 'y' == ans); return 0;

Instructors Resource Manual for Savitch Absolute C++ 08/06/12 Chapter 3 Function Basics
}

Page 17

A typical run follows:


Give me your height in inches, weight in pounds, and age in years and I will give you your hat size, jacket size (inches at chest) and your waist size in inches. 69 185 50 hat size = 7.78 jacket size = 44.57 waist size = 33.56 enter Y or y to repeat, any other character ends. y Give me your height in inches, weight in pounds, and age in years and I will give you your hat size, jacket size (inches at chest) and your waist size in inches. 67 200 58 hat size = 8.66 jacket size = 46.78 waist size = 36.59 enter Y or y to repeat, any other character ends. n 17:08:55:~/AW$

6. Average and standard deviation of scores

The problem as stated in the text requests a problem that is impossible to do within the elements of C++ available in the chapter. See the errata on the texts web site, URL: http://www.aw.com/savitch. Problem as stated in the text: Write a function that computes the average (technically, the arithmetic mean) and standard deviation of four scores, s1, s2, s3, and s4. The average is a = = s1 + s2 + s3 + s4; The standard deviation, stdDev1, is the square root of the average of the squares of the differences of the s values and the average, a.
1

These differences are often called the deviations from the mean, and the standard deviation is then the square root of the mean of the squares of the deviations from the mean:

Instructors Resource Manual for Savitch Absolute C++ 08/06/12 Chapter 3 Function Basics

Page 18

stdDev = sqrt((s1 a)2 *(s2 a)2 *(s3 a)2 *(s4 a)2 ); The function takes six parameters and calls two other functions to do the average and standard deviation of the scores. Discussion and Modified Problem: Such a problem requires call-by-reference parameters for the return values. We modify the problem by allowing the main function to call the average function and the standard deviation functions directly. These take four arguments and return their one value (average or standard deviation) as the function return value. Notice that the standard deviation function calls the average function twice, once to get the average, and once again to compute the average of the squared deviations of the data from the average. Solution:
#include <iostream> #include <cmath> using namespace std; //returns the arithmetic mean of the four arguments. double stdDev(double s1, double s2, double s3, double s4); //returns the standard deviation of the four arguments. double average(double s1, double s2, double s3, double s4);

int main() { double s1, s2, s3, s4; double stdDeviation, avg; char ans; do { cout << "Enter four values, separated by white space and" << "terminated with <CR> \n" << "I will compute the average and standard " << "deviation.\n"; cin >> s1 >> s2 >> s3 >> s4; avg = average(s1, s2, s3, s4); stdDeviation = stdDev(s1, s2, s3, s4);

Instructors Resource Manual for Savitch Absolute C++ 08/06/12 Chapter 3 Function Basics
cout << "The Average is: " << avg << endl; cout << "The Standard Deviation is: " << stdDeviation << endl; cout << "Y/y continues, any other quits.\n"; cin >> ans; } while(ans == 'y' || ans == 'Y');

Page 19

return 0; }

double {

stdDev(double s1, double s2, double s3, double s4)

double a = average(s1, s2, s3, s4); return sqrt(average((s1-a) * (s1-a), (s2-a) * (s2-a), (s3-a) * (s3-a), (s4-a) * (s4-a))); }

7. Wind chill index

The wind chill index is measure of the increase in chilling effect of low temperature with wind speed over the effect of the temperature alone. It is worth noting that wind chill only affects animals and people. The formula given in the text is both incorrect and out of date. See the errata on the texts web page. A corrected version is listed below. Meteorologists have developed a replacement formula that is (presumably) more accurate. We use the old (corrected) formula in one solution and the new formula in an alternate solution. In the following, we declare w, v, and t, and use these as follows: double w; // wind chill factor double v; // wind speed in meters/sec double t ; // temperature in degrees Celsius, t <= 10; The (incorrect) formula from the book is:

Instructors Resource Manual for Savitch Absolute C++ 08/06/12 Chapter 3 Function Basics The formula given in the text has been superceded by w = 13.12 + 0.6215 * t 11.37 * pow(v,0.16)

Page 20

w = 33 - (10 * sqrt(v) v + 10.5) * (33 t) / 23.1;

+ 0.3965 * t * pow(v,0.16); In our solutions, we will use a both a corrected old formula from the literature, and the new formula. The correct (old) formula (one that agrees with wind chill factor tables) is w = 0.045*(5.27*sqrt(v) + 10.45 0.28*v)*(t 33) + 33; This formula is available from many web sites, but this formula is taken from this URL home.vicnet.net.au/~bbcbush/feature.htm and from this URL www.msc-smc.ec.gc.ca/windchill/Science_equations_e.cfm The problem as presented in the text requires that we write a function that returns the wind chill index. We are told to enforce the temperature restriction and to look up weather reports and compare your result to the weather reports. (That is how I found that the formula is wrong.)
#include <iostream> #include <cmath> #include <cstdlib> using namespace std;

//Pre: t in degrees Celsius. Required t <= 10 //v wind speed in meters/sec //Post: returned value is the windChill index double windChill(double v, double t);

int main() { double t, v; char ans; do { cout << "Enter wind speed and Celsius temperature <= 10 degrees\n"; cin >> v;

Instructors Resource Manual for Savitch Absolute C++ 08/06/12 Chapter 3 Function Basics
cin >> t; cout << "Wind chill factor is " << windChill(v, t) << endl; cout << "Y/y continues, other quits\n"; cin >> ans; } while(ans == 'y' || ans == 'Y'); return 0; } double windChill(double v, double t) { double w; // wind chill factor if(t>10) { cout << "Quitting. windChill called with temperature > 10 " << "degrees\n"; exit(0); }

Page 21

w = 0.045 * (5.27 * sqrt(v) + 10.45 - 0.28 * v) * (t - 33) + 33; return w; }

The windChill function that uses the alternate formula follows. Note that I have omitted the restriction on wind speed, as the references do not require it.
//This requires the user include cmath for the pow function. double windChill(double v, double t) { double w; // wind chill factor

w = 13.12 + 0.6215 * t 11.37 * pow(v,0.16) + 0.3965 * t * pow(v,0.16);


return w; }

Though I have tested this solution, I do not provide run results for this problem.

Vous aimerez peut-être aussi