COSC 1315

Programming Fundamentals

Functions

Revised:  January 28, 2007
By Richard G. Baldwin

File:  Pf00108.htm
Practice Text

Preface

This lesson was written specifically for the benefit of my students in COSC 1315, Fundamentals of Programming.  The lesson was written under the assumption that those students have no prior programming knowledge when they enroll in the course.

Which came first, the blinker switch or the car?

If you have looked into very many programming fundamentals textbooks, you may have noticed that most authors tend to defer the discussion of functions until they have discussed lots of other details about the programming language.  I disagree with that approach.

Rather than learning first about the blinker switch and later learning about the car, I believe it is best to first learn about the car and then to drill down into the details to finally learn about the blinker switch.  Therefore, my approach is to teach programming starting with the big picture and working down to the details instead of the other way around.

Functions are definitely a part of the big picture, and it is easy to understand them without having to know about the programming blinker switches.

Another browser window

I recommend that you open another copy of this document in a separate browser window so that you can view the code and the discussion of that code at the same time.

Introduction

Functions

Functions have been used in computer programming since the early days of programming.  Programming structures that resemble functions are also often called by other names such as

Calculate the square root

Suppose that your program needs to calculate the square root of a number.  Referring back to your high-school algebra book, you could refresh your memory on how to calculate a square root. 

Design the algorithm and write the code

Then you could design the algorithm describing that process.  Having the algorithm available, you could write the code to calculate the square root and insert it into your program code. 

Compile and execute your program

Then you could compile, and run your program.

If you did it all correctly, your program should correctly calculate the square root.

(For reasons that will become apparent later, I will refer to the code that you inserted into your program as in-line code.)

Oops, you need to do it all over again

Suppose that further on in your program you discover that you need to calculate the square root of another number.

And later, you discover that you need to calculate the square root of still another number.

Could copy and paste your square root code

Obviously, with a few changes, you could copy your original code that computes the square root and insert it as in-line code at each location in your program where you need to calculate the square root of a number.

Is there a better way?

After doing this a few times, you might start asking yourself if there is a better way.  The answer is "yes, there is a better way."

A function provides a better way

The better way is to create a separate program module that has the ability to calculate the square root and to make that module available for use as a helper to your main program each time your main program needs to calculate a square root.

Functions and methods

In C++, this separate program module is called a function.  In Java and C#, it is usually called a method.

Sharing the workload among different programmers

In addition to making it possible to avoid the unnecessary duplication of inline code, modularization of a large program also makes it possible to share the programming workload among the different members of a programming team.

Each member of the team can take on the task of writing one or more of the required functions.  Then every member of the programming team can use the functions written by herself and by others on the programming team.

Standard or Prewritten Functions

Most modern programming languages provide large numbers of prewritten functions (in libraries) that are available for your use.

(Later, I will illustrate the use of a standard or prewritten function for calculating the square root of a number.)

You can also write your own functions

In addition, if you need a function to perform some task for which there is no available prewritten function, you can always write your own function.

Passing Parameters

Make the function general

Normally, when designing and writing a function such as one that calculates the square root of a number, it is desirable to write it in such a way that it can calculate the square root of any number (as opposed to only one specific number).  This is accomplished through the use of something called parameters.

Passing by value or by reference

Parameters provide the mechanism by which one function can pass information to another function.

In C++, parameters can be passed to functions either by value or by reference.

(I will have more to say about this later in conjunction with the explanation of the sample programs.)

Calling (invoking) a function

The process of causing a function to be executed is commonly referred to as calling or invoking the function.

Pass me the number please

When your program calls the square root function, it will need to tell the function the value of the number for which the square root is needed.

In general, many functions will require that you provide certain kinds of information when you invoke them.  The code in the function needs this information to be able to accomplish its purpose.

Passing parameters

This process of  providing information to a function when you invoke it is commonly referred to as passing parameters to the function.

For the square root function, you need to pass a parameter whose value is the number for which you need the square root.

Returning Values

A function will usually Performing an action

An example of a function that performs an action is a function that causes the computer to emit an audible beep.  This function would not need to return an answer, because that is not the purpose of the function.  The purpose is simply to cause the computer to beep.

Returning an answer

On the other hand, a function that is designed to calculate the square root of a number needs to be able to send the square root value back to the program that called the function.

Can you keep a secret?

After all, it wouldn't be very useful if the function calculated the square root and then kept it a secret.

The process of sending back an answer is commonly referred to as returning a value.

Returned values can be ignored

When functions are designed, they can be designed in such a way that they either

When a function does return a value, the program that called the function can either

For example, in some cases where a function performs an action and also returns a value, the calling program may elect to ignore the returned value.

On the other hand, if the sole purpose of a function is to return a value, it wouldn't make much sense for a program to call that function and then ignore the value that is returned (although that would be technically possible).

Sample Programs

Prewritten functions

We will begin with a program that illustrates the use of a prewritten function for computing the square root of a number.  This program is shown in Listing 1.

/*File:  Functions01.cpp

This C++ program illustrates the use of 
prewritten functions.

This program displays the following text on the 
screen:

3.87298
4.47214
5
5.47723

************************************************/

#include <iostream>
#include <math.h> //Necessary for sqrt() function
using namespace std;

int main(){//Global main function.
  cout << sqrt(15.0) << endl;
  cout << sqrt(20.0) << endl;
  cout << sqrt(25.0) << endl;
  cout << sqrt(30.0) << endl;
  return 0;
}//end main function

Listing 1

The function named sqrt

The code in Listing 1 invokes the same function four times in succession, passing a different parameter each time, and using cout to display the returned value.

The prewritten function illustrated by Listing 1 is named sqrt.  Figure 1 shows the documentation for the sqrt function as obtained from this web site:

double  sqrt ( double x );

Calculate square root.
  Returns the square root of parameter x.

Parameters.

x
Non-negative floating point value.

Return Value.
  Square root of x.

Portability.
  Defined in ANSI-C.
  ANSI-C++ adds float and double overloaded versions of this function, with the same behavior but being both, parameter and result, of one of these types.

Figure 1

As you can see from the documentation in Figure 1, the sqrt function requires a single incoming parameter of type double.

It returns the square root of the incoming value as type double.

Must include a special header file

A program must include the header file named math.h in order to be able to access the sqrt function from the library of functions.  Thus the code to accomplish that is included in Listing 1.

Call sqrt four times

As mentioned above, the code in the main function in Listing 1:

The output

The square root value returned by the function is displayed each time it is called, producing the screen display shown below:

3.87298
4.47214
5
5.47723

Very convenient

Listing 1 illustrates the convenience of being able to call a function at multiple locations within a program to perform the same task each time that task needs to be performed.

Listing 1 also illustrates the convenience of being able to call a function that was previously written by you by or someone else without having to write the code into your program.

The main function takes no parameters and returns a value

Every C++ program that runs in a stand-alone mode requires a function named main.  Execution of the program begins and ends in the main function.

For simple programs, (which excludes event-driven programs), when the main function runs out of things to do, the program terminates.

Different formats for the main function

There are different formats that can be used for the main function in C++.  One of those formats is shown in Listing 1.  This format:

Why does it return a value of type int?

I'm not going to get into the reasons for having the main function return a value of type int here.  (That is a topic for a more advanced course.)  Suffice it to say that this requirement manifests itself in two ways in Listing 1:

Functions with no parameters and no return value

Listing 2 shows a program with two user-defined functions that take no parameters and that do not return a value.

/*File:  Functions02.cpp

This C++ program illustrates functions having no
parameters and no return value.

This program displays the following text on the 
screen:

Hello World
Goodbye cruel world

************************************************/

#include <iostream>
using namespace std;

//A function prototype is required due to the
// placement of the goodbye function relative
// to the main function.  The main function
// requires the prototype in order to understand
// the interface to the goodbye function, which
// has not yet been defined when it is called.
void goodbye();//function prototype

//No function prototype is required for the
// hello function because it is defined before it
// is called.
void hello(){
  cout << "Hello World" << endl;
}//end hello
//---------------------------------------------//

int main(){//Global main function.
  hello();
  goodbye();
  return 0;
}//end main function
//---------------------------------------------//

void goodbye(){
  cout << "Goodbye cruel world" << endl;
}//end goodbye

Listing 2

General syntax for a function

The general syntax for a function consists of two main parts:

The function signature

The function signature consists of:

The formal parameter list

The formal parameter list is empty if the function requires no parameters.

That is the case for all three functions in Listing 2Otherwise, the formal parameter list would contain one or more pairs of words separated by commas.

The parameter declaration

Each pair of words in the formal parameter list (a parameter declaration) consists of the following:

(As you will see later in Listing 4, the formal parameter list may also contain the reference operator & for those cases where parameters are passed by reference.)

Additional sample programs

I will explain a sample program later in this lesson where the formal parameter list is not empty.

I will also explain a sample program where the formal parameter list contains the reference operator &.

C++ code is sensitive to position

C++ code is sensitive to the relative locations of function definitions and the code that calls the functions.

In order for C++ code to successfully call a function, the function must have either been:

A function prototype

A function prototype is used to declare a function to make it possible for code to call the function before it is actually defined.  I will explain the syntax of a function prototype later.

main function calls two other functions

The code in the main function in Listing 2 calls two other functions:

Before

The hello function is physically defined ahead of the main function in Listing 2

Therefore, a function prototype is not required for the main function to be able to call the hello function.

After

The goodbye function is physically defined after of the main function in Listing 2.

Therefore, it was necessary to provide a function prototype to declare the goodbye function in Listing 2 in a location that is physically ahead of the definition of the main function.

Otherwise, the main function would be unable to call the goodbye function.

Syntax of the function prototype

The prototype for a function essentially consists of the signature of the function followed immediately by a semicolon instead of a body.

However, the names of the parameters may be omitted from the function prototype whereas the signature must always provide names for the parameters. 

On the other hand, it is not necessary to omit the parameter names from the function prototype.

No parameters or return value required

The functions named hello and goodbye in Listing 2 perform a simple action.

Each function simply displays a message on the screen when called.

These two functions don't require incoming parameters to accomplish their purpose, and they don't return a value.

Transfer the flow of control to the hello function

The main function calls the hello function first.  This causes the flow of control in the program to pass from the main function to the hello function.

The hello function displays a message on the screen and then terminates.

Return control to the main function

When the hello function terminates,  control is returned to the main function without returning a value in the process.

Hello World

The message that is displayed on the screen by the function named hello consists of the following line of text:

Hello World

Transfer flow of control to the goodbye function

When control is returned to the main function from the hello function, the main function calls the goodbye function passing the flow of control to the goodbye function in the process.

The goodbye function displays the following text on the screen:

Goodbye cruel world

Then the goodbye function terminates, returning control to the main function without returning a value in the process.

Terminate the program

When the flow of control returns to the main function from the goodbye function, there is nothing more for the main function to do.

At that point, the main function terminates, returning a value of 0 to the operating system in the process.

When the main function terminates, the program terminates.

Functions with value parameters and no return value

C++ allows a parameter to be passed to a function either by value or by reference.  The difference can be very significant as will be illustrated by Listing 3 and Listing 4.

Passing a copy of a variable

When a program passes a variable as a parameter to a function by value

The function can do just about anything that it wants to do with the incoming parameter.

Cannot modify the original variable

However, the one thing that it cannot do with the parameter is to modify the contents of the original variable.

If it modifies the value of the parameter, it simply modifies the copy and doesn't modify the value of the original variable.

Passing an address

When a program passes a variable to a function by reference, that variable's address in memory is passed to the function.

(Maybe it is a copy of the address, but the result is the same in either case.)

Once again, the code in the function can do just about anything that it wants to do with the incoming parameter.

Can modify the original variable

For example, the code in the function can use the address to find and to modify the value stored in the original variable.

(All of the complex address manipulations take place behind the scenes requiring no special effort on the part of the programmer to modify the value stored in the original variable.)

Important

When a variable is passed by reference, if the function modifies the value of the incoming parameter, it doesn't modify the address.

Rather, some complex address manipulations take place behind the scenes causing the code to actually modify the value stored at that address in memory.

This modifies the value stored in the original variable.  This will be illustrated later in Listing 4.  First, however, we will illustrate the concept of pass by value.

Passing parameters by value

Listing 3 contains a program that illustrates passing two parameters of different types to a function by value.

/*File:  Functions03.cpp

This C++ program illustrates functions with value
parameters and no return value

This program displays the following text on the 
screen:

In main
a = 10 b = 20.1
In aFunction
x = 10 y = 20.1
Change x and y
Still in aFunction
x = 100 y = 200.1
Back in main
a = 10 b = 20.1

************************************************/

#include <iostream>
using namespace std;

void aFunction(int x,double y){
  cout << "In aFunction" << endl;
  cout << "x = " << x << " y = " << y << endl;
  cout << "Change x and y" << endl;
  x = 100;
  y = 200.1;
  cout << "Still in aFunction" << endl;
  cout << "x = " << x << " y = " << y << endl;
}//end aFunction
//---------------------------------------------//

int main(){//Global main function.
  cout << "In main" << endl;
  int a = 10;
  double b = 20.1;
  cout << "a = " << a << " b = " << b << endl;
  aFunction(a,b);
  cout << "Back in main" << endl;
  cout << "a = " << a << " b = " << b << endl;
  return 0;
}//end main function

Listing 3

Behavior of the main function

The main function in Listing 3 declares and initializes two local variables named a and b.

(I will provide an explanation of the different kinds of variables, including local variables, in a future lesson.  For now, just think of a local variable as a pigeonhole in memory where a value is stored.)

The types of the two variables are int and double respectively.

(I will also provide more information about the types of variables such as int and double in a future lesson.  For now, a variable of type int can contain whole numbers only, such as 9 or 3642.  A variable of type double can contain values with fractional parts, such as 1.333.)

Display the variables

Then the main function displays the values contained in the two variables producing the following output on the screen:

In main
a = 10 b = 20.1

(Note how insertion operators can be concatenated to cause multiple items to be displayed on the same line.)

Call the function named aFunction

Following that, the main function calls the function named aFunction passing the variables named a and b to the function by value.

The formal parameter list versus the actual parameter list

This will be a good place to discuss the difference between the formal parameter list and the actual parameter list.

As explained earlier, the formal parameter list is part of the function signature, which in this case looks like this:

void aFunction(int x,double y)

The formal parameter list is shown in boldface in the above function signature.

The actual parameter list

The actual parameter list is part of a function call, which in this case looks like this:

aFunction(a,b);

The actual parameter list is highlighted in boldface in the above function call.

How do they differ?

By comparing the two, you can see that:

Display, modify, and display the parameters

When the main method calls aFunction, control is transferred to the function.

The code in the function named aFunction:

The output from aFunction

The function named aFunction produces the following output on the screen:

In aFunction
x = 10 y = 20.1
Change x and y
Still in aFunction
x = 100 y = 200.1

Display the variables again

When control returns to the main function, the main function once again displays the values contained in the two variables that were passed to the function by value.

The output from the main function

This produces the following screen output:

Back in main
a = 10 b = 20.1

The important point is that even though the code in the function named aFunction modified the values of its incoming parameters, this had no effect on the values stored in the variables that were passed by value to the function named aFunction.

Functions with reference parameters and no return value

The program in Listing 4 is identical to the previously-discussed program in Listing 3 with one exception.

The important exception

The exception is the inclusion of the reference operator & in front of the x in the formal parameter list for the function named aFunction.

Not a trivial change

This is not a trivial change.  It produces a major difference in the behavior of this program relative to the previous program.

/*File:  Functions04.cpp

This C++ program illustrates functions with value
parameters, reference parameters, and no return 
value

This program displays the following text on the 
screen:

In main
a = 10 b = 20.1
In aFunction
x = 10 y = 20.1
Change x and y
Still in aFunction
x = 100 y = 200.1
Back in main
a = 100 b = 20.1

************************************************/

#include <iostream>
using namespace std;

//Note that the first parameter is a reference
// parameter.
void aFunction(int &x,double y){
  cout << "In aFunction" << endl;
  cout << "x = " << x << " y = " << y << endl;
  cout << "Change x and y" << endl;
  x = 100;
  y = 200.1;
  cout << "Still in aFunction" << endl;
  cout << "x = " << x << " y = " << y << endl;
}//end aFunction
//---------------------------------------------//

int main(){//Global main function.
  cout << "In main" << endl;
  int a = 10;
  double b = 20.1;
  cout << "a = " << a << " b = " << b << endl;
  aFunction(a,b);
  cout << "Back in main" << endl;
  cout << "a = " << a << " b = " << b << endl;
  return 0;
}//end main function

Listing 4

First parameter will be pass by reference

The inclusion of the & in front of the parameter name in the formal parameter list specifies that the first parameter named x in the formal parameter list will be passed to the function by reference.

Second parameter will be passed by value

The absence of a similar & with the second parameter specifies that the second parameter will be passed by value as before.

Otherwise, the code in the function named aFunction and the code in the function named main is exactly the same as in the program discussed earlier in conjunction with Listing 3.

Changing the value stored in the original variable

As a result of passing the first parameter to the function by reference -

When the code in aFunction changes the value of the first parameter from 10 to 100 -

That actually changes the value stored in the variable named a that was passed by reference to the function.

The program output

The output produced by the program is shown below:

In main
a = 10 b = 20.1
In aFunction
x = 10 y = 20.1
Change x and y
Still in aFunction
x = 100 y = 200.1
Back in main
a = 100 b = 20.1

The important difference between this output and the output produced by the previous program is highlighted in boldface. 

To reiterate, changing the value of a parameter that was passed by reference changes the value stored in the variable that was passed by reference.

Functions with parameters and a return value

Listing 5 illustrates a program that receives a single incoming parameter by value and returns a value.

(This structure is similar to the sqrt function discussed earlier.)

/*File:  Functions05.cpp

This C++ program illustrates a function with
a parameter and a return value.

This program displays the following text on the 
screen:

a = 2
a doubled = 4

************************************************/

#include <iostream>
using namespace std;

int doubleIt(int x){
  return x + x;
}//end doubleIt
//---------------------------------------------//

int main(){//Global main function.
  int a = 2;
  cout << "a = " << a << endl;
  cout << "a doubled = " << doubleIt(a) << endl;
  return 0;
}//end main function

Listing 5

Behavior of the function named doubleIt

The behavior of the function named doubleIt is very simple.  It returns a value that is double the value that it receives.  It computes that return value by adding the incoming value to itself and returning the sum.

Important changes to the code

The most important thing to note about the code in Listing 5 is the following:

Otherwise, the program in Listing 5 is straightforward.

Compatibility issue

If you replace the return statement in the function named doubleIt with either of the following statements, the program will still compile and run successfully using Dev C++ v4.9.9.2 running under WinXP Pro.  (This is apparently some kind of a coding shortcut that has been incorporated into Dev C++.)  However, the compilation will fail using MS VS 6.0 running under WinXP Pro.

int y = x + x;
x + x;

This illustrates some of the compatibility issues that you can expect to encounter when working with C++.

The output

The screen output produced by the program is

a = 2
a doubled = 4

Global functions

The functions illustrated in this lesson are all global functions.  That is to say, they are defined outside of a class and are accessible by any code in the program that knows the name of the function.

The use of global functions is not allowed in more modern object-oriented programming languages such as Java and C#.

(Programmers tend to call them methods instead of functions in Java and C#.)

However, functions or methods can be defined inside of classes in C++, Java, and C#, and what you have learned in this lesson is directly applicable to the use of functions or methods that are defined inside of classes.


Copyright 2005, Richard G. Baldwin.  Reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.

About the author

Richard Baldwin is a college professor (at Austin Community College in Austin, TX) and private consultant whose primary focus is a combination of Java, C#, and XML. In addition to the many platform and/or language independent benefits of Java and C# applications, he believes that a combination of Java, C#, and XML will become the primary driving force in the delivery of structured information on the Web.

Richard has participated in numerous consulting projects and he frequently provides onsite training at the high-tech companies located in and around Austin, Texas.  He is the author of Baldwin's Programming Tutorials, which have gained a worldwide following among experienced and aspiring programmers. He has also published articles in JavaPro magazine.

In addition to his programming expertise, Richard has many years of practical experience in Digital Signal Processing (DSP).  His first job after he earned his Bachelor's degree was doing DSP in the Seismic Research Department of Texas Instruments.  (TI is still a world leader in DSP.)  In the following years, he applied his programming and DSP expertise to other interesting areas including sonar and underwater acoustics.

Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.

Baldwin@DickBaldwin.com

-end-