Functions
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.
Writing Functions in C++
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
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.
For example, suppose we need a program which
converts gallons into liters. We could
solve the problem within
function main.
#include <iostream.h>
int 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.
Here is the same routine coded as a reusable
function:
#include <iostream>
//note .h omitted, must now include next line
using namespace std;
//can use either approach in this course
double
convert (double
amount); //
function prototype - name amount optional
int 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; //
convert (above) becomes amount*3.785
}
Sample run output:
Enter an amount of
gallons ---> 10
Corresponding
amount in liters = 37.85
Here is the sequence of events in this short
program.
ð Execution begins in function main with
the user prompt and the input of an amount of gallons.
ð The function convert is called
and the amount of gallons is passed as an argument to function convert.
ð Program execution moves to function
convert
which solves the math and returns the answer to the calling statement.
ð The answer is printed out.
The general syntax of a function declaration
is
return type
name of function (parameter list)
ð The return type must be a data type
already recognized by the compiler.
ð The name of the function must be a
valid identifier.
ð The parameter list consists of one or
more type-identifier pairs of information.
ð These parameters are called the formal
parameters.
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++.
ð 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.
ð
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.
Returning
Values
ð 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.
ð The single parameter in the above program is
an example of a value parameter.
A value parameter has the following
characteristics:
ð 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).
ð This value parameter is a variable
which can be modified within the function.
ð 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.
A function can return a single value.
ð 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.
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.
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
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.
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
Scope of Identifiers
The following concepts are very
important in all modern CS languages
ð Modularization: Breaking the code into components or functions (and classes
covered later)
ð Information Hiding: Restricting where
variables and functions have meaning - scope
Scope
There are four categories of scope in C++: file scope, block scope,
function scope, and function-prototype
scope.
ð File Scope
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. Global constants are often used in
programs but global variables are
usually inappropriate. The use
of global variables can lead to difficult bugs.
ð Block Scope
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.
Function parameters have block scope.
The local identifiers used as parameters are known throughout the function
Local variables declared inside the
function have block scope, from the point at which they are
defined.
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:
#include
<iostream>
using namespace std;
int 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;
}
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.
Passing By Reference vs By Value
#include <iostream>
using namespace std;
int Mystery1 (int x);
//need type, the name of the variable, x, is optional here
void Mystery2 (int & y);
int main ( )
{
int mon = 2;
int tue = 3;
int wed = 0;
cout <<
"original mon: "<<mon<<endl;
cout <<
"original tue: "<<tue<<endl;
cout <<
"original wed: "<<wed<<endl;
cout <<endl;
wed = Mystery1 (mon);
//Call Mystery1, pass mon
Mystery2 (tue);
//Call Mystery2, pass tue
cout << "mon is now: "<<mon<<endl;
cout << "wed is now: "<<wed<<endl;
cout << "tue is now: "<<tue<<endl;
cout << endl;
return 0;
}
int Mystery1 (int x)
{
return 2*x;
}
void Mystery2 (int & y)
{
y = 10*y;
}
Prototypes
You can omit prototypes if the function
is defined before it is used.
Always provide prototypes, however, because
this avoids typing code to the order in which functions are defined (the order can
easily change later)
Example 1
#include <iostream>
using namespace std;
void testSomething ( );
//prototype required for this function
int main()
{
testSomething ( );
return 0;
}
void printHi ( )
{
cout << "No function protype required-function defined before
used"<<endl;
}
void testSomething ( )
{
printHi ( );
}
Example 2
#include <iostream>
using namespace std;
//no function prototypes required here
void printHi ( )
{
cout << "No function protype required-function defined before
used"<<endl;
}
void testSomething ( )
{
printHi ( );
}
int main() //all functions before main - bad paractice!
{
testSomething ( );
return 0;
}
Passing Parameters
#include <iostream.h>
//preprocessor directive
//function prototypes
void Greetinga ( );
//no parameters are passed, nothing returned
void Greetingb (int);
//an integer parameter is passed, nothing returned
double Matha (int a, double b); //int and
double parameters passed, a and b ignored, double returned
int main ( )
{
Greetinga ( );
//calling function Greetinga
int a = 7;
Greetingb(a);
//calling function Greetingb
int b = 2;
double c = 4.0;
double answer;
answer = Matha(b, c);
//calling function Matha, return placed in answer
cout <<"Return from Matha is "<<answer<<endl;
return 0;
}
//function definintion
void Greetinga ( )
{
cout <<"Good morning"<<endl;
}
//function definition
void Greetingb (int m)
{
cout <<"You are customer number "<<m<<endl;
}
//function definition
double Matha(int a, double b)
{
return a/3.0 + b;
}
Function Calling Another
#include <iostream.h>
void firstFunction (int);
void secondFunction ();
int main ( )
{
int age = 0;
cout << "Please enter an age"<<endl;
cin >>age;
firstFunction (age);
return 0;
}
void firstFunction (int age)
{
if (age < 20)
secondFunction ( );
else
cout <<"age is not less than
20"<<endl;
}
void secondFunction ( )
{
cout << "age is less than 20"<<endl;
}
Note: Always check the
possibilities when debugging code
Suggested Approach
Step 1: Outline the Program with Function
Prototypes
Step 2:
Copy and Paste Function Prototypes
Step 3: Complete the Main, Then Complete the Other
Functions
Step 1: Outline the Program by Writing
the Following. Here, the main modules are identified.
//Name
//Date
//Lab Number
#include <iostream.h>
void firstFunction (int a, double b);
//a and b not required. My rationale for including them
int secondFunction (int c);
//c not required
double thirdFunction (double d, int e); //d and e not
required
int main ( )
{
return 0;
}
Step 2: Copy and Paste the function prototypes below the main, remove semicolon,
etc.
Run this "Stub". If you have errors here, correct them before filling in the
function details
//Name
//Date
//Lab Number
#include <iostream.h>
void firstFunction (int a, double b);
int secondFunction (int c);
double thirdFunction (double d, int e);
int main ( )
{
return 0;
}
void firstFunction (int a, double b)
{
}
int secondFunction (int)
{
return 1;
//1 is a placeholder so the program will run
}
double thirdFunction (double, int)
{
return 1.0;
//1.0 is a placeholder so the program will run
}
Step 3: Initialize variables in the main function and call the other
functions
//Name
//Date
//Lab Number
#include <iostream.h>
void firstFunction (int a, double b);
int secondFunction (int c);
double thirdFunction (double d, int e);
int main ( )
{
//all variables declared and intitialized at the beginning of function
int a = 6;
double b = 10.0;
int c = 32;
double d = 4.5;
int e = 5;
int secondResponse = 0;
double thirdResponse = 0.0;
//Call the functions. Note that data type not included - stated
already.
firstFunction (a,b);
secondResponse = secondFunction (c);
thirdResponse = thirdFunction (d, e);
//Print the output of second and third functions
cout << "c is: "<<c<<" and 2 times c is:
"<<secondResponse<<endl;
cout << "d is: "<<d<<" e is: "<<e<<" and d + e is:
"<<thirdResponse <<endl;
return 0;
}
//Function definition
void firstFunction (int a, double b)
{
cout <<"a is: "<<a<<endl;
cout <<"b is: "<<b<<endl;
}
//Function definition
int secondFunction (int c)
{
return 2*c;
//The function in main now becomes 2*c
}
//Function definition
double thirdFunction (double d, int e)
{
return d + e;
//The function in main now becomes d + e
}
Some Points
Prototypes
ð Must include return type, name of
function, data type of parameters
ð Name of parameters is optional
Main
ð Declare and initialize variables
before they are used.
ð A good rule is to declare and
initialize variables at the beginning of the main.
ð Call functions by invoking the name
and including the parameter names; do not include data types, if you do you
will get a duplicate
definition error.
ð If a function returns something,
declare and initialize a variable to hold the answer.
Function Definitions
ð Header (first line) must be identical
to prototype except no semicolon.
ð
If return type is anything other than
void then you must include appropriate return statement.
ð If return type is void then you cannot
include the return statement.