5: Loops and Functions

What We Will Cover


Continuations

Questions from last class?

Homework Questions?

Homework Discussion Questions (Thursday)

  1. What test conditions did you use to determine which shape to draw?
  2. Did anyone use pair programming?
  3. What are the 4 rules of pair programming?
  4. Did anyone try using loops to draw the shapes?
  5. Did anyone try using loops for input validation?

5.1: Counting Loops

Learner Outcomes

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

  • Design and implement counting loops
  • Design and implement loops that accumulate values
  • Translate these designs into C++ code

5.1.1: Using Loops to Count

  • Assume we want to write an application that writes a list of numbers
  • We want to start at the number 1 and let the user choose the ending number
  • Thus the program output will look something like:
    This program writes lists of numbers.
    Enter the maximum number: 5
    1
    2
    3
    4
    5
    
  • We cannot simply write five numbers with cout because the user chooses the maximum number
  • Since we understand our problem, our next step is to write our algorithm
  • We can create an algorithm for this task using two variables and a loop
  • When designing with a loop, we need to consider these things:
    1. Loop body -- which statements to repeat
    2. Loop test condition -- when to loop and when to stop
    3. Loop test update -- must change something to exit the loop
    4. Initialization code -- how to get started correctly
  • We start with the first task and design our loop body
  • To count using a loop we need to use a variable to keep track of the count
  • This variable is often called a counter or stepper
  • We decide to use a variable named counter and to increment the counter variable each time the loop repeats:
    write the counter
    increment the counter
    
  • Now we need to design the loop test condition
  • We need a test condition for ending our loop when the count reaches the maximum number
  • Working through our loop manually when the count is near maximum, we see that our condition could be:
    while counter <= maximum
  • Also, we consider the test update and decide that incrementing the counter does the job
  • Now we move to the last task and ask ourselves what value the counter variable must start with to print the first number correctly
  • We realize that we need to start the counter variable at 1 to get the first number correct:
    set count = 1
  • Putting the pieces together we have:
    set counter = 1
    while counter < 6
        print out the counter
        increment the counter
    
  • We test this algorithm manually and then translate it into C++ code

Example C++ Application That Counts to Five

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

int main() {
    int max = 0;
    cout << "This program writes lists of numbers.\n";
    cout << "Enter the maximum number: ";
    cin >> max;

    int counter = 1; // initialization code
    while (counter <= max) { //loop termination condition
        //loop body
        cout << counter << endl;
        counter = counter + 1; // adjust the counter
    }

    return 0;
}

5.1.2: for Statements

  • It turns out that counting is a very common use for loops
  • Loops that are controlled by a counter variable are called counter-controlled loops
  • A counter-controlled loop has the form:
    i = start;
    while (i < end) {
        ...
        i++;
    }
    
  • Where:
    • i: the name of a counter variable
    • start: the initial starting value
    • end: the final ending value
  • Because this loop is so common, there is a special form for it:
    for (i = start; i < end; i++) {
        ...
    }
    
  • The following example shows the same loop as before but using a for loop instead of a while loop

Counter-Controlled-Loop Example

counting loop

Execution Sequence

  • The execution sequence of a for loop is:
    1. When for statement reached -- initialization executes
    2. If the test condition evaluates to true:
      1. Execute statements in the body of the loop
      2. When the end of loop body is reached, execute the update statement
      3. Return to step 2
    3. Otherwise, the loop is finished so continue with statements after the loop
  • We will use counting loops in several ways in the following exercise

5.1.3: Understanding the for Loop

  • Take another look at the for loop example:

    counting loop

  • Notice the structure of the code for the looping application
  • First was the statement to correctly initialize the looping condition:
    int i = 1;
  • Then came the the test condition
    i <= max
  • The loop executes the body of the loop if and only if the condition evaluates to true
  • The final statement inside the for loop is the update statement
    i = i + 1
  • Following the for statement is the curly braces containing the statements to repeat
  • Note how the repeated code is indented inside the loop
  • This lets us see easily which code is repeated and which is not
  • Following is a diagram of the for loop operation followed by a description of each step

Diagram of for Loop Operation

for loop flow chart

Execution Steps

  1. When for loop is reached, execute the INITIALIZATION statement
  2. Check if CONDITION is true
    • if true then continue with Step 3
    • Otherwise, continue with Step 6
  3. Execute the block containing the statements to repeat (LOOP_BODY)
  4. When end of loop body is reached, execute the UPDATE statement
  5. Return to Step 2
  6. Loop is finished: continue with statements after the loop

Exercise 5.1

In this exercise we explore some uses of counter-controlled loops.

Background

Recall that a char data type is stored by the computer as a number using the ASCII code (ASCII Table). Since a char is stored as an int by the computer, C++ lets you cast an int to a char.

int count = 65;
cout << (char) count << endl;

Specifications

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

    counting loop

  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:
    This program uses a loop to count.
    Enter the maximum number: 5
    1
    2
    3
    4
    5
    

    Note that we are using a for loop to count and that the variable i is the counter variable. For more information, see section: 5.1.2: for Statements.

  3. For our next counting application we will create a list of numbers and their square. Replace the cout statement inside the curly braces of the for loop with the following code:
    cout << i << '\t' << i * i << endl;
    

    Notice that the '\t' is the escape sequence for a tab character. We use the tab character to keep the columns aligned. For more information on escape sequences, see section: 3.2.4: Output of Hard-to-Print Characters.

  4. Compile and run your modified program and make sure your output looks like:
    This program uses a loop to count.
    Enter the maximum number: 5
    1       1
    2       4
    3       9
    4       16
    5       25
    
  5. For our next counting application we will display a list of numbers and their ASCII character equivalent. Replace the cout statement inside the curly braces of the for loop with the following code:
    cout << i << '\t' << (char) i << endl;
    

    Recall that a char data type is stored by the computer as a number using the ASCII code (ASCII Table). Since a char is stored as an int by the computer, C++ lets you cast an int to a char. For more information on casting, see section: 4.1.6: Type Casting.

  6. Compile and run your modified program and make sure your output looks like:
    This program uses a loop to count.
    Enter the maximum number: 128
    (output not shown)
    65      A
    66      B
    67      C
    (more output not shown)
    

    Use a large number like 128 to view the ASCII characters. You may want to use some of these special characters in your project.

  7. For our next counting application we will display a bar chart. Replace the current for loop with the following code:
    cout << "\n" << max << ": ";
    for (int i = 1; i <= max; i = i + 1) {
        cout << '*';
    }
    cout << endl;
    

    Notice that we show a horizontal bar chart by simply counting the number of characters to display. For more information, see section: 5.1.3: Making Bar Graphs.

  8. Compile and run your modified program and make sure your output looks like:
    This program uses a loop to count.
    Enter the maximum number: 5
    
    5: *****
    
  9. For our next counting application we will sum the numbers from 1 to the maximum value. Replace the code after the cin statement with the following:
    int sum = 0;
    for (int i = 1; i <= max; i = i + 1) {
        cout << i << endl;
        sum = sum + i;
    }
    cout << "The sum of these numbers is: "
         << sum << endl;
    

    For this application we needed to use another variable to hold the values as we gather them. This is known as accumulating values. For more information, see section: 5.1.4: Accumulating Values.

  10. Compile and run your modified program and make sure your output looks like:
    This program uses a loop to count.
    Enter the maximum number: 5
    1
    2
    3
    4
    5
    The sum of these numbers is: 15
    
  11. Submit your final program source code to Blackboard as part of assignment 5.

Check Yourself

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

  1. What are the three parts of a loop you must always consider when designing a looping algorithm? (5.1.1)
  2. What makes a loop a counting loop? (5.1.2)
  3. What does the following code display: (5.1.2)
    for (counter = 5; counter > 0; counter = counter - 1) {
        cout << counter << endl;
    }
    
  4. What does the following code display: (5.1.2)
    for (counter = 0; counter < 0; counter++) {
        cout << counter << endl;
    }
    
  5. How do you code a loop to display horizontal bar graphs? (5.1.3)
  6. How do you code a loop to accumulate values? (5.1.4)

5.1.4: Making Bar Graphs

  • Lets use our counting loop to make a horizontal bar graph
  • Our task is:

    Write a program that asks a user for a number and then displays a horizontal bar graph using '*' characters. Use one '*' for each number.

  • For example:
    Enter a number and I will display a bar graph.
    Enter your number: 5
    
    Your graph:
    *****
    
  • Since we understand our problem, our next step is to write our algorithm
  • We start with getting the user input
    Prompt the user
    Get the number to graph
    
  • Now we need an algorithm to display the bar graph
  • Since we need to repeat stars ('*'), we realize that we need to use a loop
  • Also, in a flash of inspiration, we realize that this problem is like our previous counting loop
  • We start our loop design by considering these things:
    1. Loop body -- which statements to repeat
    2. Loop test condition -- when to loop and when to stop
    3. Loop test update -- must change something to exit the loop
    4. Initialization code -- how to get started correctly
  • First we decide what needs to be repeated during the loop
    print out a '*'
    
  • Then we realize we are going to output a specific number of stars
  • Thus we can use our standard counting loop:
    for (int i = 0; i < max number; i++)
    
  • We know that max number is the number entered by the user
  • Putting all the pieces together we have:
    Prompt the user
    Get the number of stars to graph
    set count = 0
    for (int i = 0; i < number of stars; i++)
        print out a '*'
    
  • We test this manually with a small number like 3 and then translate it into C++ code

Example C++ Application That Displays a Bar Chart

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

int main() {
    int number = 0;

    cout << "Enter a number and I will show its"
         << " bar graph.\nEnter your number: ";
    cin >> number;

    cout << "\nBar graph:\n";
    for (int i = 0; i < number; i++) {
        cout << '*';
    }
    cout << endl;

    return 0;
}

5.1.5: Accumulating Values

  • One common looping task is to input a list of numbers and calculate their sum
  • For example, given the task:

    Display the sum of the numbers from 1 through n, where n can be any positive number greater than 0.

  • We start analyzing the problem working out a problem manually:
    sum = 1 + 2 + 3 + 4 + 5 = 15
  • As we look at the problem, we notice that the difference from one number to the next is just 1
  • In a flash of inspiration, we realize that this problem is like our counting loop
  • We need to count the numbers from 1 to 5
  • However, instead of printing the numbers, we need to add them to some variable
  • Since we understand our problem, our next step is to write our algorithm
  • We start with getting the user input
    Prompt the user
    Get the number to sum to
    
  • We start our loop design by considering these things:
    1. Loop body -- which statements to repeat
    2. Loop test condition -- when to loop and when to stop
    3. Loop test update -- must change something to exit the loop
    4. Initialization code -- how to get started correctly
  • First we decide what needs to be repeated during the loop
    sum = sum + counter
    
  • We start with our standard counting loop:
    for (int i = 0; i < max number; i++)
    
  • We know that max number is the number entered by the user
  • However, we realize that adding 0 has no effect, thus we start at 1 instead
  • Also, we need to include our final number, so we change the test condition to <=
  • Putting all the pieces together we have:
    Prompt the user
    Get the max number
    set sum = 0
    for (int i = 1; i <= max number; i++)
        sum = sum + i
    
  • We test this manually and find we forgot to display the sum after the loop
  • Display the sum after the loop
  • We add the missing step and then translate the algorithm into C++ code

Example Application to Sum a Sequence of Numbers

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

int main() {
    cout << "Enter the number to sum to: ";
    int number = 0;
    cin >> number;
    int sum = 0;
    for (int i = 1; i <= number; i++) {
        sum = sum + i;
    }
    cout << "Total sum = " << sum << endl;

    return 0;
}

Calculating Products

5.1.6: More Loopy Errors

  • A common problem with counting loops is the off-by-one error
  • Often a less-than is confused with a less-than-or-equal-to
  • Another problem is starting the count at the wrong number
  • For example, to sum the numbers from 1 to 5, what is wrong with:
1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
using namespace std;

int main() {
    int sum = 0;
    for (int count = 0; count < 5; count++) {
        sum += count;
    }
    cout << sum << endl;

    return 0;
}

Tracing Variables

  • One good way to discover loopy errors is to display the variables that change inside the loop
  • Tracing variables means watching their values change as the program executes
  • You can insert temporary output statements in your program
  • cout << "count=" << count << ", sum=" << sum << endl;

5.1.7: Summary

  • One common use for loops is to count numbers
  • The for loop gives us a compact way to program counter-controlled loops
    for (i = start; i < end; i++) {
        ...
    }
    
  • Once you know that a program needs a loop, you need to consider these things:
    1. Loop body -- which statements to repeat
    2. Loop test condition -- when to loop and when to stop
    3. Loop test update -- must change something to exit the loop
    4. Initialization code -- how to get started correctly
  • The for loop lets you specify the last two items in the for statement
  • We saw several applications for loops that count in this section
    • Counting loops
    • Making bar graphs
    • Summing numbers

5.2: Predefined Functions

Objectives

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

  • Create code that calls predefined functions
  • Describe the flow of control of a function call
  • Write code that generates random numbers

5.2.1: About Functions

Function -- a subprogram (method, procedure or subroutine) that executes a block of code when called.

  • Most popular programs are large, containing thousands to millions of lines of code
  • When programs are this large, the best way to develop and maintain them is to construct them from smaller pieces or modules
  • In C++, these smaller pieces are called functions
  • Later on we will look at another way to create larger modules called Classes
  • You may have noticed that we have been using functions already
  • For instance, main() is a function that we use in every program
    1
    2
    3
    4
    5
    6
    7
    
    #include <iostream>
    using namespace std;
    
    int main() {
        cout << "Hello, World!\n";
        return 0;
    }
    
  • Function are often collected into libraries so they can be reused by many different programs
  • C++ comes with many common libraries such as <cmath> which contains functions like sqrt()
  • We have used many of these library functions and will use more as the course progresses
  • Functions such as these are known as predefined functions
  • A predefined functions is simply a function that someone else wrote
  • Our use of predefined functions shows one of the benefits of functions: reusable code
  • Later on we will learn to define our own functions so that we can create reusable code as well
  • For now, we are going to focus on how to use functions

5.2.2: Calling a Function

  • When a function is defined or included in a program, C++ ignores the statements at first
  • In order to run the statements, you must call the function
  • Function call: an instruction that passes control to a function; after completing the function, control returns to the next instruction in the calling function.
  • Calling a function is like a boss asking a worker to do something
  • The "boss" (calling function) asks the "worker" (called function) to complete a task

Flow of Control for a Function Call

  • To understand how a function works, you need to trace its flow of control
  • The programs we write in this course have a single flow of control
  • All the statements in our programs execute in sequence, which can be modified by conditional statements or loops
  • A function call is another way to change the flow of control
  • When we call the function, the caller function stops and waits for the called function to finish
  • You can see this flow in the following diagram:

    Function call flow of control

Arguments and Returned Values

  • When we call a function we can send the function data called arguments
  • For example, to calculate the square root of a number, we call the sqrt() function with a particular value:
    sqrt(9.0);
  • In this case the argument is the numerical value 9.0
  • When the called function finishes executing, it may return a value
  • In this case our function returns the value 3.0

Example Program with a Function Call

1
2
3
4
5
6
7
8
9
10
#include <cmath>
#include <iostream>
using namespace std;

int main() {
    double result = 1 + sqrt(9.0);
    cout << result << endl;

    return 0;
}

5.2.3: Generating Random Numbers

  • Random numbers are a series of numbers whose order cannot be predicted
  • The C++ library has a random number generator, which produces numbers that appear to be random
  • Many computational problems need to use random numbers
  • rand() is a library function that produces a series of psuedorandom numbers:
    • Range is 0 up to and including RAND_MAX
    • Returns an "random" int value
  • Random numbers actual come from a a very long sequence of numbers computed from fairly simple formulas; they just behave like random numbers
  • For that reason they are often called psuedorandom numbers
  • The following program uses rand to produce the same output every time it runs
  • The reason that the numbers are the same is because the numbers are generated with formulas

Example Program Using rand()

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

int main() {
    int i;
    for (i = 0; i < 10; i++) {
        int num = rand();
        cout << num << "\n";
    }

    return 0;
}

Another Random Number Generator

Random Number: a less useful random number generator

5.2.4: Seeding the Random Generator

  • When running programs we do not always want the same sequence of numbers every time
  • For instance, if we run a dice simulation for a game we want different numbers every time the program runs
  • To get a different number, we must seed the random number generator
  • We set the seed with the srand() function
  • If we change the seed value, we will get different numbers every time
  • One common strategy for changing the seed value is to use time
  • Since the time changes every second, we get a new random number sequence every time we run our program
  • To generate a number from time, we can use the Time class from the textbook:
    Time now;
    int seed = now.seconds_from(Time(0,0,0));
    srand(seed);
    
  • Another way is to use the time() function from the C time library:
    srand(time(0));
  • The expression time(0) returns the number of seconds since January 1, 1970

Exercise 5.2

In this exercise we look at how to call functions and learn how to generate random numbers.

Specifications

  1. Copy the following program into a text editor, save it as dice.cpp, and then compile the starter code to make sure you copied it correctly.
    #include <iostream>
    using namespace std;
    
    int main() {
        // Enter your code here
    
        return 0;
    }
    
  2. Random numbers are generated by using the rand() function. Declare two integer variables, die1 and die2, and assign them values returned by the rand() function using code like the following:
    int die1 = rand();
    int die2 = rand();
    cout << "You rolled a " << die1
         << " and a " << die2 << endl;
    

    For more information, see section: 5.2.3: Generating Random Numbers.

  3. Compile and run your program and make sure your output looks like the following. Note that the actual numbers may be different.
    You rolled a 0 and a 1481765933
    

    Notice the size of the numbers displayed. We want to limit the size of the random numbers generated by rand() to only six numbers. We limit the range by using the modulus (%) operator.

  4. Change the two assignment statements with the following code:
    int die1 = rand() % 6;
    int die2 = rand() % 6;
    

    The number 6 in the above code is known as the scaling factor since it limits the scale of the numbers produced by the rand() function.

  5. Compile and run your program and make sure your output looks like the following. Note that the actual numbers may be different.
    You rolled a 0 and a 5
    
  6. Seeing just one roll of the dice is not very useful. Add a counting loop to roll and display the dice 10 times. For more information, see section: 5.1.1: Using Loops to Count. You may want to use a for loop for counting as described in section 5.1.2: for Statements.
  7. Compile and run your program and make sure your output looks like the following. Note that the actual numbers may be different.
    You rolled a 0 and a 5
    You rolled a 3 and a 2
    You rolled a 5 and a 0
    You rolled a 0 and a 4
    You rolled a 0 and a 2
    You rolled a 1 and a 3
    You rolled a 5 and a 3
    You rolled a 5 and a 0
    You rolled a 5 and a 0
    You rolled a 0 and a 5
    

    Notice that we get numbers in the range of 0 to 5 when we want 1 to 6. To correct this problem, we must add one to each of the statements generating the random numbers. Go ahead and make this change now. For more information, see section: 5.2.5: Simulating Dice.

  8. Rerun your code two or more times and check the numbers rolled. Do you see any patterns? To correct the problem we must "seed" the random number generator. Add the following code after the start of main and before your counting coop:
    srand(time(0));
    

    For more information, see section: 5.2.4: Seeding the Random Generator.

  9. Compile and run your program and make sure your output looks like the following. Note that the actual numbers may be different.
    You rolled a 1 and a 1
    You rolled a 4 and a 5
    You rolled a 5 and a 6
    You rolled a 3 and a 6
    You rolled a 2 and a 4
    You rolled a 4 and a 6
    You rolled a 3 and a 4
    You rolled a 1 and a 5
    You rolled a 4 and a 5
    You rolled a 4 and a 6
    
  10. Submit your final program source code to Blackboard as part of assignment 5.

Check Yourself

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

  1. What is a function? (5.2.1)
  2. Why do we use functions? (5.2.2)
  3. Where does the control flow during a function call? (5.2.2)
  4. What is an argument? (5.2.2)
  5. What is a returned value? (5.2.2)
  6. What is a random number? (5.2.3)
  7. What is the value of RAND_MAX on our classroom computers? (5.2.3)
  8. How do you make the rand() function return a different random sequence when you run your program again? (5.2.4)
  9. How do you code a random number that simulates rolling a die? (5.2.5)
  10. What statement do we use to limit the range of the values returned by the rand() function to the values 1 through 10? (5.2.5)

5.2.5: Simulating Dice

  • A simulation is an imitation of some real thing or process
  • We create a simulation in a computer program by generating random events and evaluating their outcome
  • One simple simulation we can do is a pair of dice
  • We need a number between 1 and 6, but rand() returns a number between 0 and RAND_MAX
  • We need only random numbers for a die and so we scale the range of RAND_MAX using the % operator
  • Now we can generate random integer numbers between 0 and 5
  • To get a number between 1 and 6, we shift the numbers by adding 1
  • Our code to simulate a single die with random numbers is now:
  • int die = 1 + rand() % 6;
    cout << die << endl;
    
  • We can generalize our formula for producing integer random numbers to:
    rand() % SCALING_FACTOR + SHIFTING_VALUE;
    
  • The following program implements our dice rolling simulation
  • Note how the program simulates rolling 2 dice using 1 die at a time
  • You would get a different result if you just generated a random number between 2 and 12
  • To repeat the dice rolling, we use a loop

Example Program Simulating the Rolling of a Pair of Dice

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

int main() {
    srand(time(0));

    for (int i = 0; i < 10; i++) {
        int die1 = 1 + rand() % 6;
        int die2 = 1 + rand() % 6;
        cout << "You rolled a " << die1
             << " and a " << die2 << endl;
    }

    return 0;
}

5.2.6: Flotaing-Point Random Numbers

  • Sometimes we want random numbers that are of data type double
  • For example, we may want a random x and y locations for a turtle location
  • However, the rand() function returns an int and we need to convert the int to a double
  • For this we can use the formula:
    double r = rand() / (RAND_MAX + 1.0);
    
  • This produces a number between 0 (inclusive) and 1 (exclusive), often written as [0, 1)
  • One we have this random double, we multiply it by the scaling factor
  • Also, we can shift the range using addition or subtraction
    double num = r * SCALING_FACTOR + SHIFTING_VALUE;
    
  • Since the standard graphics screen ranges from -10 to +10, we would want to scale by 20 and shift by -10:
    double r = rand() / (RAND_MAX + 1.0);
    double y = r * 20 - 10;
    
  • However, depending on the size of the shape, we may want to adjust the scaling factor to keep the shape in the window
  • The following program draws 10 squares in random locations on a graphics window

Example Program Creating Random Coordinates

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
#include "turtlelib.cpp"

int ccc_win_main() {
    srand(time(0)); // seed generator one time
    Turtle myrtle;
    myrtle.right(90);

    string repeat ="y";
    while("y" == repeat) {
        myrtle.clear();
        for (int i = 0; i < 10; i++) {
            double rx = rand() / (RAND_MAX + 1.0);
            double x = rx * 15 - 10;
            double ry = rand() / ( RAND_MAX + 1.0);
            double y = ry * 14 - 10;
            myrtle.moveTo(x, y);

            myrtle.forward(5);
            myrtle.left(90);
            myrtle.forward(5);
            myrtle.left(90);
            myrtle.forward(5);
            myrtle.left(90);
            myrtle.forward(5);
            myrtle.left(90);
        }
        repeat = myrtle.getString("Again? (y/n) ");
    }
    exit(0);

    return 0;
}

5.2.7: Summary

  • A function is a block of code get executed when called
  • During a function call, control is passed to the called function
  • When the called function finishes executing, control returns to the calling function and statement
  • C++ has many predefined functions in several libraries
  • Libraries must be "included" in a program
  • #include <cmath>
  • Newer standard libraries, such as cmath, also require the directive
  • using namespace std;
  • One of the library functions generate "random" numbers: rand()
  • To seed the random number generator, you use the srand() function
  • We can use these functions to simulate the rolling of a die
  • srand(time(0));
    
    int die = 1 + rand() % 6;
    cout << die << endl;
    
  • You can use random numbers for other computations as well, such as x and y coordinates:
    double r = (double) rand() / ((double) RAND_MAX + 1.0);
    double y = r * 20 - 10;
    

5.3: Coding Functions

Learner Outcomes

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

  • Define functions with and without parameters
  • Pass arguments to functions

5.3.1: Drawing Multiple Squares

  • Recall our test code to draw a single square:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include "turtlelib.cpp"

int ccc_win_main() {
    Turtle myrtle;
    myrtle.right(90);

    myrtle.forward(5);
    myrtle.left(90);
    myrtle.forward(5);
    myrtle.left(90);
    myrtle.forward(5);
    myrtle.left(90);
    myrtle.forward(5);
    myrtle.left(90);

    return 0;
}
  • What would we need to add to draw two squares?
  • We would want to draw the two squares at different locations on the screen
  • Thus we would want to move the turtle to a new location and then draw the second square
  • 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
#include "turtlelib.cpp"

int ccc_win_main() {
    const double ANGLE = 90;
    const double SIZE = 5;
    Turtle myrtle;
    myrtle.right(90);

    // Draw first square
    myrtle.forward(5);
    myrtle.left(90);
    myrtle.forward(5);
    myrtle.left(90);
    myrtle.forward(5);
    myrtle.left(90);
    myrtle.forward(5);
    myrtle.left(90);

    // Jump to another location without drawing
    myrtle.moveTo(-6, -6);

    // Draw second square
    myrtle.forward(5);
    myrtle.left(90);
    myrtle.forward(5);
    myrtle.left(90);
    myrtle.forward(5);
    myrtle.left(90);
    myrtle.forward(5);
    myrtle.left(90);

    return 0;
}
  • Our program would be easier to write if we could draw a square without repeating the code
  • Ideally, we would give the list of commands a name and then run the list using the name
  • We can do this in C++ by creating a function

5.3.2: Defining a Function

Function -- a named block of code.

  • In other languages, a function is known as a method or subroutine.
  • Once you define a function, you can execute the block of code using the function's name
  • We have used functions already, such as:
    • sqrt(x) -- computes the square root of a floating point number
    • pow(x, y) -- computes the power of xy
  • Many functions have input values (a.k.a. arguments or parameters) that are transferred or passed into the function
  • For example:
    • The x in: y = sqrt(x);
    • Both the x and the y in: z = pow(x, y);
    • An expression as in: sqrt(b * b - 4 * a * c);
  • Many functions have output or return values
  • For example the y in: y = sqrt(x);
  • Both parameters and return values are a particular type
  • For instance:
    • You cannot compute: sqrt("Ed Parrish");
    • You cannot assign: string thing = sqrt(5.5);

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 statements to execute when the function is called
  • As an example, we can define our function to draw a square like this:
    void drawSquare(Turtle& turtle) {
        // Statements to draw a square
    }
    
  • Lets look more details of the syntax in order from left to right

Return Type

  • Sometimes you will want a function to return a value
  • If you do, then you need to specify the type of data it will return
  • If you do not want a function to return a value, then you use the keyword void
  • Functions with void return types are sometimes called procedures or just void functions

Function Name

  • Technically, you can use any valid identifier for a function name
  • However, you should use a name that suggests the action the function performs
  • For instance, drawSquare suggests that the function will draw a square

Parameter List

  • You must have parenthesis after the function name
  • Inside the parenthesis, you define a list of zero or more parameters
  • Parameters are like variables except they are declared inside the function parenthesis
  • Each parameter must have both a type and a name, just like a variable
  • If you have more than one parameter, you separate each one with commas
  • A parameter type can be any primitive type or class type, like a variable
  • A class type is usually followed by an ampersand "&" (we will discuss why later)
  • Any parameter that you declare must be given a value when you call the function

Code Block

  • After the parenthesis, you define the block of code that you want to execute
  • The block starts with an opening curly brace: {
  • The block ends with a closing curly brace: }
  • Between the curly braces, you place all the statements you want the function to execute
  • For readability, you indent the statements within the curly braces

5.3.3: Example Function Definition

  • Let us define a function to draw a square
  • In addition, let us use the function to draw two squares

Example Program with a Function for Drawing a Square

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
#include "turtlelib.cpp"

void drawSquare(Turtle& turtle) {
    const double ANGLE = 90;
    const double SIZE = 5;

    turtle.forward(SIZE);
    turtle.left(ANGLE);
    turtle.forward(SIZE);
    turtle.left(ANGLE);
    turtle.forward(SIZE);
    turtle.left(ANGLE);
    turtle.forward(SIZE);
    turtle.left(ANGLE);
}

int ccc_win_main() {
    Turtle myrtle;
    myrtle.right(90);

    drawSquare(myrtle); // Draw first square
    myrtle.moveTo(-6, -6); // Jump to new location
    drawSquare(myrtle); // Draw second square

    return 0;
}
  • Note that the function drawSquare() comes before main()
  • In C++, the compiler requires us to declare a function before we call the function
  • Since we call function drawSquare() from main(), we must put the function before main()

Why Parameters?

  • A variable declared inside a function can only be used within that function
  • For example, we declared myrtle inside the main() function:
    Turtle myrtle;
  • Since myrtle is declared in main(), we cannot use myrtle inside drawSquare()
  • Instead, we have to pass a copy of myrtle to drawSquare() in a function call:
    drawSquare(myrtle);
  • Then inside of drawSquare(), we can continue using myrtle with her new name of turtle:
    void drawSquare(Turtle& turtle) {
        // Statements to draw a square
    }
    

Flow of Control for a Function Call

  • To use functions well, you 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:
    drawSquare(myrtle);
  • The program executes the statements in the function and then returns to the statement from which it jumped
  • After returning to the same statement, the program moves on to the next statement
  • 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

5.3.4: Passing Data to a Function

  • Our drawSquare() function is flawed because the size of the square is hard-wired
  • Hard-wired means that the function is unable to change
  • Hard-wiring is bad because it prevents us from reusing the function
  • For instance, we may want to draw a square with a size of 3 or 7.5 for each side
  • We avoid hard-wiring functions by passing them parameters
  • In our example, the drawSquare() function already takes a single parameter:
    void drawSquare(Turtle& turtle) {
        // Statements to draw a square
    }
    
  • To allow changing the size, we add a second parameter:
    void drawSquare(Turtle& turtle, double size) {
        // Statements to draw a square using size
    }
    
  • When a function starts, its parameter variables are initialized with the arguments in the function call:
    drawSquare(myrtle, 3);
  • Note that parameters are just like variables except parameters are:
    • Declared inside the function parenthesis
    • Initialized by the arguments of the function call
  • You can see the improved drawSquare() function in the following example

Example Program with Multiple Function Parameters

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
#include "turtlelib.cpp"

void drawSquare(Turtle& turtle, double size) {
    const double ANGLE = 90;

    turtle.forward(size);
    turtle.left(ANGLE);
    turtle.forward(size);
    turtle.left(ANGLE);
    turtle.forward(size);
    turtle.left(ANGLE);
    turtle.forward(size);
    turtle.left(ANGLE);
}

int ccc_win_main() {
    Turtle myrtle;
    myrtle.right(90);

    drawSquare(myrtle, 3);
    myrtle.moveTo(-6, -6);
    drawSquare(myrtle, 5);

    return 0;
}

Arguments and Parameters

  • Depending on your programming background, you might use the term arguments or parameters for the values passed into functions
  • The terminology is not that important
  • However, the way I will use the terms is:
    • A called function has parameters
    • void drawSquare(Turtle turtle, double size) {
          // Send commands to turtle
      }
      
    • A caller passes arguments
    • drawSquare(myrtle, 5);
  • Arguments are values you pass into functions
  • When the argument drops into a function, it lands in a parameter
  • The parameter is just like a local variable in the function
    • Except that a parameter gets initialized by an argument
  • The important part is:

    If a function takes a parameter, you must pass it a value.

  • Also, the value must be the same type as the parameter

5.3.5: Summary

  • When we reuse a block of code in various parts of a program, we should put the code into a function
  • To define a function, we use 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
  • When we define a function, we want it to be reusable
  • To make a function more reusable, we avoid hard-wiring important values
  • Instead, we pass the key values by defining parameters
  • When we call the function, we supply an argument for each parameter

Exercise 5.3

In this exercise we define our own function.

Specifications

  1. Copy the following program into a text editor, save it as triangle.cpp, and then compile the starter code to make sure you copied it correctly.
    #include "turtlelib.cpp"
    
    int ccc_win_main() {
        // Enter code here
    
        return 0;
    }
    
  2. Inside the main() function, create a turtle named boggy.
    Turtle boggy;
  3. Before the main() function, define a function named drawTriangle() with the following code:
    void drawTriangle() {
        double angle = 120;
        double size = 5;
    
        boggy.forward(size);
        boggy.left(angle);
        boggy.forward(size);
        boggy.left(angle);
        boggy.forward(size);
        boggy.left(angle);
    }
    
  4. Try to compile your code. You should see an error message like:
    triangle.cpp:6: error: `boggy' undeclared
    

    The reason is that the turtle boggy we declared in main() cannot be used in another function. Instead, we need to have our own local version of boggy.

  5. Inside the curly braces of the drawTriangle() function, create a turtle named boggy as the first statement in the function.
    Turtle boggy;
  6. Compile and run your code. Notice that the window appears when you run your program but you do not see a triangle. In order to draw a triangle, we must call the function drawTriangle().
  7. At the end of the main() function, add a statement to call the drawTriangle() function:
    drawTriangle();
    

    Remember that C++ ignores the statements in a function until you call the function. For more information, see section: 5.2.2: Calling a Function.

  8. Compile and run your code to verify it draws a triangle.
  9. We want to draw triangles of different sizes. For this we need to add a parameter to the drawTriangle() function. First change the first line of the drawTriangle() function definition to:
    void drawTriangle(double size) {
    

    Then delete the statement double size = 5; inside the function.

    Notice the format of the parameter: double size. It looks like the code to declare a variable. The reason is that declaring a parameter is the same with one exception: a parameter is initialized to the value of the argument passed in the call to the function. Thus we do not need to assign a value "= 5". For more information, see section: 5.3.4: Passing Data to a Function.

  10. To initialize the parameter, we need to change the call to drawTriangle() and add the argument. While making the change, add an extra function call like:

    drawTriangle(5);
    drawTriangle(3);
    
  11. Compile and run your code to verify you see two triangles of different sizes.

    Notice how the two triangles overlap each other. We need a way to move the turtle before we draw the second triangle. The best way is to add a Turtle parameter to the drawTriangle() function.

  12. Change the first line of the drawTriangle() function to add a Turtle parameter:
    void drawTriangle(Turtle& boggy, double size) {
    

    Then delete the statement Turtle boggy; inside the function. Notice the format of the parameter: Turtle boggy. It looks like the code to construct an object except for the added ampersand (&). Most of the time you add an ampersand when using an object parameter. For more information, see section: 5.3.4: Passing Data to a Function.

  13. Now we need to move the turtle before drawing the second triangle. In main() change the call to drawTriangle() to add the argument for boggy. Also, tell boggy to moveTo() another location. The code inside of main() should now look something like:
    Turtle boggy;
    boggy.right(90);
    drawTriangle(boggy, 5);
    boggy.moveTo(-4, 0);
    drawTriangle(boggy, 3);
    

    When we call the drawTriangle() function, we are passing boggy as an argument. For more information, see section: 5.3.4: Passing Data to a Function.

  14. Compile and run your code to verify you see two separate triangles.
  15. Your final program should look like the listing below. Submit your final program source code to Blackboard as part of assignment 5.

Program to Draw Two Triangles

Code to draw a triangle

Check Yourself

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

  1. Why do programmers write functions? (5.3.1)
  2. What is a function? (5.3.2)
  3. What are the four main parts of a function? (5.3.2)
  4. How can you tell the difference between a function name and a variable name? (5.3.2)
  5. How many parameters can you declare for a function? (5.3.2)
  6. How is a variable declaration different than a parameter? (5.3.2)
  7. If you declare three parameters, how many arguments must you include in a function call? (5.3.4)
  8. Why do functions need parameters? (5.3.3)
  9. If you call a function in main(), do you place the function definition before or after main()? (5.3.3)
  10. Which of the following is a function definition and which is a function call? (5.3.4)
    1. void drawSquare(Turtle& turtle, double side) { }
    2. drawSquare(myrtle, 7.5);
  11. What is the difference between an argument and a parameter? (5.3.4)

Wrap Up

    Reminders

    Due Next: A4-Select a Shape (3/12/09)
    A5-Five Easy Functions (3/19/09)

  • 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 | Announcements | Day Schedule | Eve Schedule
Course info | Help | FAQ's | HowTo's | Links
Last Updated: April 11 2009 @16:25:35