7: More About Functions

What We Will Cover


Continuations

Homework Questions?

Questions from last class?

Problem 1: What is output by the following program? (Do not run the code -- work it out by hand)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
using namespace std;

int mystery(int param);

int main() {
    int num = 2;

    cout << "At first, num=" << num << endl;
    int result = mystery(num);
    cout << "After calling, num=" << num << endl;
    cout << "And result=" << result << endl;

    return 0;
}

int mystery(int param) {
    cout << "param=" << param << endl;
    param = param * 2;
    return param;
}
  1. At first, num=2
    param=2
    After calling, num=4
    And result=4
    
  2. At first, num=2
    param=4
    After calling, num=4
    And result=4
    
  3. At first, num=2
    param=2
    After calling, num=2
    And result=4
    
  4. None of these

7.1: More About Functions

Learner Outcomes

At the end of the lesson the student will be able to:

  • Return a value from a function
  • Document functions
  • Trace the control-flow of function calls

7.1.1: Variable Scope and Global Constants

  • Variables and parameters declared in a function can only be used within that function
  • The area of code that a variable can operate within is known as it's scope

    Scope: the enclosing block within which a variable exists

  • Because of scope, we can use variables with the same name in different functions
  • For instance, the following program uses the variable area in both main() and circleArea()
  • Variables defined inside a function are known as local variables

    Local variable: a variable accessible only within a function or block

  • When the function finishes executing, local variables disappear
  • Trying to use a local variable outside a function causes a compile error

Program Using Local Variables and Global Constants

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
using namespace std;

const double PI = 3.14159265;

double circleArea(double radius) {
    double area = PI * radius * radius;
    return area;
}

int main() {
    cout << "Enter the radius of a circle: ";
    double radius = 0.0;
    cin >> radius;

    double area = circleArea(radius);
    cout << "The circle area is " << area << endl;

    return 0;
}

Global Variables and Constants

  • Notice the constant variable PI in the above example:
    const double PI = 3.14159265;
  • C++ lets you define variables and constants with global scope
  • Global variables and constants are declared outside of any function and can be accessed in any function
  • Because they have the same value everywhere, global constants are considered good programming practice

Programming Style: No Global Variables

  • Global variables are variables that are defined outside functions
  • They are declared just like a global constant but without the const keyword
  • Unlike global constants, global variables are considered poor programming practice
  • A global variable can be modified anywhere in your program, so it is hard to trace where it is changed
  • Global variables make programs more difficult to understand and maintain
  • Do not use global variables in your programs for this course
  • Instead, use function parameters and return statements to transfer data from one function to another

More Information

Check Yourself

  1. Blocks of code are set inside a set of __________
    1. Colons -- : :
    2. Curly brackets -- { }
    3. Parenthesis -- ( )
    4. Square brackets -- [ ]
  2. True or false: scope is the area, usually a block of code, within which a variable exists.
  3. A variable only accessible inside a function or block is called a(n) ________ variable.
  4. True or false: global constants are good programming practice whereas global variables are bad.

7.1.2: void Functions

  • Previously we looked at functions that returned one value
  • Functions returning a value use a return statement
    return result;
  • A function that returns no value is called a void function
  • In C++, void functions are defined like functions that return a value
  • However, the keyword void replaces the return type
  • For example, what do you notice that is different about the following?
    void showFToC(double fDegrees) {
        double cDegrees = 5.0 / 9 * (fDegrees - 32);
        cout << fDegrees
             << " degrees Fahrenheit is equivalent to "
             << cDegrees << " degrees Celsius." << endl;
        return;
    }
    
  • There are only two differences between definitions for void functions and other functions:
    • void return type
    • return statement is optional and does not specify a value if used
  • If no return type is specified, the function returns after executing the last statement
  • Here is an example program using the void function shown above

Example Program With a void Function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
using namespace std;

void showFToC(double fDegrees) {
    double cDegrees = 5.0 / 9 * (fDegrees - 32);
    cout << fDegrees
         << " degrees Fahrenheit is equivalent to "
         << cDegrees << " degrees Celsius." << endl;
    return;
}

int main() {
    double fTemperature;

    cout << "Enter a temperature in Fahrenheit: ";
    cin >> fTemperature;
    showFToC(fTemperature);

    return 0;
}

When to Write void Functions

  • When we use a non-void function, we are asking a question
  • The function returns a value in response to our question
    cout << sqrt(9.0);
    
  • When we use a void function, we are giving the computer a command
    showFToC(212);
  • We do not expect or receive an answer

Common Errors With void Functions

  • Note that we cannot call a void function from a cout statement
  • For example, the following causes a compile error:
    cout << showFToC(fTemperature); // NO!
  • The reason is that a void functions does not return a value and cout has nothing to print
  • Similarly, we cannot call a void function in an assignment statement:
    double temp = showFToC(fTemperature); // NO!
  • There is nothing to assign to the variable temp

Check Yourself

  1. True or false: return statements are optional for void functions, but not for non-void functions.
  2. We use a void function when we issue the computer a(n) ________ and do not need an answer.
  3. True or false: Assuming that printResults() is a void function, the following is not allowed because printResults() does not return a value.
    cout << printResults(32.5, 0.3); // not allowed
    

7.1.3: Functions Calling Functions

  • Functions may call other functions
  • Within the body of one function, we can call another function call
  • Functions can call other functions as often as needed
  • We are already doing this when main() calls a function
  • The following program writes the program status to the console as the program runs
  • Writing values like this is known as data logging
  • Using log statements is a good debugging technique

Example of Functions Calling Functions

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
using namespace std;

void log(string funName, double value) {
    cout << "In " << funName << " the value is ";
    cout << value << endl;
}

double square(double number) {
    log("square() before", number);
    double result = number * number;
    log("square() after", result);
    return result;
}

int main() {
    double number = 5;
    log("main() before", number);
    double result = square(5);
    log("main() after", result);

    return 0;
}

Check Yourself

  1. A function can call other functions ________.
    1. one time
    2. two times
    3. three times
    4. as many times as needed
  2. Computer data ________ is recording information about a program as it runs.

7.1.4: Function Prototypes

  • C++ allows you to declare functions without defining them
  • Function declarations (prototypes) have the function heading without the function body
  • The general syntax for declaring a function is:
    returnType functionName(parameter1, ..., parametern);
    
  • Where:
    • returnType: the type of the value returned
    • functionName: the name you make up for the function
    • parameterx: the input values, if any
  • As an example, we can declare a function to calculate the square of a number like this:
    double square(double number);
  • By declaring a function, the compiler can resolve a function call made inside main()
  • Thus, we can reorganize our programs to place function definitions after main()
  • For now the use of function prototypes is optional
  • However, there are times in C++ when you need to use function prototypes
  • Note that if you use function prototypes, you place the block comments before the prototypes and not the definitions
  • You can see this new function organization in the following example

Example Program with a Function Prototype

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
using namespace std;

// Returns the square of a number
double square(double number);

// Displays a message to the console
void log(string funName, double value);

int main() {
    double number = 5;
    log("main", number);
    double result = square(5);
    log("main", result);

    return 0;
}

double square(double number) {
    log("square", number);
    double result = number * number;
    log("square", result);
    return result;
}

void log(string funName, double value) {
    cout << "In " << funName << "() the value is ";
    cout << value << endl;
}

Check Yourself

  1. A function ________ is a declaration of a function before it is defined.
  2. True or false: one reason for function prototypes is to allow the programmer to write the function definition after the main() function.
  3. True or false: the main difference between a function prototype and a function definition is that the function body is missing in a function prototype.
  4. Of the following, ________ would be a valid function prototype.
    1. fun() { /* C++ statements */ }
    2. int fun;
    3. int fun() { /* C++ statements */ }
    4. int fun();

7.1.5: Programming Style Requirements for Functions

  • Let us look more closely at the layout of the function shown above
  • Note the placement of the curly braces
  • There are two common styles of curly brace placement for functions:
    1. Place the opening brace on the same line as the function heading:
      void myFunction() {
          // statements of the function
      }
      
    2. Place the opening brace under and lined up with the first letter of the return type:
      void myFunction()
      {
          // statements of the function
      }
      
  • You can use either style as long as you are consistent
  • Also notice the indentation of the statements inside the function
  • As before, you always indent 3-4 more spaces after an opening curly brace
  • After the closing curly brace, you no longer indent the extra 3-4 spaces
  • Indenting makes it easier to see the block of code

Naming Functions

  • When making up a name for a function, use verbs since functions perform an action
  • There are two common naming styles you may use:
    1. Start with a lower-case letter and use uppercase letters as separators. Do not use underbars ('_'):
      int myFunction()
    2. Use all lower case letters and use underbars ('_') as separators:
      int my_function()

Commenting Functions

  • For your homework, every function must have a block comment before the function declaration
  • Comments are for human readers, not compilers
  • There is no universal standard for comment layout, but we use a style commonly used with many programming languages:
    1. Block comments start with /** and ends with */
    2. The first line explains the idea of the function, not the implementation
    3. An @param entry explains each parameter
    4. An @return entry describes the return value
  • The following example has a fully commented function
  • Notice that the example does NOT include the program file block comment required for homework

Example Program with Fully Commented Function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
using namespace std;

/**
    Returns the square of a number

    @param number The number to square
    @return the square of number
*/
double square(double number);

/**
    Displays a message to the console

    @param funName The name of the function
    @param value The value to display
*/
void log(string funName, double value);

int main() {
    double number = 5;
    log("main", number);
    double result = square(5);
    log("main", result);

    return 0;
}

double square(double number) {
    log("square", number);
    double result = number * number;
    log("square", result);
    return result;
}

void log(string funName, double value) {
    cout << "In " << funName << "() the value is ";
    cout << value << endl;
}

Using Doxygen

  • The purpose of the comment layout is to produce hyperlinked web pages describing your program
  • The program we use to produce the web pages is called Doxygen
  • We can run Doxygen from TextPad in the classroom and CTC
  • You can install Doxygen at home by following my instructions
  • Running Doxygen produces a folder named "html"
  • Inside the folder, we open the index.html file in a Web browser

Further Information

Check Yourself

  1. Of the following, ________ is an acceptable curly-brace placement and statement indentation style for function definitions.
    1. int fun() { /* C++ statements */ }
    2. int fun()
      { /* C++ statements */ }
    3. int fun() {
      /* C++ statements */ }
    4. int fun()
      {
           /* C++ statements */
      }
  2. True or false: functions names should start with lower-case letters.
  3. True or false: comments should be placed before function prototypes instead of function definitions.
  4. By starting block comments with ________ instead of /*, you tell Doxygen to include your comments in the hyperlinked web page documentation it produces.
  5. True or false: the first line of a function block comment explains the idea of the function, not the implementation.
  6. For every function parameter, you include a(n) ________ tag in the function block comment.
  7. If the function returns a value, you include a(n) ________ tag in the function block comment.

7.1.6: Tracing Code

  • One critical programming skill is tracing program code, often statement by statement
  • In a sense, we have to "be the computer"

    Be the computer

  • To trace the code, we follow the flow of execution
  • Every program starts with the first line of the main() function and continues sequentially statement by statement from there
  • A function call transfers the flow to the first statement of the called function
  • When the function returns, the flow transfers back to the point from which the call was made
  • Thus, every time the flow of control reaches a function call, the program:
    1. Temporarily stops executing in the current function
    2. Jumps to the called function and executes the statements of that function
    3. Returns to the point in the code from which it jumped
  • Let us trace the flow in the following code by line number:

Example Program for Tracing the Flow

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
using namespace std;

// Returns the square of a number
double square(double number);

// Displays a message to the console
void log(string funName, double value);

int main() {
    double number = 5;
    log("main", number);
    double result = square(5);
    log("main", result);

    return 0;
}

double square(double number) {
    log("square", number);
    double result = number * number;
    log("square", result);
    return result;
}

void log(string funName, double value) {
    cout << "In " << funName << "() the value is ";
    cout << value << endl;
}

Exercise 7.1

In this exercise we trace the flow of control in a program where functions call other functions, both void and non-void functions.

Specifications

  1. Create a file named trace.txt.
  2. In the trace.txt file, list the line numbers of each statement of the program shown below in the order the lines are executed. For example, the following are the first few line numbers of the program flow (assuming main() starts on line 20):
    20, 21, 22, 36, 37, ...
    

    Do not bother to list blank lines or lines containing only the closing curly brace (}) of a function definition. For more information on tracing, see section 7.1.6: Tracing Code.

  3. Save the trace.txt file to submit to Blackboard as part of assignment 7.

Program to Trace

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
using namespace std;

/**
    Returns the square of a number

    @param number The number to square
    @return the square of number
*/
double square(double number);

/**
    Displays a message to the console

    @param funName The name of the function
    @param value The value to display
*/
void log(string funName, double value);

int main() {
    double number = 5;
    log("main", number);
    double result = square(5);
    log("main", result);

    return 0;
}

double square(double number) {
    log("square", number);
    double result = number * number;
    log("square", result);
    return result;
}

void log(string funName, double value) {
    cout << "In " << funName << "() the value is ";
    cout << value << endl;
}

As time permits, review the summary below and be prepared to answer the Check Yourself questions.

7.1.7: Summary

  • Scope is the term used to define where you can access a variable
  • A variable inside a pair of curly braces is local to that block of code
  • Blocks begin at an opening brace ({) and end at a closing brace (})
  • This includes functions and other statements that use curly braces
  • Thus, variables declared in one function are not available in any other function
  • When the function finishes executing, local variables disappear
  • Trying to use a local variable outside a function cause a compile error
  • Global variables are variables declared outside of any function
    • Do NOT use global variables in your programs for this course
  • Global constants, on the other hand, are the preferred way to declare constants
  • Recall that we define a function using the following syntax:
    returnType functionName(parameter1, ..., parametern) {
        statements
    }
    
  • If the function does not return a value, we use the return type: void
  • Otherwise, we specify the type of data we want to return
  • Note that functions can call other functions
  • This is not new since we have called other functions from main()
  • C++ allows you to declare functions without defining them
  • Function declarations (prototypes) have the function heading without the function body
  • The general syntax for declaring a function is:
    returnType functionName(parameter1, ..., parametern);
    
  • For example:
    double square(double number);
  • Prototypes end with a semicolon (;) rather than curly braces
  • By declaring prototypes before main() you can define the functions after main()
  • Functions have style requirements you must follow
  • For instance, you must have a block comment before the name

Check Yourself

Answer these questions to check your understanding. You can find more information by following the links after the question.

  1. What is meant by the term scope? (7.1.1)
  2. What is a block of code? (7.1.1)
  3. What is a global variable? (7.1.1)
  4. Why should you avoid using global variables in your programs? (7.1.1)
  5. What is a global constant? (7.1.1)
  6. Why might you want to use a global constant in your programs? (7.1.1)
  7. What makes a global constant acceptable whereas a global variable should be avoided? (7.1.1)
  8. When do you use the void return type in a function definition? (7.1.2)
  9. Are you required to have a return statement in a void function definition? (7.1.2)
  10. What effect would removing the return statement from the following function have on compiling or executing the program? (7.1.2)
    void showResults(double fDegrees, double cDegrees) {
        cout << fDegrees
             << " degrees Fahrenheit is equivalent to "
             << cDegrees << " degrees Celsius." << endl;
        return;
    }
    
  11. Assuming that showResults() is a void function, what is wrong with: (7.1.2)
    cout << showResults(32.5, 0.3); // not allowed
    
  12. How many times can functions call other functions? (7.1.3)
  13. What is the reason for using function prototypes? (7.1.4)
  14. How does a function prototype differ from a function definition? (7.1.4)
  15. What are the four pieces of a block comment for functions? (7.1.5)
  16. What is meant by the term, "tracing code"? (7.1.6)

7.2: Reference Parameters

Learner Outcomes

At the end of the lesson the student will be able to:

  • Explain the difference between call-by-value and call-by reference parameter passing
  • Return values from functions using call-by-reference

7.2.1: Value Parameters

  • There are two ways to pass arguments to parameters
  • All our functions so far have used value parameters
  • Value parameters are separate variables from the ones in main() (or another calling function)
  • Modification of value parameters does not affect the original value

How Value Parameters Work

  • During the function call, your program copies the argument value into the parameter variable
  • The scope of value parameters is the same as for a local variable
  • If modified, only the local copy changes
  • When the function returns, your program discards any value assigned to the parameter
  • The following example program uses value parameters
  • What does this program output?

Example of Value Parameters

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
using namespace std;

int mystery(int param);

int main() {
    int num = 2;

    cout << "At first, num=" << num << endl;
    int result = mystery(num);
    cout << "After calling, num=" << num << endl;
    cout << "And result=" << result << endl;

    return 0;
}

int mystery(int param) {
    cout << "param=" << param << endl;
    param = param * 2;
    return param;
}

7.2.2: Reference Parameters

  • C++ has another parameter-passing mechanism known as call-by-reference
  • A reference parameter does not create a new variable, but refers to an existing variable instead
  • Any change in a reference parameter is actually a change in the variable to which it refers
  • We create a reference parameter by using an ampersand (&) between the parameter's type and name
    parameterType& parameterName
    
  • The following program shows an example of reference parameters
  • What is different?
  • What does this program output?

Example of Reference Parameters

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
using namespace std;

int mystery(int& param);

int main() {
    int num = 2;

    cout << "At first, num=" << num << endl;
    int result = mystery(num);
    cout << "After calling, num=" << num << endl;
    cout << "And result=" << result << endl;

    return 0;
}

int mystery(int& param) {
    cout << "param=" << param << endl;
    param = param * 2;
    return param;
}

Call-By-Reference Details

  • What's really passed to the reference parameter?
  • A reference to the caller's original argument!
  • A reference is the memory address of a variable
  • Note that arguments for reference parameters must be variables and not constants

Check Yourself

  1. When an argument is passed to a value parameter the ________ of the variable is passed to the parameter.
  2. When an argument is passed to a reference parameter the ________ of the variable is passed to the parameter.
  3. True or false: when a variable is used as a call-by-value argument, the value of the variable is never changed by the function call.
  4. True or false: when a variable is used as a call-by-reference argument, the value of the variable is never changed by the function call.
  5. True or false: you cannot pass a literal value to a call-by-reference parameter.

7.2.3: Mixed Parameter Lists

  • Parameter lists can include both value and reference parameters
  • As usual, the order of arguments in the list is critical
  • The following is a function prototype with mixed parameter types:
    void mixedCall(int& par1, int par2, double& par3);
    
  • To call the function:
    int arg1 = 0, arg2 = 1;
    double arg3 = 2.2;
    mixedCall(arg1, arg2, arg3);
    
  • arg1 must be an integer type and is passed by reference
  • arg2 must be an integer type and is passed by value
  • arg3 must be a double type and is passed by reference

Check Yourself

  1. True or false: you can include both call-by-value and call-by-reference parameters in the same function definition.

7.2.4: When to Use Reference Parameters

  • Reference parameters are more efficient than value parameters because they do not make copies of the parameters:
    • A program simply passes the memory address to the function
    • No new memory space is allocated and deallocated
  • Therefore, function calls using reference parameters usually operate faster
  • However, reference parameters restrict the arguments you can use for your function
  • Specifically, you must use a variable argument and not a literal or constant value
  • Usually, the best practice is to pass an object by reference
  • For instance, a string variable is an object
  • Also, you should pass a primitive type by value unless a function needs to modify a parameter
  • The performance advantage of reference parameters for primitive types tends to be negligible
  • Thus, it is not worth restricting the call pattern of your function

Exercise 7.2

In this exercise we explore how call-by-reference parameters differ from call-by-value parameters.

Specifications

  1. Type the following program into a text editor and save it as swap.cpp:

    Program using pass by value

  2. Compile and run the starter program to make sure you entered it correctly. When you run the program, the output should look like this:
    Enter two integers: 1 2
    After calling function: 1 2
    

    Notice that num1 and num2 have the same values before and after calling the function swap(). Any value assigned to var1 and var2 have no effect on num1 and num2. For more information, see section: 7.2.1: Parameter Passing and Value Parameters.

  3. Change your program by adding the four ampersands (&) circled below:

    Program using pass by reference

    The ampersands tell C++ to use call-by-reference when passing parameter values. For more information, see section: 7.2.2: Using Reference Parameters.

  4. Compile and run the modified program to make sure you made the changes correctly. When you run the program, the output should look like this:
    Enter two integers: 1 2
    After calling function: 2 1
    

    Notice that num1 and num2 have different values before and after calling the function swap(). Any value assigned to var1 and var2 change num1 and num2 respectively. For more information, see section: 7.2.2: Using Reference Parameters.

  5. Submit your final program source code to Blackboard as part of assignment 7.

Check Yourself

As time permits, be prepared to answer these questions. You can find additional information by following the links after the question.

  1. When an argument is passed to a value parameter, what gets copied? (7.2.1)
  2. When an argument is passed to a reference parameter, what gets copied? (7.2.2)
  3. How do call-by-value and call-by reference differ? (7.2.1 and 7.2.2)
  4. Can you mix call-by-value and call-by-reference in the same parameter list? (7.2.3)
  5. When should you use reference parameters? (7.2.4)
  6. When should you use value parameters? (7.2.4)

7.2.5: Summary

  • There are two ways to pass arguments to parameters
  • Value parameters are separate variables from the ones in the calling function
  • Modification of value parameters does not affect the original value
  • C++ has another parameter-passing mechanism known as call-by-reference
  • A reference parameter does not create a new variable, but refers to an existing variable instead
  • Any change in a reference parameter is actually a change in the variable to which it refers
  • We create a reference parameter by using an ampersand '&' between the parameter's type and name
  • Arguments for reference parameters must be variables, not constants
  • We can mix value and reference parameters in a function, like:
    void mixedCall(int& par1, int par2, double& par3);
    
  • We typically use reference parameters when:
    • We pass an object to a function
    • We need to return more than one value

7.3: Designing with Functions

Learner Outcomes

At the end of the lesson the student will be able to:

  • Use stepwise refinement to create algorithms
  • Write functions following the black-box analogy

7.3.1: Stepwise Refinement

  • As programs get larger, they become harder to design
  • In this course, we are starting to develop more complex programs
  • If we look at a particular problem, it may seem impossible to solve because of the complexity
  • For example, the design of the following programs are not obvious:
    • A program to do your taxes
    • A program to write the numbers on a check as words (see textbook page 203)
    • A program to produce a barcode
    • A computer game version of a game like Nim
  • Before you start working on a program like these, you need a plan
  • We call this planning process the "Problem Solving Phase" (see lesson 1.3: Programming and Problem Solving)
  • The output of the problem solving phase is an algorithm, often written as psuedocode
  • One commonly used and powerful technique is called stepwise refinement (also called top-down design or functional decomposition )
  • Stepwise refinement starts with an understanding of the problem and task to perform (see lesson 1.3.3: Analyzing Problems)
  • When a task is complex or difficult, we break it down into simpler subtasks
  • We keep breaking down the subtasks until we are left with tasks we know how to solve
  • Here is a diagram of the process:

    task breakdown

  • In algorithmic form:
    1. From a high level view, list the steps for solve the problem
    2. For each step that is too complex to implement, break it down into subtasks
    3. Repeat step 2 until all tasks are simple enough to solve easily
    4. Review, simplify and test the design
  • The output of our analysis and design is an algorithm usually expressed as psuedocode
  • Psuedocode is a mixture of a high-level programming language (like C++) and natural language (like English)
  • As an example of how top-down design works, we will consider the complex problem of buying pizza

Check Yourself

  1. The two main phases of program development are the ________ phase followed by the implementation phase.
  2. Breaking down a large problem into smaller problems is known as ________, top-down design, or functional decomposition.
  3. You should stop decomposing a problem when ________.
    1. you are tired
    2. you know how to solve each task
    3. you are about three levels down from the top
    4. you feel ready to write some code
  4. ________ is an informal way of describing an algorithm.

7.3.2: Case Study: Buying Pizza

  • Let's apply stepwise refinement to a case study for buying pizza

    Adapted from: Problem Solving with C++, 6/e, Walter Savitch, Addison Wesley, ISBN 0-321-41269-9, pp.209-215

  • Often times the large "economy" size of a product is not always a better buy than the smaller size
  • This is sometimes true when buying pizza
  • Pizza sizes are given in diameters
  • However, the amount of pizza you get is really the area of the pizza
  • The problem is: which size of pizza gives the lowest cost per square inch?
  • We need to write a program that gives us the price per area of any two pizza sizes

Problem Analysis

Problem restatement: What is the best buy for a pizza, the large size or the small size?

  • To better understand the problem we are solving, we ask some questions:
  • What output do we want?
    • A decision on which size is the best buy
    • Based on the cost per square inch for each size of pizza
  • What data do we have to work with?
    • Diameter of two sizes of pizza
    • Cost of the same two sizes of pizza
  • What formulas do we need?
    • area = πr2
    • cost per inch = price / area
  • What if the cost per square inch is the same for both sizes?
    • The smaller size will be the better buy

7.3.3: Creating a Design

  • We use top-down design to list the initial steps or tasks
  • One such list of steps is:
    1. Get the size and cost of both pizzas
    2. Compute the price per inch for smaller pizza
    3. Compute the price per inch for larger pizza
    4. Determine which size is the better buy
    5. Output the size of the better buy
  • Is any step too complex to solve easily?
    • If so they we break the step down into subtasks
  • When the breakdown is complete, we look for ways to simplify the design
  • We notice that tasks 2 and 3 are the same:
    radius = diameter / 2
    area = PI * radius ^ 2
    pricePerSquareInch = price / area
    
  • Both of these tasks take the same type of input and return the same type of result
  • Whenever two or more subtasks make the same computation, you should make a function out of them

    Rule of thumb: If you reuse the same sequence of 3 or more statements in various parts of your program, you should write a function to perform the task.

  • For instance, we could make a function named calcUnitPrice()
  • When writing a function, you start with comments and the function prototype:
    /**
        Calculates the price per square inch of a pizza
    
        @param diameter The diameter of the pizza in inches.
        @param price The price of the pizza in dollars.
        @return The price per square inch of a pizza.
     */
    double calcUnitPrice(int diameter, double price);
    
  • Notice how our function is specified
  • A programmer knows what values can be sent to the function and what to expect back from the function without needing to see the function code
  • This is known as designing a function as a black box

7.3.4: Functions as Black Boxes

  • A key concept in designing functions is called the black-box analogy

    Black box: a technical term for an object viewed in terms of its input, output and function.

  • Here is a diagram of the concept:

    Black box

  • A black box is something that we know how to use but not how it operates
  • An example might be a cell phone or an iPod
  • These devices have controls that we know how to operate
  • However, we really do not know their internal workings

Designing Functions

  • A function should be designed like a black box
  • The function has a job to do
  • For our example: calculate the price per square inch of a pizza
  • A programmer using the function needs to know what the function's job is and how to use it
  • However, a programmer should not need to know how the function does its job
  • This is known as, "treating the function like a black box"
    • Calling something a black box is a figure of speech
    • It is intended to convey the image of a physical device that we know how to use but not details of how it operates
  • If a function is well designed, then a programmer can use it as if it were a black box
  • A programmer should not have to look at a function's statements to know what the function does
  • All a programmer needs to know is that if correct arguments are passed to the function then a correct value will come out of the black box

Function Comment Blocks

  • An important technique for providing information about a function is the function comment block
  • A function comment block is a description of:
    • What the function does
    • What each parameter is for
    • What the function returns
  • A function comment block should tell the programmer all the information needed to use the function
  • However, the function comment block should not describe how the function does its task
  • The format of the function comment block is shown in the How-To's for Documenting and Organizing C++ Code
  • Every function must have a comment block before the function declaration
  • The comments, along with the prototype, allow a programmer to use the function
  • With this information, there is no need to study the statements inside the function
  • This allows the programmer to keep fewer details in mind while solving a problem

7.3.5: Testing a Design

  • We now have the design for our program:
    1. Get the size and cost of both pizzas
    2. Compute the price per inch for smaller pizza
    3. Compute the price per inch for larger pizza
    4. Determine which size is the better buy
    5. Output the size of the better buy
    
    /**
        Calculates the price per square inch of a pizza
    
        @param diameter The diameter of the pizza in inches.
        @param price The price of the pizza in dollars.
        @return The price per square inch of a pizza.
     */
    double calcUnitPrice(int diameter, double price);
    radius = diameter / 2
    area = PI * radius ^ 2
    pricePerSquareInch = price / area
    
  • Before translating our design into code, we should test it or do a walkthrough (a.k.a. desktop testing)

    walkthrough a process of checking the algorithm step-by-step

  • For out walkthrough, we use example numbers to test our algorithm
  • If the walkthrough yields the correct result, we have confidence our algorithm is correct

7.3.6: Translating into C++

  • Whenever you write software, you should start with something that you know compiles and runs
  • To start translating our program into C++, we start with our template
1
2
3
4
5
6
7
8
#include <iostream>
using namespace std;

int main() {
    // Enter your code here

    return 0;
}
  • We save the file as pizza.cpp, and then compile and run it to make certain everything works so far
  • We add to the program a few lines at a time, and then compile and run the code to test it
  • If the code does not compile or run, you know where the problem exists
  • If we find an error, we correct it before continuing

Creating Stubs

  • When implementing your code incrementally, sometimes it makes sense to put all the functions in place
  • This lets you verify that the overall structure is correct
  • However, you do not want to actually write the statements for the function at this time
  • Instead, you can "stub out" the function definition and then compile and run the program to make sure everything still works

    Stub: a minimal set of code to act as a placeholder for a function

  • Function stubs are like an outline of a function but without the algorithm implemented
  • When a function must return a value, we return a "dummy" value
  • For example:
    double calcUnitPrice (int diameter, double price) {
        return 1; // dummy value
    }
    
  • Stubs allows us to design and code a high-level structure without worrying about the details

Coding calcUnitPrice

  • We translate our psuedocode into C++ and obtain the following:
    double calcUnitPrice(int diameter, double price) {
        const double PI = 3.14159623;
        double radius, area;
        radius = diameter / 2;
        area = PI * radius * radius;
        return (price / area);
    }
    
  • What do you notice about the code?
  • The following statement looks right but is a serious mistake
    radius = diameter / 2;
  • We want the radius to include the fractional part of the size
  • However, integer division truncates the remainder
  • How do we fix the problem?
    double calcUnitPrice(int diameter, double price) {
        const double PI = 3.14159623;
        double radius, area;
        radius = diameter / static_cast<double>(2);
        area = PI * radius * radius;
        return (price / area);
    }
    
  • Now radius will include fractional parts
    • This would work as well:
      radius = diameter / 2.0;
  • Here is a link to a completed program: pizza.cpp

Testing

  • Just because a program compiles and runs does not mean that it is correct
  • To verify that you program returns the correct answers, you should test it with known values and compare it with known results
  • You can get known values and results by using pencil and paper or a calculator
  • Once you have checked your program with a few known values, then you can have more confidence that it is correct

Check Yourself

  1. A function ________ is just enough code to allow the function to compile.
  2. True or false: we add function stubs to our code as a placeholder until we write the function body.
  3. True or false: one should compile and test code after every few lines are added so that one knows where the problem occurs.

7.3.7: Summary

  • Top-down design is a technique for creating algorithms
    • The ideas is to break down the tasks into subtasks
    • Then you break down each subtask into smaller subtasks as needed
    • Eventually, the tasks are so trivial that they are easy to code
  • We applied top-down design to the problem of buying the best size of a pizza
  • Along the way, we made sure to design our functions as black boxes
  • A black box refers to something that we know how to use, but not how it operates
  • A programmer who uses a function needs to know what the function does, not how it does it
  • You want to write functions so that the function declaration and block comments are all a programmer needs to use the function
  • We write functions for our code for these reasons:
    1. To organize our code into modules
    2. To reduce repeated code
    3. To allow for code reuse in another program

Check Yourself

  1. What are the two main phases of program development? (1.3.2)
  2. What is the output of the problem-solving phase? (1.3.2)
  3. What is the first step to take when solving a problem? (1.3.3)
  4. What is meant by the term top-down design? (7.3.1)
  5. When should you stop decomposing (breaking down) your design? (7.3.1)
  6. If you notice repeated code in your design or program, what should you do? (7.3.3)
  7. What does it mean to say that a programmer should be able to treat a function as a black box? (7.3.4)
  8. What is the purpose of the comment that accompanies a function declaration? (7.3.4)
  9. What is one way to test a design? (7.3.5)
  10. What is a function stub? (7.3.6)
  11. If a stub must return a value, what value should it return? (7.3.6)
  12. What is the purpose of testing code that compiles? (7.3.6)

Exercise 7.3

In this exercise we create a top-down design for the next assignment.

Specifications

  1. Start a file named design.txt.
  2. Look at the specifications for assignment 7 and analyze the problem including:
    • A problem restatement
    • A list of questions and answers
    Write your problem restatement and list of questions in your design.txt file.
  3. Once your understand the problem, create a top-down design in psuedocode by listing the tasks to perform in your design.txt document.
  4. Break down each complex task into easier subtasks and list steps for each subtask as needed.
  5. Submit your design.txt file to Blackboard as part of assignment 7.

7.4: Midterm Preparation

Learner Outcomes

At the end of the lesson the student will be able to:

  • Discuss how to prepare for the midterm exam
  • Describe how to take the midterm exam

7.4.1: About the Exam

  • I am using Blackboard to administer the test
  • Since there are more students than computers, we must take the exams in shifts
  • Shifts are determined by your last name and section as follows:
    Last Name Section Start Time
    A-J Day 2:30 PM
    K-Z Day 3:30 PM
    A-K Evening 6:00 PM
    L-Z Evening 8:00 PM
  • If you want to change shifts then make arrangements to switch with another student who is on the other shift
  • Note that the day class must show up for the exam on both class days of the week

Ground Rules

  • You must attend the exam or you will receive a score of zero (0)
    • Except by prior arrangement with the instructor
  • The exam is closed books and closed notes
    • However, you may have one 3" x 5" card of handwritten notes for the exam
  • You may have a sheet of blank scratch paper
  • You may use a classroom computer, but only to take the exam in Blackboard
  • You may NOT use the computer to compile or run programs
  • You may NOT use the computer to view documents on the Internet
  • You may NOT use a calculator or other electronic device
    • Thus, you may NOT use your own computer to take the exam
    • If you have a cell phone visible or in use during the exam, you will automatically fail
  • You may NOT communicate with anyone but the instructor during the exam

3"x5" Card Requirements

  • Put your name on your card
  • Maximum card (or paper) size is 3 inches by 5 inches
  • You may use both sides of the card
  • Notes must be handwritten and NOT photocopied
  • Notes cannot have any complete functions -- only code snippets
  • Any 3" x 5" cards violating these rules will be confiscated before the test
  • You must turn in your 3" x 5" card after the exam in any case

7.4.2: Test Preparation Self Assessment

Take two minutes to read the following questions and answer "yes" or "no" according to how you currently prepare for exams.

  1. Do you begin planning and studying for exams from the first week of the semester?

  2. Do you attend all classes and use effective note-taking strategies?

  3. Do you review your reading and lecture notes the day after and on a weekly basis?

  4. Do you analyze your homework, quizzes, and exams throughout the semester for pattern and error?

  5. Do you identify possible exam questions while reading and taking notes?

  6. Do you study with a partner or a group?

  7. Do you use your instructors' office hours to ask questions about material you don't understand?

  8. Do you use study strategies appropriate for the type of exam (like flashcards to memorize facts, completion of example problems to understand processes)?

  9. Do you use small portions of time for review rather than cramming?

  10. Do you learn course material in-depth enough that you could explain it to one of your classmates?

Discussions Questions

  • What are your practices when preparing for tests or exams?
  • How much time do you dedicate to preparation?
  • What are your successful strategies for exam preparation?

7.4.3: How to Study for the Exam

forked road
  • No one can ace a test without studying and understanding the material
  • To get an "A" you need to thoroughly prepare for the test well in advance
  • With the midterm approaching, you have a choice:
    • Study and do well, or
    • Not study and do less than your best
  • Victims are people who let their lives control them, like a pawn on a chessboard
  • Creators are people who controls their own life, like a person playing chess
  • You can take responsibility for studying and do well on a test
  • Or you can make excuses and do less than you are capable of on a test

Boosting Your Performance

Here are some steps you can take to improve your test results:

  1. Compile a list of topics you might be tested on.

    Look over your assignments, exercises, and lecture notes to determine what you covered. Write a list of topics from these sources.

  2. Make sure you understand all the topics on your list.

    Correct any mistakes you may have made in your assignments or exercises.

  3. Identify the most probable exam topics for thorough study.

    To do well, you need deep understanding of the test topics. Oftentimes, you can tell what is on a test simply by which topics the instructor spends the most time talking about.

  4. Create a list of test questions.

    Turn headings from the textbook and lecture notes into questions. Look at the section summaries in the lectures and read the Check Yourself questions.

  5. Study your questions over and over until you know them perfectly.

    Make flash cards with questions on one side and answers on the other. Carry the cards with you and review them when you have a few minutes available. Have other people ask you questions from your flash cards.

  6. Prepare your 3"x5" card of test notes.

    Since the instructor allows a 3"x5" card, make use of it. For the topics you had the most trouble with, write down a short note or summary. If the pressure of the test causes you to forget something, you can refer to your card.

More Information

Exercise 7.4

Use the next 10 minutes to complete the following.

  1. Join a group of 4-5 people and introduce yourself to each other.
  2. As a group, develop a list of topics for one of the lessons of the lecture notes
  3. Write your list of topics on the board.

As a homework, prepare a list of 5 questions on one of the topics. Post the questions you develop in the indicated Discussions area of Blackboard before the first test day. Your posts will be graded.

7.4.4: Another Review Technique

  • To help you study, you can use this review game: Greenfoot Jeopardy
  • Stay with your team from the last exercise
  • We will start the game without a timer and with the "cpp.txt" file

Game Rules

  • We will rotate the question selection so each team gets a chance to select a question
  • Within a team, the first to raise their hand gets to answer
  • Each team keeps track of their score
  • If the team member gets the question right, the team gets the points for the question
  • If the team member get the question wrong, the team subtracts the points

7.4.5: More Test Preparation

  • To help your understanding of how the midterm will operate, I am providing a practice exam in Blackboard
  • The questions are intended to help you get a "feel" for taking an exam in Blackboard
  • The questions are NOT intended to tell you everything that is on the exam
  • Suggestion: prepare first and then try the practice exam
  • This will give you a better understanding of how much more preparation you need

Exam Taking Tips

  • Save after every answer -- you can change your mind and choose another
  • If you get stuck on a question, make your best guess and return later
  • If you are equally uncertain between two choices, go with first impression
  • When writing code, do NOT add more than the problem asks for
  • You do not need to comment code for tests and exams
    • Unless specifically instructed to in the exam question
  • Use the full time available
    • Check your work if you finish early
  • Any questions?

Wrap Up

Due Next:
A6-Programs With Functions (3/22/12)
A7-Postal Bar Codes (4/5/12)
  • When class is over, please shut down your computer
  • You may complete unfinished exercises at the end of the class or at any time before the next class.
Home | Blackboard | Day Schedule | Eve Schedule
Syllabus | Help | FAQ's | HowTo's | Links
Last Updated: March 22 2012 @16:00:05