Lab  8 -- C++ void Functions, Value and Reference Parameters, Local Variables

Click Here to CREATE ANSWER SHEET for LAB 8

Objectives:

Sections:
  1. Introduction
  2. Void Functions with no parameters
  3. Void Functions with value parameters
  4. Void functions with reference parameters
  5. Local variables

Introduction
In order to write a "good" modular program, it is essential that the program be composed of useful, well-defined functions.  There are two types of C++ functions:

User defined functions can be further divided into two groups depending on whether a function does or does not return a value. In this lab, we learn  how to write user-defined functions that do not return a value. This type of function is often referred to as the "void" function. The second topic of this lab is function parameters. In C++, there are two types of function parameters: (i) value parameters, and (ii) reference parameters. Value parameters are used to pass information into a function. Reference parameters are used to pass information in and out of a function.  We learn how to write functions that contain both of these types of parameters. Lastly, we discuss the usage of local variables in C++ programs.
 

void Functions with No Parameters
There are three basic things to remember when writing C++ functions. All C++ functions (except for the function called main) MUST be Declared, Activated, and Defined. All we need to remember is DAD!
 

Function Declaration
The C++ compiler requires specific information related to all functions activated in the program. To provide this information to the compiler, we must use a function declaration statement (or, function prototype declaration). The syntax for declaring the function prototype is:


type function-name (formal parameter type list);
Example : A function named "PrintHeading" that does not return a value, and does not require function parameters can be declared as:
// Print out the introductory message
void PrintHeading ();

All function prototypes should be declared before their activation.
 

Function Activation
No function in a C++ program will be executed unless it is "activated" (or "invoked" or "called") by another function. The syntax for void function activation is:


function-name(argument-list);

To activate the function "PrintHeading" declared above, we merely need to specify the name of the function and use () to indicate that the function requires no arguments:

PrintHeading ();

Function Definition
The function definition is a listing of the actual instructions that should be executed in the function. For example, if we had a function called "PrintHeading", we would assume that the definition for that function would contain several output statements to print an appropriate heading.

The function definition is composed of two separate divisions: a function header and a function body.
The function header appears as:


type function-name (formal parameter list)

The function body appears as follows:


{
[local declarations]         // a phrase in [ ] means "optional"
executable statements;
return ;

}

NOTE:


Example :

// function: PrintHeading
// Print out the introductory message 
void PrintHeading()
{
    cout << "***************** Mortgage Calculator 1.0 *****************" 
         << endl;
    cout << "Welcome! " << endl;
    cout << "This program computes the monthly mortgage payment on a house"
         << endl;
    cout << "You supply the information on: the loan amount, the interest rate"
         << endl;
    cout << "and the number of years on the loan." << endl << endl;
    cout << "The program will compute the monthly mortgage payment for you."
         << endl;
    cout << "**********************************************************"
         << endl;
    cout <<"Let's get started ..." << endl;
    
    return;
}

 

Exercise 1:
(a) Copy file cla8a.cc (it appears below for your convenience) into your directory. The function declaration part of this program is missing. Your job is to insert the function prototypes for all user-defined functions into the program. First, decide how many and what are the user-defined functions (exclude the main function) in this program. Then, declare the function prototype of each function in the appropriate place in the program. Compile and run the program. Make sure you understand the output of the program.
 

(b) Next, you should modify the program so that it produces output similar to the following (see the steps below for how to do this):

                           *
                       *       *
                    *             *
                    *             *
                    *             *
                       *       *
                           *
                    ---------------
                   |               |
                   |               |
                   |               |
                   |               | 
                   |               |
                    ---------------
                           $
                         $   $
                        $     $
                       $       $
                      $         $

    Step 1:  Add a new function "DrawCircle" to the program by writing the function definition and the function prototype. This function draws a circle in the following form:

                           *
                       *       *
                    *             *
                    *             *
                    *             *
                       *       *
                           *

    Step 2: Modify function activations in the main function, so that the program produces the output shown above.

    Step 3: Turn in a script log containing a cat, compile, and run of your program.
 



//File: cla8a.cc
//This program draws a house by printing characters
//to the screen.

#include <iostream>

using namespace std;

// declare all function prototypes here

int main()
{
     PrintIntersecting();      //draw the roof
     PrintHorizontal();        //draw the base of the roof
     PrintParallel();          //draw the sides of the house
     PrintHorizontal();        //draw the base of the house 

     return 0;
}


// function : PrintParallel()
// Print out two parallel lines

void PrintParallel()
{
     cout << "|        |" << endl;
     cout << "|        |" << endl;
     cout << "|        |" << endl;
     cout << "|        |" << endl;
     cout << "|        |" << endl;
     return;
}


// function : PrintIntersecting()
// Print out two intersecting lines

void PrintIntersecting()
{
     cout << "     $     " << endl;
     cout << "    $ $    " << endl;
     cout << "   $   $   " << endl;
     cout << "  $     $  " << endl;
     cout << " $       $ " << endl;
     return;
}


// function : PrintHorizontal()
// Print out a horizontal line

void PrintHorizontal()
{
     cout << "-----------" << endl;
     return;
}

Functions with Value Parameters
Function Declaration
A value parameter is used to pass information into a function to be processed.
Remember the general form for a function declaration:


type function-name (formal parameter type list);
A void function with value parameters are declared by enclosing the list of types for the parameter list in the parentheses.

Example:  A function that prints out a user specified number of horizontal lines is declared as:


// Purpose: Print out a number of lines
// Precondition: numOfLines has a value assigned.
// Postcondition: the number of lines are printed.
void PrintLines(int);

or

// Purpose: Print out a number of lines
// Precondition: numOfLines has a value assigned.
// Postcondition: the number of lines are printed.
void PrintLines(int numOfLines); //parameter names are used for documentation only

Example: A function that  prints out the final letter grade for a student, given the name of the student and his/her overall score, is declared as:



// Purpose: Print out the final letter grade for a student
// Precondition: the name of the student and the overcall score are assigned
// Postcondition: the final letter grade is printed.
void PrintGrade(string, float);

or

// Purpose: Print out the final letter grade for a student
// Precondition: the name of the student and the overcall score are assigned
// Postcondition: the final letter grade is printed.
void PrintGrade(string name, float score);

Function Activation
To activate a void function with value parameters, we specify the name of the function and provide the actual arguments enclosed in parentheses.  The order  and types of the list of arguments should correspond exactly to those of the formal parameters declared in the function prototype. The arguments can be constants, expressions, variables, or even function calls themselves. If an argument is a variable, at the time of function activation, the variable must have a value.

Example:

       PrintLines(8);
                   or

        numOfLines = 5;
        PrintLines(numOfLines);

Example:

        PrintGrade("John", (90+87.5)/2);       
                    or
 
        name = "John";
        overallScore = (90+87.5)/2;
        PrintGrade(name, overallScore);

Function Definition
The order and types of the list of formal parameters in a function header should correspond exactly to those declared in the function prototype.  For value parameters, a copy of the value of the arguments is passed into the function. This means that if a value parameter is changed within a function, only the copy is changed, and does not change the value of the argument in the calling function.

To help visualize the relationship between the actual arguments in the calling program and formal parameters in a function, consider the situation below. In the calling program suppose we have the declarations and activation statements shown on the left. Then memory could be depicted as shown on the right. Similarly, if the function definition were as shown on the left, memory for the function could be depicted as shown on the right.


 

Now lets look at two examples of function definitions.

Example:

	// function: PrineLines( )
	// Purpose: Print out a number of lines
	// Precondition: numOfLines has a value assigned.
	// Postcondition: the number of lines are printed.
	void PrintLines(int numOfLines)
	{
		int i = 0;
		while (i < numOfLines)
		{
			cout << "-------------" << endl;
			i++;
		}
		return;
	}

Example:

	// Purpose: Print out the final letter grade for a student
	// Precondition: the name of the student and the overcall score are assigned
	// Postcondition: the final letter grade is printed.
	void PrintGrade(string name,float overall)
	{
		cout << endl;
		cout << "The final grade for " << name  << " is " ;
		if (overall >= 90)
		{
			cout << "A" << endl;
			cout << "Congratulations!" << endl;
		}
		else if (overall >=80)
		{
			cout << "B" << endl;
			cout << "good job!" << endl;
		}
		else if (overall >=70)
		{
			cout << "C" << endl;
			cout << "Work harder next time!" << endl;
		}
		else if (overall >=60)
			cout << "D" << endl;
		else
			cout << "F" << endl;
		return;
	}

Exercise 2:
Copy program cla8b.cc into your directory.  This program attempts to draw a series of triangles. The height and the letter used to draw each triangle is supplied by the user.  For example, when the specified height is 6, and the letter is '&', the triangle drawn by the program looks like this:

&
&&
&&&
&&&&
&&&&&
&&&&&&

The declaration, activation, and definition of the user-defined function "DrawTriangle" are missing from the code. Fill in the missing code.
Turn in a script log containing a cat of your program, a compile, and a run of your program with the following value pairs:
 run 1:   9     '*'
 run 2:   5      '$'
 run 3:   10    '@'
(note:  the end-of-file character on Unix is Ctrl-d)


 
// File Name:     cla8b.cc
// This program prints a series of triangles.
// Both the height and the character used to draw each 
// triangle are supplied by the user.

#include <iostream>

using namespace std;


// declare the function prototype for "DrawTriangle" here


int main()
{
    //local variables
    int height;          //the height of the triangle
    char character;      //the character used in drawing the triangle

    cout << "Enter the height of the triangle. ";
    cout << "Enter the end-of-file character to quit. " << endl;
    cin >> height;
    cout << "Enter the character used to draw the triangle. ";
    cout << "Enter the end-of-file character to quit. "<< endl;
    cin >> character;

    //loop to continue processing triangles until the user
    //type the end-of-file character.
    while (cin)
    {
         cout << endl << endl;

         
         //fill in the activation statement for DrawTriangle here
         
         

         cout << "Enter the height of the triangle. ";
         cout << "Enter the end-of-file character to quit. " << endl;
         cin >> height;
         cout << "Enter the character used to draw the triangle. ";
         cout << "Enter the end-of-file character to quit. "<< endl;
         cin >> character;
     }   //end of while loop
     return 0;
}

//fill in the function definition here 
//Hint:  Use a nested while loop to draw the triangle
void DrawTriangle (int h, char c)
{


}
void Functions with Reference Parameters
Function Declaration
The second type of parameter in C++ is called a reference parameter. These parameters are used to send back a value (output), or both to send in and out values (input and output)  from functions. Reference parameters have the ampersand (&) following their type identifier in the function prototype and function heading.

Example:  A function that reads and returns (output)  the length and width of a rectangle entered by the user, is declared as:


// Purpose: Read and return the length and width of a rectangle 
// Postcondition: the values of the two arguements are read
void GetData(int& length, int& width);

or

// Purpose: Read and return the length and width of a rectangle 
// Postcondition: the values of the two arguements are read
void GetData(int&, int&);

Note: In this example, both values are to be sent back to the calling function, therefore, both are reference parameters.

Example:  A function that updates (input and output) the balance of a bank account by incorporating the current transaction amount, is declared as:


// Purpose: Update the balance of a bank account by incorporating the current transaction
// Precondition: the value of the amount is assigned
// Postcondition: the value of the balance is updated
void UpdateBalance(float amount, float& balance);
  
or 

// Purpose: Update the balance of a bank account by incorporating the current transaction
// Precondition: the value of the amount is assigned
// Postcondition: the value of the balance is updated
void UpdateBalance(float, float&);

Note: In this example, "amount"  is for input information only, and therefore is declared to be a value parameter. Yet, "balance"  is used both as an input and output parameter. Therefore, it is declared to be a reference parameter.
 

Function Activation
Unlike value parameters, the arguments corresponding to reference parameters have to be variables, and should have been declared properly before the activation of the function.

Here are two examples of  function activations :

Example:     GetData(length, width);

Example:     UpdateBalance(1000, balance);
 

Function Definition
For the function heading, reference parameters have types followed by an ampersand(&).

Example:


// Purpose: Read and return the length and width of a rectangle 
// Postcondition: the values of the two arguements are read
void GetData(int& length, int& width)
{
      cout << "Enter the length of the rectangle" << endl;
      cin >> length;
      cout << "Enter the width of the rectangle" << endl;
      cin >> width;
      return;
}

Example:


// Purpose: Update the balance of a bank account by incorporating the current transaction
// Precondition: the value of the amount is assigned
// Postcondition: the value of the balance is updated
UpdateBalance(float amount, float & balance)
{
      balance = balance + amount;
      return;
}

If the parameter is a reference parameter, the address of the parameter is passed to the function. This means, if the reference parameter is changed in the function, the argument is changed. To help visualize the relationship between actual arguments in the calling program and formal reference parameters in a function, consider the situation below. Note that the formal arguments are using the same memory location as the actual arguments. The picture below shows that when the function is called, x (and therefore a) has the value 5. The second actual argument, y, has not been assigned a value yet and thus the formal argument b does not have a value either.

The picture below shows the values of x, y, a, and b after the two statements in the function have been executed but prior to the return to the calling program. Notice that since b was assigned to 3.0 that y also has the value 3.0 because both y and b refer to the same memory location. Similarly the value given to a is also given to x because both x and a refer to the same memory location.


 

Exercise 3:
Copy files "cla8c.cc" and "cla8c.dat" into your directory. In this exercise, you will complete the program (cla8a.cc) that computes the average, the highest, and the lowest scores of a test for a class. All test scores are stored  (one score per line) in a file called "cla8c.dat". Some code of the program is missing. This includes the declaration, the activation, and the definition of a user-defined function "ProcessTest". "ProcessTest" is the function that computes and returns the average, the highest, and the lowest test scores. It has 4 parameters:
(1) the input file containing test data,
(2) the average test score,
(3) the highest score,  and
(4) the lowest score.

Determine whether each parameter should be declared as a value parameter or a reference parameter (Hint: All input and output files streams must be reference parameters). Then fill in the missing code in the program at the appropriate places. Turn in a script containing a cat of the modified program, a compile, and a run.
 


// File Name:  cla8c.cc
// This program computes the average, the highest, and
// the lowest scores of a test for a class.
// All the scores are stored in a data file (one score per line)
// called "cla8c.dat".


#include < iostream >
#include < fstream >

using namespace std;


// declare function "ProcessTests" here



int main()
{
    float     highest,         //the highest score in the file 
              lowest,          //the lowest score in the file
              average;         //the average score in the file
    ifstream  datafile;        //an input file stream object
    
    //open the data file
    datafile.open("cla8c.dat");

    // fill in the activation statement for function "ProcessTests" here



    cout << "The highest score is " << highest << endl;      
    cout << "The lowest score is " << lowest << endl;      
    cout << "The average score is " << average << endl;      

    datafile.close();
    return 0;
}


// define the function here

// ProcessTests
// This function finds the highest, lowest, and
// the average test score

void ProcessTests(   ,   ,   ,     )
{



}

  Local Variables
Variables defined in a function are local variables. This means that these variables are visible and can only be used by the function in which the variable is defined! Because local variables are destroyed once the function returns control to the calling function, they can not be used to store values between calls to the function. A function's value parameters are also local variables for the function.

Exercise 4:
Examine the program cla8d.cc listed below. On the answer sheet list all local variables in the main () function. List all local variables in function GenerateTable()
 


// File Name:   cla8d.cc
// Displays the height of an object dropped from a tower
//    at user specified intervals, until it hits the ground.

//include statements
#include < iostream >
#include < iomanip >
#include < cmath >

using namespace std;

//function prototypes
void GenerateTable(float, float);

int main ()
{
   // Local data ...
   float towerHeight;          // height of tower (meters)
   float deltaT;               // time interval

   // Enter tower height and time interval.
   cout << "Enter tower height in meters: ";
   cin >> towerHeight;
   cout << "Enter time in seconds between table lines: ";
   cin >> deltaT;
   cout << endl;

   // Display object height until it hits the ground.
   GenerateTable(towerHeight, deltaT);

   return 0;
}

// GENERATE TABLE
// This function computes the height of the object at user specified time
// intervals and print out the heights in a table format

void GenerateTable
  (float towerHeight,      // INPUT: height of tower from which object dropped
   float deltaT)           // INPUT: time interval
{
   const float g = 9.80655; // gravitational pull in meters per second squared
   float objectHeight;      // height of object at any time t
   float t;                 // total elapsed time

   // Display table header.
   cout << setw(10) << "Time" << setw(9) << "Height" << endl;
   t = 0.0;
   objectHeight = towerHeight;

   // Display table.
   cout.setf(ios::fixed);
   while (objectHeight > 0.0)
   {
      cout << setw(9) << setprecision(2) << t << setw(10) << objectHeight 
           << endl;
      t += deltaT;
      objectHeight = towerHeight - 0.5 * g * pow (t, 2);
   }  // end while

   // Object hits the ground.
   cout << endl << "SPLAT!!!" << endl << endl;
}

Congratulations!! You have reached the end of Lab 8