ADVANCED PLACEMENT Computer Science - C++

Lesson 6 - Functions and Scope

INTRODUCTION:               
 
Programs of any significant size are broken down into logical pieces called functions.  It was recognized long ago that programming is best done in small sections which are connected in very specific and formal ways.  C++ provides the construct of a function, allowing the programmer to develop new functions not provided in the original C++ libraries.  Breaking down a program into blocks or sections leads to another programming issue regarding identifier scope.  Also, functions need to communicate with other parts of a program which requires the mechanics of parameter lists and a return value.

The key topics for this lesson are:

A.    Writing Functions in C++
B.    Value Parameters and Returning Values
C.    Scope of Identifiers 

VOCABULARY:           

1. FUNCTION DECLARATION 5. VALUE PARAMETERS 9. FUNCTION DEFINITION
2. PARAMETERS 6. ACTUAL ARGUMENTS 10. GLOBAL SCOPE
3. BLOCK 7. FORMAL ARGUMENTS 11. SCOPE 
4. LOCAL SCOPE 8. LEAST PRIVILEGE  

DISCUSSION:                       

A.    Writing Functions in C++

1.    A function is like a box which takes data in, solves a problem, and usually returns a value.  The standard math functions follow this pattern:

       sqrt (2)  --->  1.414

2.    There are times when the built-in functions of C++ will not get the job done.  We will often need to write customized functions which solve a problem using the basic tools of a programming language.

3.    For example, suppose we need a program which converts gallons into liters.  We could solve the problem within function main.

       Program 6-1

#include <iostream.h>

main ()

{
double gallons, liters;
         cout << "Enter an amount of gallons ---> ";
         cin >> gallons;
         liters = gallons * 3.785;
         cout << "Corresponding amount in liters = " << liters << endl;
         return 0;
}

       This works fine, but the mathematics of the conversion is buried inside function main.  The conversion tool is not available for general use.  We are not following the software engineering principle of writing code which can be recycled in other programs.

4.    Here is the same routine coded as a reusable function

       Program 6-2

#include <iostream.h>

double  convert (double amount);               //  function prototype

 main ()
{
         double   gallons, liters;
         cout << "Enter an amount of gallons ---> ";
         cin >> gallons;
         liters = convert (gallons);
         cout << "Corresponding amount in liters = " << liters << endl;
         return 0;
}

double  convert (double  amount)               // function definition
{
         return   amount * 3.785;
}

    Sample run output:

     Enter an amount of gallons ---> 10
        Corresponding amount in liters = 37.85

Here is a sample showing the intro function, which is required in all future programs.

//Program cfunctions,#9 by R. Krane on 10/12/99

#include <iostream.h >

  
int intro();                    // prototype
double convert (double amount); 

int main()
{
	 intro();
       double   gallons, liters;
       cout << "Enter an amount of gallons ---> ";
       cin >> gallons;
       liters = convert (gallons);
       cout << "Corresponding amount in liters = " << liters <<endl;
       return 0;
}

int intro()
{
	cout << "Program Cfunctions by R. Krane on 10/12/99" << endl;
	cout << endl;
	cout << "This program will convert gallons to liters." << endl;
	cout << endl;
	return 0;
}

double convert(double amount) //function definition
{
         return   amount * 3.785;
}     

5.    Here is the sequence of events in this short program. 

a.     Execution begins in function main with the user prompt and the input of an   amount of gallons.
b.    The function convert is called and the amount of gallons is passed as an argument to function convert.
c.     Program execution moves to function convert which solves the math and returns the answer to the calling statement.
d.    The answer is printed out.

6.    The general syntax of a function declaration is

       return type     name of function    (parameter list)

a.     The return type must be a data type already recognized by the compiler.
b.    The name of the function must be a valid identifier.
c.     The parameter list consists of one or more type-identifier pairs of information.  These parameters are called the formal parameters.

7.    The line above function main

double  convert (double);             //  function prototype

       is called the function declaration or prototype.  This statement declares the 
       function before it is referred to in function main.  When the compiler encounters 
       the line inside of function main

         liters = convert (gallons);

       it has already seen convert defined in the prototype.  The function definition at the bottom of the program completes the function which must include both the prototype and code which solves the problem.  We could have placed the function definition above function main and omitted the function declaration, but this is good practice for later issues regarding program design in C++.

8.    When writing the function prototype, the identifier of a variable type in the parameter list can be omitted.  The compiler will ignore any identifier names in the parameter list of a function prototype. 

9.    When the function is called, the value passed to the function is called the actual parameter.  The integer named gallons inside of function main serves as the actual parameter.

B.    Value Parameters and Returning Values

1.    The values passed to a function become the source of input for the function.  Notice that inside of function convert, no data input was required from an external source.

2.    The single parameter is an example of a value parameter.  A value parameter has the following characteristics:

a.     It receives a copy of the argument which was passed to the function.  The value of 10 stored in gallons (inside of main) is passed to the parameter amount (inside of convert).

b.    This value parameter is a variable which can be modified within the function.

c.     This value parameter is a local variable.  This means that it is valid only inside of the block in which it is declared.  We refer to a function in C++ as a block of code.

3.    A function can return a single value.  The data type of the value returned is listed first in the function prototype.  If this data type is omitted the default value returned is an integer. Somewhere in the body of the function there must be a return statement if we want the function to return the correct answer.

4.    If a function returns no value the term void should be used.  For example:

void  printHello ( )

{
       cout << "Hello world" << endl;

       The term void can be used in one or both locations of input and output for the function.  However, an alternative to a void parameter list is the empty parameter list as used in the above example.

5.    A function can have multiple parameters in its parameter list.  For example:

double  doMath (int  a, double x)

{

         ... code ...

       When this function is called, the arguments fed to function doMath must be of an appropriate type.  The first argument must be an integer.  The second argument can be an integer (which will be promoted to a double), but it will most likely be a double.

doMath (2,3.5);                      //  this is okay

doMath (1.05, 6.37);              //  this will not compile

6.    Value parameters are often described as one-way parameters.  The information flows into a function but no information is passed back through the value parameters.  A single value can be passed back using the return statement, but the actual parameters in the function remain unchanged. 

7.    The actual arguments used to supply values for the value parameters can be either literal values (2, 3.5) or variables (a, x).

         doMath (a, x);                 // example using variables

C.    Scope of Identifiers

1.    Scope refers to the area of a program in which an identifier is valid and has meaning.

2.    There are four categories of scope in C++:  file scope, block scope, function scope, and function-prototype scope.

3.    An identifier declared outside of any function has file scope.  Such an identifier can be used in all functions which follow until the end of the file.  Such variables are also called global variables.  The function prototypes declared near the top of a source code have file scope.

See Handout H.A.6.1, Scope and Value Parameters , to reinforce scope concepts.

4.    Global constants are often used in programs but global variables are usually inappropriate.  The use of global variables can lead to difficult bugs,  therefore such use is discouraged.  

5.    Block scope applies to identifiers declared inside a block.  A block begins wherever that identifier is declared until the terminating right brace (}) of that block.  Functions have two possible categories of identifiers with block scope.

a.     Function parameters have block scope.  The local identifiers used as parameters are known throughout the function.

b.    Local variables declared inside the function have block scope.

       If a block is nested inside another block, identifiers declared in the inner block only have meaning inside the inner block.  The outer block does not have access to the inner identifiers.  For example:

Program 6-3

#include <iostream.h>

main ()

{
         int  a = 3;
         cout << "The value of a in the outer block = " << a << endl;
         {
                 int  a = 8;
                 cout << "The value of a in the inner block = " << a << endl;
         }
         cout << "The value of a in the outer block is still " << a << endl;
         return 0;
}

      Run output:

    The value of a in the outer block = 3
     The value of a in the inner block = 8
       The value of a in the outer block is still 3

6.    Identifiers used in the parameter list of a function prototype have no meaning elsewhere in the program, even in the definition of the function.  Identifiers used in the parameter list of a function prototype are ignored by the compiler.

7.    C++ provides the unary scope resolution operator (::) which allows access to a global variable having the same name as a local variable.

Program 6-4     Unary Scope Resolution Operator

#include <iostream.h>
int  a = 3;        // global version of a
main ()

{
         int  a = 5;        // local version of a
         cout << "Local a = " << a << endl;
         cout << "Global a = " << ::a << endl;
         return 0;
}

 

Run Output:
Local a = 5
Global a = 3
 

       This unary scope resolution operator will be used when programming classes in Lessons 12 and Lessons 27-29.


Syntax/correctness issues

 

6-1        The data type of the return value of a function must match the data type in the function prototype.

6-2        Forgetting to return a value from a function, which is supposed to return one, will lead to unexpected errors in a program.

 6-3        In a function prototype, the parameter must include the data types of values to be passed; identifiers are optional.  Also, each function prototype must end with a semicolon.

              int  doSomething (int  x,y);       //  syntax error, the y needs a data type

             int  doItRight (int x,  int y);      //  this is acceptable

             int  P (int, int);              //  this is also acceptable

 6-4        When writing the function definition, do not place a semicolon after the parameter list.

              int  doItRight (int x,  int y);      //  <--- no semicolon on this line, this will not compile

             {

                  // some code

             }

6-5        Do not define a function inside another function.  C++ does not allow for nested definitions.

 6-6        Function prototypes are required in C++.

Formatting suggestions

6-7        Separate the implementation of functions with blank lines to enhance their readability.

Software engineering

6-8        Function main should consist of calls to other functions which accomplish the work of the program.

6-9        Each function should solve a single, well-defined task.  The name of the function should help describe the task of the function.

6-10      Functions should be no longer than one page.  If possible, keep functions short.  This will make it easier to read and debug your code.

6-11      A function which contains a large number of parameters may be trying to do too much.  Consider breaking the function down into smaller functions.

6-12      Global variables should be avoided as they allow side-effects to occur.  A side-effect is an unintended change to a global variable from inside a function.  Variables which exist during the entire execution of the program should be declared in function main and then passed to other functions through parameters.


SUMMARY/REVIEW:                Your programs will grow in size and complexity.  Initially you will not use all the tools presented in this lesson and Lesson 7 regarding functions.  However, you need to see and understand all the function-writing tools in C++ since eventually you will need them in your own work and to help you read another programmer's code. 

ASSIGNMENT:                           Lab Exercise, L.A.6.1, Fun