A function is a part of a program that does a specific task. Functions have two main purposes:
You can think of a function as if it were a recipe. For example, a cookbook may have a recipe for Eggs Benedict, which needs Hollandaise sauce. It might look like this:
At the end of step 2, you put aside the eggs and muffin, and turn to page 211. After you’re done with that recipe, you return to step 4 and continue with the recipe. This approach also is modular. The recipe for Salmon and Hollandaise sauce won’t have to repeat the part about the sauce; it can just point you to page 211 and off you go.
A function has this generic form:
type name( parameters ) // function header
{
function body
}double
and the toupper() function returns a char.
If a function doesn’t return a value, you use the word
void here.
getMagicObject, but not magicObject.
toupper() needs a character
as its input– which character are you converting to uppercase?
srand() needs an integer as its input–where would
you like the random number generator to start? rand(),
on the other hand, doesn’t need any extra information from you.
It just generates a random number all by itself
Let’s give some examples.
When you call a function to show a game’s instructions,
that function doesn’t require any extra
information, and it doesn’t return some numeric or character
value to you. That means you have a void function
with no parameters:
void showInstructions( )
{
cout << "Move your character through the maze." << endl;
cout << "Press J to jump, L for left, R for right," << endl;
cout << "U for up, and D for down. Q quits the game." << endl;
}
You would call this function from main( ) as shown in the
following code. Notice that, even though there are no parameters, you
must put parentheses after the function name. That lets the
compiler know you are calling a function rather than referring to a
simple variable.
int main( )
{
const int N_ROWS = 10;
const int N_COLS = 10;
int maze[N_ROWS][N_COLS];
showInstructions( );
}
If you try writing this program and put the showInstructions()
function after main(), it won’t work. The compiler
needs to know what showInstructions is, just as it needs to
know your variable names before you use them. You have two choices. You
can either put the function before main() in your .cpp file,
or you can give the compiler a “preview of coming attractions”
by putting a copy of the function header before main(). This
copy is called a function prototype, and it makes the compiler
happy. Note that the prototype ends with a semicolon, the header never does.
void showInstructions( );
int main( )
{
const int N_ROWS = 10;
const int N_COLS = 10;
int maze[N_ROWS][N_COLS];
showInstructions( );
}Some functions just display information and don’t calculate any values to return to you, but they do need extra information to do their job. For example, here is a function that displays the number of lives left, pluralized correctly. To do its job, you have to tell it how many lives to display. In the following code, numbers in black boxes like this: 0 refer to the notes that are after the program.
void showLives( int nLives ); // function prototype
int main( )
{
int nLives = 9; 1
// ...
showLives( nLives ); 2
// ...
return 0;
}
void showLives( int nLives ) 3
{
cout << "You have " << nLives;
if (nLives == 1)
{
cout << " life ";
}
else
{
cout << " lives ";
}
cout << "remaining." << endl;
} 4
1 When the progra
encounters this line, the variable
nLives is created in the main() function.
2 This line is the
function call. The main() function
goes “on hold,” and the showLives() function
becomes active. The value in the parentheses is called the
argument, and it will be passed on to the function.
3
The showLives() function has one parameter, which
is a placeholder variable, a “fill-in-the-blank” for
information from
the caller. In this case, the placeholder variable is also called
nLives, and it receives a copy of the
actual parameter.
4
When the function finishes, the nLives parameter goes away
(it is out of scope), and the main()
function comes off
“hold” and continues.
These aren’t very common. The only good example that I can give
you is the rand() function. As mentioned
before, you don’t need to give it
any information, but it returns an integer to you.
These are by far the most common functions. For this example, we will have a function that takes two parameters: an object’s mass and its velocity, and returns the kinetic energy of that object (a measure of how much power it has, so to speak).
double calcEnergy( double mass, double velocity ); // prototype
int main( )
{
double mass = 0.0;
double velocity = 0.0;
double kineticEnergy = 0.0; 1
cout << "Enter mass in kg: ";
cin >> mass;
cout << "Enter velocity in m/sec: ";
cin >> velocity; 2
kineticEnergy = calcEnergy( mass, velocity ); 3 7
cout << "The kinetic energy is " << kineticEnergy << " joules." << endl;
}
double calcEnergy( double mass, double velocity ) 4
{
double result = 0.0; 5
result = (mass * velocity * velocity ) / 2.0;
return result; 6
}
main() function.
main(). Notice that parameters belong to the function where
they are declared.
result is defined. It belongs to calcEnergy()
because it is inside the function body.
return statement:
return. In this case, it’s the value of the
variable result, which is 3802.5.
kineticEnergy).
At this point, you may be wondering why we are going to all this trouble of passing parameters. The names are the same, so why are we creating duplicate copies that belong to the function? Why not use global variables to make our life easier? Why go to the trouble of returning a value to the scratch paper? Why not just change a global variable?
We could rewrite our code and make all the variables global by putting them outside both functions.
void calcEnergy( ); // prototype
double mass = 0.0;
double velocity = 0.0;
double kineticEnergy = 0.0;
int main( )
{
cout << "Enter mass in kg: ";
cin >> mass;
cout << "Enter velocity in m/sec: ";
cin >> velocity;
calcEnergy( );
cout << "The kinetic energy is " << kineticEnergy << " joules." << endl;
}
void calcEnergy( )
{
kineticEnergy = (mass * velocity * velocity ) / 2.0;
}Although the program still works, doing this is a very bad idea!
Global variables are fundamentally evil. Global constants,
on the other hand, are quite useful. If a game has many functions that all
need to know the size of the playing grid, it makes sense to declare
const int N_ROWS = 10; and
const int N_COLS = 10; rather than having
to pass those parameters to every single function. Other people can still
use your code if you are careful to put these declarations into a
header file, which they can use with a #include.
Whenever you open a block of code with a brace {, you open a new
scope. The book shows
you that you can nest scopes and create duplicate-named variables that are
in different scopes. The book says it’s not a good idea. That is wrong.
It’s a terrible idea. Something like this is just insane:
int main()
{
int var = 10;
cout << var << endl;
{
int var = 20; // new scope, new variable!
cout << var << endl;
}
cout << var << endl; // back to outer scope
return 0;
}A for loop opens a
new scope, and it’s fine to declare a counter variable whose
scope will be the loop body. If you nest loops, though, you should
never use the same variable name in both loops!
for (int i = 0 ; i < N_ROWS; i++)
{
for (int j = 0; j < N_COLS; j++) // This is OK; the variable names are different
{
grid[i][j] = 0;
}
}