Introduction to Programmer-Defined Functions Creating Reusable Operations (§5.1 - §5.3) 1 Problem The playing field (actually called a "pitch") for Australian Rules Football field is an ellipse whose (ideal) dimensions are 165m x 135m. A team owner is planning to put artificial turf on the field and a running track around the outside and would like to know, therefore, the area and the circumference of the field. Our task: Write a program that computes the area and the circumference of the field. 2 Problem Generalization Generally, a program should solve a collection of problems rather than just one specific one. So we reformulate our task: Design a program that computes the area and circumference for any number of ellipses. area = pab b a Project 1.3 b a a2 + b2 circumference = 2p 2 3 Text: temperature conversion Algorithm 1. Display via cout the program information. 2. Loop: a. Display a prompt for the major and minor axes of an ellipse. b. Read majorAxis, minorAxis from cin. c. Compute semiMajor = majorAxis / 2.0 and semiMinor = minorAxis / 2.0. d. Compute area = PI * semiMajor * semiMinor. e. Compute circumference = 2.0 * PI * sqrt((semiMajor 2 + semiMinor 2) / 2.0). f. Display area and circumference with descriptive labels. End Loop 4 Coding PROGRAM DOCUMENTATION GOES HERE #include <iostream> #include <cmath> using namespace std; // cin, cout, <<, >>, ... // sqrt(), pow(), ... int main() { cout << "Program to compute the area and circumference of ellipses.\n"; const double PI = 3.14159; Ellipse Computations double majorAxis, minorAxis; cout << "\nEnter major & minor axes (in meters) (0 0 to stop): "; cin >> majorAxis >> minorAxis; while (majorAxis > 0) { double semiMajor = majorAxis/2.0, semiMinor = minorAxis/2.0; double area minorAxis); double area = = ellipseArea(majorAxis, PI * semiMajor * semiMinor ; double circumference = ellipseCircumference(majorAxis, minorAxis); 2.0 * PI * sqrt( (semiMajor * semiMajor + semiMinor * semiMinor) / 2.0); } } cout << "\nFor major axis " << majorAxis << " meters, minor axis " << minorAxis << " meters\n" << "\tarea = " << area << " sq. meters\n" << "\tcircumference = " << circumference << " meters\n"; cout << "\nEnter ellipse's major & minor axes (0 0 to stop): "; cin >> majorAxis >> minorAxis; 5 Note the while Encapsulate in funcs so can reuse Testing Program to compute the area and circumference of ellipses. Enter major & minor axes (in meters) (0 0 to stop): 2 2 For major axis 2 meters and minor axis 2 meters area = 3.14159 sq. meters circumference = 6.28318 meters Enter major & minor axes (in meters) (0 0 to stop): 8 6 For major axis 8 meters and minor axis 6 meters area = 37.6991 sq. meters circumference = 22.2144 meters Solve Problem Enter major & minor axes (in meters) (0 0 to stop): 165 135 For major axis 165 meters and minor axis 135 meters area = 17494.7 sq. meters circumference = 473.589 meters Enter major & minor axes (in meters) (0 0 to stop): 0 0 6 test: circle radius 1; 2nd: approx. 7pi ~ 22 Improving Reusability We’ve done a fair amount of work in creating these formulas, but we have no way to directly reuse our work if we ever need to use these ellipse-related formulas again. Solution: Rewrite those formulas as functions. Why use functions? • Improve code reusability • Implement new operations • Modularize complex programs large-scale reuse Put functions in a library 7 What's Necessary to Use a Function in a Program? • The function must have a name; we will use the same naming convention for functions as we do for variables. • Like mathematical functions, we must be able to pass values (called arguments) to the function. We do this using expressions of the form functionName(list-of-arguments) and we refer to this as calling the function. 8 User perspective: needs to know: name: sqrt, pow, floor # & types of args; what returns and type An Aside Why "call" a function? One reasonable explanation: In the 1960s when scientists at IBM were developing the Fortran programming language and using it to write programs for scientific problems, they often needed some mathematical function, e.g., a trig function such as sine. Since code for computing values of such functions (using infinite series) was nontrivial, a programmer would write it down and keep it in a notebook so he could look it up and copy it into a program when needed. If some other programmer needed one of these functions, she might remember that Joe had the code in his notebook, and she would call out, "Hey Joe, I need your sine function!" As this began to happen more and more frequently, creating more and more of a disturbance, these notebooks containing code for commonly used functions were placed in the company's library where programmers could get them and insert the code into their program. Today, we still use this language of calling functions, and (as we'll see later) we can put them in a library from where they can be automatically retrieved and included in a program. 9 • The function must have some way to receive the arguments passed to it. For this, the function uses a list of variables called parameters that will store these values. • The function must also be able to return a value that it computes. We can then use this value; for example, assign it to a variable: var = functionName(list-of-arguments); • In order to use this value returned by the function, we must know its type. So a function must also specify what type of value it returns. 10 Function perspective: params to receive values; return mechanism; specify return type; pow DIAGRAM Function Prototypes A declaration of a variable (or constant) gives it a name and specifies what it does (e.g., stores a double). A function must also be declared to name it and to specify what it does (but not how it does it): • What it receives • What it returns This is called the function's prototype. Note the semicolon! Pattern for a prototype: ReturnType name (parameter-declarations); void if nothing is returned A valid identifier May be empty 11 main() - empty; returns to OS;() indicate function - not variable; void: later return > 1 value A function's prototype must precede any call to that function by another function — by main(), in particular — (as well as any definition of that function), or a compiler error will occur. • Usually prototypes are put ahead of main(), after the #includes and using namespace std; This makes them available throughout the entire program. • Their order is irrelevant — it need not be the same as the order in which they called (or the order in which they will be defined). 12 like var - declare before use; Example: Ellipse Computations PROGRAM DOCUMENTATION GOES HERE #include <iostream> // cin, cout, <<, >>, ... #include <cmath> // sqrt(), pow(), ... prototypes using namespace std; double ellipseArea(double length, double width); double ellipseCircumference(double length, double width); int main() { cout << "Program to compute the area and circumference of ellipses.\n "; } double majorAxis, minorAxis; cout << "\nEnter major & minor axes (in meters) (0 0 to stop): "; cin >> majorAxis >> minorAxis; while (majorAxis > 0) { double area = ellipseArea(majorAxis, minorAxis); double circumference = ellipseCircumference(majorAxis, minorAxis); cout << "\nFor major axis " << majorAxis << " meters, minor axis " << minorAxis << " meters\n" << "\tarea = " << area << " sq. meters\n" << "\tcircumference = " << circumference << " meters\n"; cout << "\nEnter ellipse's major & minor axes (0 0 to stop): "; cin >> majorAxis >> minorAxis; } 13 #include <cmath> inserts prototypes of pow, etc. Can omit param names -- bad idea Once the prototypes are in place, a program that calls the functions can be compiled (but not linked yet). The compiler will only check that the functions are being used correctly: • Same number of arguments as parameters • Type of each argument and the type of the corresponding parameter are compatible • Return value of function is used correctly Argument names need not be different from the parameter names. For example, we could use: double ellipseArea(double majorAxis, double minorAxis); double ellipseCircumference(double majorAxis, double minorAxis); 14 Compiler only needs the "what", not "how" - proc. abstr. Linker needs 'how' where fun's code is to LINK a call to it. May not know param names -- e.g., pow Function Definitions Our program cannot be executed yet because prototypes only tell what functions do, not how they do it. If we attempt to build (compile & link) the program, we will get a linker error, because the linker’s job is to connect each function call with the code for that function’s definition. This means that we must provide definitions of the functions. Each one will contain statements that dictate the function’s behavior when it is called. ellipse0 15 ellipsedemo1 Pattern of function definition: Return type, name, and parameter types must match those in prototype. DOCUMENTATION returnType name(parameter-declarations) { Note: No statementList semicolon! } The documentation describes what the function does, what it receives, what it returns, and other information. These definitions can be added to the program after main()(but we will see later how to put them and their prototypes in separate files called a library). 16 param names need not match -- but usually do Copy prorotype and remove ; for heading // end of main() const double PI = 3.14159; /* Function to compute the area of an ellipse Receive: two double values length, width, representing the major axis and minor axis of an ellipse Return: the area of the ellipse ---------------------------------------------------------*/ double ellipseArea(double length, double width) { double halfLength = length/2.0, halfWidth = width/2.0; return PI * halfLength * halfWidth; } 17 /* Function to compute the circumference of an ellipse Receive: two double values length, width, representing the major axis and minor axis of an ellipse Return: the circumference of the ellipse ---------------------------------------------------------*/ double ellipseCircumference(double length, double width) { double halfLength = length/2.0, halfWidth = width/2.0; return 2.0 * PI * sqrt( (halfLength * halfLength + halfWidth * halfWidth) / 2.0); } • The order of the definitions is irrelevant; it need not match the order of the prototypes. ellipse1 See the start of program for Project 4 at the end of these slides for another example. 18 23 29 How Function Calls Work When a function is called, its caller can pass to it values called arguments. These values are copied and stored in the function's parameters. main() double area = ellipseArea(majorAxis, minorAxis); 165 135 165 135 double ellipseArea(double length, double width) { double halfLength = length/2.0, halfWidth = width/2.0; return PI * halfLength * halfWidth; } 19 Execution of the calling function (main()) is then suspended and the called function (ellipseArea()) begins execution using its parameter values. main() double area = ellipseArea(majorAxis, minorAxis); 165 135 165 135 double ellipseArea(double length, double width) { double halfLength = length/2.0, halfWidth = width/2.0; return PI * halfLength * halfWidth; } 20 The values of the local variables halfLength and halfWidth are calculated and then used in the expression that calculates the area. When the return statement is encountered: • The value computed by the called function is passed back to the caller (main()). main() double area = ellipseArea(majorAxis, minorAxis); 165 135 165 135 double ellipseArea(double length, double width) { double halfLength = length/2.0, halfWidth = width/2.0; return PI * halfLength * halfWidth; } 21 • Execution of the called function is terminated. • Execution of the caller (main()) resumes using the returned value to assign a value to area . main() double area = ellipseArea(majorAxis, minorAxis); double circumference = ellipseCircumference(majorAxis, minorAxis); 165 135 double ellipseArea(double length, double width) { double halfLength = length/2.0, halfWidth = width/2.0; return PI * halfLength * halfWidth; } When the next statement is encountered, execution proceeds in a similar manner with the function ellipseCircumference(). 22 29 Example of a void function: PROGRAM DOCUMENTATION GOES HERE #include <iostream> #include <cmath> using namespace std; Project 5 Use a void function to output results. // cin, cout, <<, >>, ... // sqrt(), pow(), ... double ellipseArea(double length, double width); double ellipseCircumference(double length, double width); void display(double length, double width double area, double circumference); int main() { cout << "Program to compute the area and circumference of ellipses.\n"; } double majorAxis, minorAxis; cout << "\nEnter major & minor axes (in meters) (0 0 to stop): "; cin >> majorAxis >> minorAxis; while (majorAxis > 0) { double area = ellipseArea(majorAxis, minorAxis); double circumference = ellipseCircumference(majorAxis, minorAxis) display(majorAxis, minorAxis, area, circumference); cout << "\nEnter ellipse's major & minor axes (0 0 to stop): "; cin >> majorAxis >> minorAxis; } 23 // DEFINITIONS OF ellipseArea() AND ellipseCircumference() // GO HERE OR AFTER DEFINITION OF display() /* Void function to output information about an ellipse. Receives: axes of ellipse (in meters), its area and circumference (in square meters) Returns: nothing Outputs: axes, area, and circumference with labels ----------------------------------------------------------*/ void display(double length, double width, double area, double circumference) { cout << "\nFor an ellipse with major axis "<< length << " meters and minor axis " << width << " meters:\n" << "\tarea = " << area << " sq. meters\n" << "\tcircumference = " << circumference << " meters\n"; } 19 24 Program Structure C++ programs typically follow this pattern: #include directives Function prototypes Main function Function definitions OCD with Functions 1. Specify the desired behavior of the program. 2. Identify the objects needed. 3. Identify the operations. a. If any operation is not predefined: Write a function to perform it. 4. Organize objects and operations into an algorithm. 25 #include <iostream> #include <cmath> using namespace std; // cin, cout, <<, >>, ... // sqrt(), pow(), ... double ellipseArea(double length, double width); double ellipseCircumference(double length, double width); void display(double length, double width double area, double circumference); int main() { cout << "Program to compute the area and circumference of ellipses.\n"; double majorAxis, minorAxis; cout << "\nEnter major & minor axes (in meters) (0 0 to stop): "; cin >> majorAxis >> minorAxis; while (majorAxis > 0) { double area = ellipseArea(majorAxis, minorAxis); double circumference = ellipseCircumference(majorAxis, minorAxis); display(majorAxis, minorAxis, area, circumference); cout << "\nEnter ellipse's major & minor axes (0 0 to stop): "; cin >> majorAxis >> minorAxis; } } 26 const double PI = 3.14159; /* Function to compute the area of an ellipse Receive: two double values length, width, representing the major axis and minor axis of an ellipse Return: the area of the ellipse ---------------------------------------------------------*/ double ellipseArea(double length, double width) { double halfLength = length/2.0, halfWidth = width/2.0; return PI * halfLength * halfWidth; } /* Function to compute the circumference of an ellipse Receive: two double values length, width, representing the major axis and minor axis of an ellipse Return: the circumference of the ellipse ---------------------------------------------------------*/ double ellipseCircumference(double length, double width) { double halfLength = length/2.0, halfWidth = width/2.0; } return 2.0 * PI * sqrt( (halfLength * halfLength + halfWidth * halfWidth) / 2.0); 27 /* Void function to output information about an ellipse. Receives: axes of ellipse (in meters), its area and circumference (in square meters) Returns: nothing Outputs: axes, area, and circumference with labels ----------------------------------------------------------*/ void display(double length, double width, double area, double circumference) { cout << "\nFor an ellipse with major axis "<< length << " meters and minor axis " << width << " meters:\n" << "\tarea = " << area << " sq. meters\n" << "\tcircumference = " << circumference << " meters\n"; } 28 /* This is a driver program to test the following triangle-processing functions: triangle() -- checks if 3 lengths can form a triangle ==> ADD NAMES & DESCRIPTIONS OF OTHER FUNCTIONS HERE Input: Three sides of a triangle Output: The boolean values returned by the functions ==> ADD YOUR NAME, DATE, COURSE & SECTION, PROJECT # HERE ------------------------------------------------------------*/ #include <iostream> using namespace std; // FUNCTION PROTOTYPES GO HERE bool triangle(double sideA, double sideB, double sideC); int main() { // ADD STATEMENTS TO OUTPUT PROGRAM INFO AND YOUR INFO HERE double side1, side2, side3; // possible sides of a triangle // LOOP cout << "Enter three legs of a triangle: "; cin >> side1 >> side2 >> side3; 29 cout << "Sides form a triangle --- " << boolalpha << triangle(side1, side2, side3) << endl; // STATEMENTS TO TEST OTHER FUNCTIONS GO HERE //END LOOP } // end of main() // FUNCTION DEFINITIONS GO HERE /* Function to determine if 3 lengths form a triangle Receive: three double values sideA, sideB, sideC, representing three sides of a triangle Return: true if triangle can be formed, false otherwise -----------------------------------------------------------*/ bool triangle(double sideA, double sideB, double sideC) { bool isaTriangle = (sideA + sideB) > sideC && (sideA + sideC) > sideB && (sideB + sideC) > sideA; return isaTriangle; } // ADD YOUR FUNCTION DEFINITIONS HERE 30 31