Welcome to Lesson 15!


Learning Objectives
By the end of today's class, you should know...
  • How do you write a simple function?
  • What are the different parts of the function signature and what is the purpose of each one?
    • name of function
    • return type
    • parameter list
  • How do you return a value from a function?
  • What is a local vs global variable?
  • How do you "call" a function?

Announcements

  • Midterm 2 next class
    • Through today's lesson on strings -- no functions!
    • Just like the previous midterm in format (12-15 multiple choice, short answer, T/F + one full program)
    • What to study:
      •  Your old quizzes
      • In-class review exercises
      • Programs you have written for homework
  • Practice quiz posted - use as a practice test for first part of your midterm
  • Assignment 15 due one week from today!
  • Lab 8 posted on CodeLab


Wrapping Up Strings

The Problem with Newlines

  • When you press the Enter key, a newline character ('\n') is inserted as part of the input
  • The newline character can cause problems when you mix cin >> with getline()
  • Recall that cin >> s1:
    1. Skips whitespace
    2. Reads non-whitespace characters into the variable
    3. Stops reading when whitespace is found
  • Since whitespace includes newline characters, using cin >> will leave a newline character in the input stream
  • However, getline() just stops reading when it first finds a newline character
  • This can lead to mysterious results in code like the following:
    cout << "Enter your age: ";
    int age;
    cin >> age;
    cout << "Enter your full name: ";
    string name;
    getline(cin, name);
    cout << "Your age: " << age << endl
         << "Your full name: " << name << endl; 
  • There are two options to resolve this problem:
  1. Use cin.ignore(); //ignore the '\n' in the input buffer
  2. Use cin >> ws; //clear whitespace from the input buffer

Example Using cin >> ws


#include <iostream>
using namespace std;

int main() {
    cout << "Enter your age: ";
    int age;
    cin >> age;
    cout << "Enter your full name: ";
    string name;
    //alternately call cin.ignore();
    cin >> ws; // clear whitespace from buffer getline(cin, name); cout << "Your age: " << age << endl << "Your full name: " << name << endl; }

Activity 15.1: Sentence Continued (10 pts)
  • Let's add to our program involving sentences from the last class. We will also calculate the number of letters in the sentence and take in a user guess for a number of letters.
  • At the end of the program, we will confirm whether their guess was correct or not.
  • Declare a new variable beneath the other two at the top of the program. This variable will be used to store our calculation for the number of letters. 
  • Also, add a variable to store the user input for their guess. 
  • The variable declaration section of your program should now look like this:
string sentence;
int numWords = 1;
int numLetters = 0;
int guess;
  • Now alter your first cout statement to reflect the additional uses of this program. Remove the original message in your cout statement and replace it with the one below:
Think of a sentence in your mind.
Later I will tell you how many words and letters are in your sentence.

  • Now, ask the user to enter a guess for how many letters are in the sentence. We want the user to guess without counting the number of letters.
Enter a guess for the number of letters in your sentence (don't count!): _
  • Store the user guess as the guess variable using cin.
  • Next, prompt the user to enter the sentence. Your prompt should remain the same from the last exercise and, as before, you should use getline() to store the user input as the sentence variable.
Please enter your sentence: _
  • Verify that your code inside main looks like identical to the code below:

  • Now, run your program. You should notice a problem.
  • How can we fix this problem?
  • Add a cin >> ws or cin.ignore() above your getline(cin, sentence);
cin >> ws; //or you can use cin.ignore()
getline(cin, sentence);
  • Compile and run your code again and verify that it is now working properly.
  • Now let's alter the code inside the for loop to calculate how many letters are in the sentence.
  • Since we don't want to count any blank spaces, we only want to increment the numLetters variable when we are NOT incrementing the numWords variable. 
  • Therefore, we need to add an else statement to our for loop. Make sure your if-else in the for loop looks like this:
if (sentence[i] == ' ') {
    numWords++;
} else {
    numLetters++;
}
  • Now, let's add another cout statement below the for loop to print out the number of letters in the sentence,
cout << "And, " << numLetters << " letters.\n";
  • Did our user guess the number of letters correctly? Now is the time to let him or her know. Add the following if-else block above the return 0; of main.
if (guess == numLetters) {
    cout << "You guessed right!\n";
} else {
    cout << "You guessed wrong!\n";
}
  • Run your program again and you should get the following output. Note: if you don't get the output below, compare your program to the final version at the end of this exercise. When you are finished, upload to Canvas:

  • Your final code should look identical to the following:


Introducing Functions

C++  comes with libraries of predefined functions

  • Example:  sqrt function returns, or computes, the square root of a number:
double the_root = sqrt(9.0);

 

  • The number, 9.0, is called the argument
  • the_root will contain 3.0

Function Calls

  • sqrt(9.0) is a "function call."
  • It invokes, or sets in action, the sqrt function
  • The argument (9), can also be a variable or an expression
  • A function call can be used like any expression:
double bonus =  sqrt(sales) / 10;

cout << "The side of a square with area " << area
         << “ is “
         << sqrt(area);


What functions have we seen so far in this class?

  • pow(base, exponent)
  • sqrt(number)
  • length()
  • substr(index, numChars)
  • getline(cin, stringVariable)
  • setprecision(n)
  • Any others?
  • What do they all have in common? Notice any similarities in their syntax?

Function Call Syntax

  • Function_name (Argument_List)
  • Argument_List is a comma separated list:  (Argument_1, Argument_2, … , Argument_Last)   

side = sqrt(area);
cout << "2.5 to the power 3.0 is "
         << pow(2.5, 3.0);

Libraries

  • Predefined functions are found in libraries
  • The library must be “included” in  a program to make the functions available
  • An include directive tells the compiler which library header file to include.
  • To include the math library containing sqrt():
        #include <cmath>
  • Newer standard libraries, such as cmath, also require the directive
using namespace std;

Other Pre-Defined Functions
  • abs(x)     ---  int value = abs(-8);
    • Returns absolute value of argument x
    • Return value is of type int
    • Argument is of type x
    • Found in the library cstdlib
  • fabs(x)     ---  double value = fabs(-8.0);
    • Returns the absolute value of argument x
    • Return value is of type double
    • Argument is of type double
    • Found in the library cmath

Writing Our Own Functions

Grouping Repeated Commands

  • Some of the main() functions in our programs have been getting lengthy and complicated
  • The biggest problem in developing software is managing the complexity of programs
  • We can improve our code by organizing it into smaller pieces known as functions
  • Functions are a key tool in creating easy-to-understand programs that can be changed easily

Video: Chris Bosh Explains Functions

  • After watching the video, what does it mean to write our own functions?

What is a Function?

  • As developers, we need to know how to write and call functions

    Function: a named block of statements that can receive input, perform an action, and optionally return a value

  • Functions are like little programs in our larger program
  • We give each little function commands we want executed
  • We call the function whenever we want the commands executed
  • When the function has finished running, program execution returns to the point just after the code that called the function

Example Application for a Function

  • As an example, recall our test code to validate user input:
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 main() {
    double input = 0.0;
    do {
        cout << "Enter a positive number: ";
        cin >> input;
        if (cin.fail()) {
            cout << "You must enter digits, not words\n";
            cin.clear();
            cin.ignore(1000, '\n');
            input = -1; // set loop test to fail
        } else if (input <= 0.0) {
            cout << "You must enter a positive number\n";
        }
    } while (input <= 0.0);
    cout << "You entered: " << input << endl;

    return 0;
}
  • What if we need to enter two validated numbers into a program?
  • We want to process the first number after input and then input the second number
  • Doing so, we would end up with code like this:
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
40
#include <iostream>
using namespace std;

int main() {
    double input = 0.0;
    do {
        cout << "Enter a positive number: ";
        cin >> input;
        if (cin.fail()) {
            cout << "You must enter digits, not words\n";
            cin.clear();
            cin.ignore(INT_MAX, '\n');
            input = -1; // set loop test to fail
        } else if (input <= 0.0) {
            cout << "You must enter a positive number\n";
        }
    } while (input <= 0.0);

    // Process the input
    cout << "You entered: " << input << endl;

    double input2 = 0.0;
    do {
        cout << "Enter a positive number: ";
        cin >> input2;
        if (cin.fail()) {
            cout << "You must enter digits, not words\n";
            cin.clear();
            cin.ignore(INT_MAX, '\n');
            input2 = -1; // set loop test to fail
        } else if (input <= 0.0) {
            cout << "You must enter a positive number\n";
        }
    } while (input <= 0.0);

    // Process the second input
    cout << "You entered: " << input2 << endl;

    return 0;
}
  • Our program would be easier to write if we could get the second input without repeating the code
  • With functions, we give the list of commands a name and then run the list by calling the name
  • Using functions we keep all the code in one place and avoid duplication
  • Avoiding duplication reduces the complexity of our code and makes it easier to understand and change

Programming Style: Avoid Duplicating Code

  • Duplicate code can lead to problems such as:
    • Long repeated sections that are more difficult to understand than shorter sequences
    • Repetition of largely identical code within which it is difficult to see the different purposes of each section
    • Update problems where we make changes in some sections but overlook making changes in other sections
  • If we find ourselves writing similar code of three or more lines multiple times, we should consider writing a function

Defining a Function

  • In this section we look at function definition syntax and examine a simple example function
  • After we understand the syntax we can write more complicated functions

Function Syntax

  • The general syntax for defining a function is:
    returnType functionName(parameter1, ..., parametern) {
        statements
    }
    
  • Where:
    • returnType: the data type of the value returned
    • functionName: the name you make up for the function
    • parameterx: the input values, if any
    • statements: the list of statements to execute when the function is called
  • Can you identify each of these syntax items in the function we have always used?
    int main() {
        // program statements go here
    }
    

Example Program with a Second Function

  • As an example, the following program has a simple function to add two numbers
  • Notice that the code has two functions: add() and main()
  • The second function is placed before main() so the compiler knows about the function
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
using namespace std;

int add(int a, int b) {
    int sum = a + b;
    return sum;
}

int main() {
    cout << "Enter two numbers to add: ";
    int num1, num2;
    cin >> num1 >> num2;
    int total = add(num1, num2);
    cout << "Sum=" << total << endl;

    return 0;
}

Function Name

  • Every function must have a name that identifies the function
  • Function names follow the same rules as variable names
  • Technically, we can use any valid identifier for a function name
  • However, we should use a name that suggests the action the function performs
  • In our example, add suggests that the function will return the sum of two numbers

Function Structure

  • The first line of a function is known as the function signature
    int add(int a, int b)
    
  • The curly braces {...} contain the function body
  • The function body is the list of statement the function executes when called
  • The function signature describes the name, inputs and output of a function
  • We will look at these features in more detail in the following sections

Parameters

  • When defining a function, it is worth thinking about what helpful action it will perform
  • We can make the function more useful if we give it parameters
  • The parameters for an add function would be the two numbers to sum
  • Read through the following code to identify how the code makes use of the parameters

Example Code with Function Parameters

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

int add(int a, int b) {
    int sum = a + b;
    return sum;
}

int main() {
    cout << "Enter two numbers to add: ";
    int num1, num2;
    cin >> num1 >> num2;
    int total = add(num1, num2);
    cout << "Sum=" << total << endl;

    return 0;
}

Parameter List

  • We must have parenthesis after a function name
  • Inside the parenthesis, we define a list of zero or more parameters
  • Parameters are the inputs to a function
  • In our example, we have two parameters inside the parenthesis
    int add(int a, int b)
    
  • Parameters are the declaration of a new variable, even though they are declared inside parenthesis
  • Each parameter must have both a type and a name, just like a regular variable
  • If we have more than one parameter, we separate them with commas
  • Any parameter that we declare must be given an argument when we call the function
  • In the following image, the value of arguments num1 and num2 are copied to the parameters a and b

Passing Arguments to Function Parameters


Arguments and Parameters

  • Depending on our background, we might use the term arguments or parameters for the values passed to functions
  • The terminology is not that important
  • However, the way I will use the terms is:
    • A function definition has parameters
      int add(int a, int b) { // a and b are parameters
          // ...
      }
      
    • A function call passes arguments
      add(num1, num2); // num1 and num2 are arguments
      
  • Arguments are values we pass into functions
  • When the argument drops into a function, it lands in a parameter
  • A parameter is just like other variables in the function
    • Except that a parameter gets initialized by an argument
  • The important part is:

    We must pass every function parameter an argument.

  • The arguments must be in the same order as the parameters
  • Also, the argument value must be compatible with the type of the parameter
  • For example, we cannot call add() with: add("Jennifer", "Parrish")



Returning a Value

  • The first word in the function signature is the return type
    int add(int a, int b)
    
  • The return type specifies the type of data the function outputs
  • In our example the return type is an int

Return Statement

  • Functions that return a value must execute a return statement
    return result;
    
  • For instance, our example function add() has a return statement
    int add(int a, int b) {
        int sum = a + b;
        return sum;
    }
    
  • Note that the type of the returned valued must be compatible with the function return type
  • The returned value is substituted for the function call in the calling code
    sum =>[replaces]=> add(num1, num2)
    
  • We must save the returned value if we want to process it later in the program
    int total = add(num1, num2);
    

Returning a Value from a Function


Returning an Expression

  • The value after the word return can be an expression
  • It does not have to be just the name of a variable
  • We could rewrite our return statement to the following:
    return a + b;
    

Multiple return Statments

  • We can have more than one return stattement in a function
  • The first return statement reached is the one executed
  • We might have multiple returns if we have if-statments with alternate actions, like:
    if (x > 400) {
        return 1;
    } else {
        return 0;
    }
    
  • We do not have alternate actions in our simple add function and so have only one return statement

Activity 15.2 Writing a Function (10 pts)

In this exercise we define our own function.

Specifications

  1. Copy the following program into Eclipse, save it as sub.cpp, and then compile and run the starter program to make sure you copied it correctly.
    #include <iostream>
    using namespace std;
    
    // Define function here
    
    int main() {
    
        return 0;
    }
    
  2. Write the signature for a function named sub that receives two int numbers and returns an int value, like we did for the add() function
    returnType sub(two_int_parameters)
    
  3. Add the curly braces for the function body: { }.
  4. Inside the function body, subtract the second parameter from the first and return the value, like we did for the add() function.
        int sum = a + b; // from add() function, CHANGE THIS!
        return sum;
    
  5. Compile and run your code. What do you see when you compile? (click here) Click to show answer
  6. Inside the main() function, enter these statements:
        cout << "Enter two numbers to subtract: ";
        int num1, num2;
        cin >> num1 >> num2;
        int diff = sub(num1, num2);
        cout << "Difference=" << diff << endl;
    

    The fourth line contains the function call.

  7. Compile and run your modified program and verify the output looks like:
    Enter two numbers to subtract: 3 1
    Difference=2
    
  8. Save your sub.cpp file and submit it to Canvas.

Completed Program

When finished, your application should look like the following.




Functions Continued

Variable and Parameter Scope

  • A variable declared inside a function can only be used within that function

    Local variable: a variable that can only be accessed within a function or block.

  • Parameters are a local variable and thus can only be used inside the function in which they are declared as well
  • As an example of a local variable, we declared sum inside the add() function:
    int sum = a + b;
    
  • In addition, we declared another variable named total inside main():
    int total = add(num1, num2);
    
  • These variables cannot be accessed outside the function they were declared within

Scope

  • The area of code that a variable can operate within is known as it's scope

    Scope: the enclosing area within which a variable exists

  • Because of scope, we can use variables with the same name in different functions
  • To send information to a function we must include a parameters:
    int add(int a, int b)
    
  • When the function call is made, we send the arguments to the parameters:
    add(num1, num2)
    
  • The values of num1 and num2 are copied to the parameter variables a and b

Example of Scope

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

#include <iostream>
using namespace std;

int add(int a, int b) {
    int sum = a + b;
    return sum;
}

int sub(int a, int b) {
    int sum = a - b; //okay to name this variable sum?
    return sum;
}

int main() { cout << "Enter two numbers to add and subtract: "; int num1, num2; cin >> num1 >> num2; int total = add(num1, num2);
    int diff = sub(num1, num2);
    cout << "Sum=" << total << " Difference=" << diff<< endl;
    //Why can't I do this?
//cout << sum << endl;
  return 0; }

Flow of Control for a Function Call

  • To use functions well, we must understand their flow of control
  • In our example, the program starts executing in the main() function
  • When our program gets to the following statement, it stops executing in main() and jumps to our function:
    int total = add(num1, num2);
    
  • The program executes the statements in the function and then returns to the statement from which it jumped
  • When the function returns, the returned value replaces the function call
  • After returning, the program completes processing the calling statement and then moves on to the next statement
  • In our example, the statement saves the returned value in the variable: total
  • 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

Function Call Flow

Order of statements executed

  1. Every program starts executing at the start of the function main().
  2. When reaching a function call, arguments are copied to the parameters.
  3. Function code executes until reaching a return statement.
  4. Return statement returns a value to the function call.
  5. Calling function continues after the function returns.


Activity 15.3: Tracing a Function Call (10 pts)

  1. List the line numbers of each statement of your program from your sub.cpp from the last activity in the order the lines are executed. For example, if main() starts on line 9, statements are executed as follows:
    9, 10, 11, 12, ...
    

    Note: Do not bother to list blank lines or lines containing only a curly brace (}).

  2. Submit the list of line numbers in the textbox provided on Canvas for this activity.


Some Style Requirements for Functions

  • Consider again our example function

#include <iostream>
using namespace std;

int add(int a, int b) {
    int sum = a + b;
    return sum;
}

int main() {
    cout << "Enter two numbers to add: ";
    int num1, num2;
    cin >> num1 >> num2;
    int total = add(num1, num2);
    cout << "Sum=" << total << endl;

    return 0;
}
  • 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:
      int myFunction() {
          // statements of the function
      }
      
    2. Place the opening brace under and lined up with the first letter of the return type:
      int myFunction()
      {
          // statements of the function
      }
      
  • We can use either style as long as we are consistent
  • Also notice the indentation of the statements inside the function
  • As before, we always indent 3-4 more spaces after an opening curly brace
  • After the closing curly brace, we no longer indent the extra 3-4 spaces
  • Indenting makes it easier to see the block of code
  • In addition, function names always start with a lower case letter like variables
  • We can tell the difference between function and variable name because functions have parenthesis


Activity 15.4: My Salary (10 pts)

  • Open up Eclipse and create a new project called Salary with a C++ file called salary.cpp.
  • Copy and paste the starter code below into the file.
  • NOTE: Do not change the starter code! All you need to do is add to it.
/*
* Name
* Section
*/

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

//write your functions here

int main() {
   
    int hours;
    double hourly_wage;
    double weekly_salary = 0;
    double monthly_salary = 0;
    double yearly_salary = 0;
   
    cout << "This program will calculate your weekly, monthly and yearly salary!\n";
    cout << "Please enter your hourly wage: ";
    cin >> hourly_wage;

    cout << "Please enter the number of hours you work each week: ";
    cin >> hours;

    //call functions below
   

    weekly_salary = //function call goes here
    monthly_salary = //function call goes here
    yearly_salary = //function call goes here
   
    cout << fixed << setprecision(2);

    cout << "You make $" << weekly_salary << " per week.\n";
    cout << "You make $" << monthly_salary << " per month.\n";
    cout << "You make $" << yearly_salary << " per year.\n";

}

  • Now write three functions as follows and place them above main:
    • weeklySalary()
Takes in an integer argument for the number of hours worked each week
Takes in a double argument for the hourly wage
Returns a double for the weekly salary
    • monthlySalary()
Takes in an integer argument for the number of hours worked each week
Takes in a double argument for the hourly wage
Returns a double for the monthly salary
    • yearlySalary()
Takes in an integer argument for the number of hours worked each week
Takes in a double argument for the hourly wage
Returns a double for the yearly salary
Assume that you work 50 weeks a year (2 weeks vacation)
  • Add a function call and store the result as the appropriate variable.
weekly_salary = //function call goes here
monthly_salary = //function call goes here
yearly_salary = //function call goes here
  • Now, run your code and verify that it prints the correct values for each salary type.
  • When you are finished, upload your file to Canvas.
  • Your output should look identical to the following (except user input will vary):




Wrap Up

  • With a partner, answer the questions from today's learning objectives


Upcoming Assignments
  • Assignment 15 due Monday at 9:20 on Canvas
  • Lab 8 due Friday at midnight
  • Midterm 2 next class