Logical Groups or: Why We Use Functions

When designing large programs, it was noticed that a segment of code was often used more than once during the program. And in very large programs, there might be more than one of these repeated segments. In the following 'diagram', each letter represents a small segment/fragment of code:

   A, B, C, B, C, A, D, E, B, C, F, G, C, H, I, A, B, C, D, J, H, ...

Note how the code segments labeled B and C occur many times — often together. A is also repeated several times. See:

   A, B, C, B, C, A, D, E, B, C, F, G, C, H, I, A, B, C, D, J, H, ...
   -  -  -  -  -  -  -     -  -        -  -     -  -  -  -     -
      ----  ----           ----                    ----
   -------                                      -------

So H appears twice. A appears three times (twice in an ABC group). B appears four times (always in a BC group). And C appears five times (once by itself). Finally D also appears twice.

By grouping such segments of code together in a common place, we can avoid writing them several times. Instead, we just refer to them when the point in the program comes where we would have re-typed them. This grouping is known as creating (or extracting) a module (or function). When we refer to the module, we are invoking (or calling) it — asking it to do its job at this time.

When grouped into functions, the above code might look like:

   S:  A
   T:  B
   U:  C
   W:  D
   X:  H
   Y:  T, U        // B, C
   Z:  S, Y        // A, B, C

   Z, Y, S, W, E, Y, F, G, U, X, I, Z, W, J, X, ...

Notice how much shorter the sequence is now. (Also remember that each letter here stands for a group of logically connected statements — not necessarily just a single statement. And what's more, the statements don't have to be extremely simple assignment, input, or output — they can be branches or loops or calls to other functions!)

While this may look more complicated, forming functions this way actually allows us many benefits:

Many Hats

Up until now, you have thought of yourself as just a single individual. However, in reality, you've been two people since this class began. As a programmer, you are both the application coder as well as the application tester. You perform the role of end-user when the testing phase of a programming project is at hand.

With the advent of functions, you will become two more people (sort of). You will still be the application coder and tester, but you will also be the coder of and caller of functions. As mentioned above, coding functions is fairly simple — you get to concentrate on one simple task. This is because when you code a function, you aren't concerned with how it will be used in an application. You are only concerned that the function performs its duty well.

Then, when that is done, you switch hats back to the application coder. Now you are concerned with how you will use this function in your application. You are the function caller as well as the application coder.

Don't get confused between function caller and end-user. One is a programmer who is re-using code written by someone (maybe herself, maybe not). The other is some schmuck who's bought your program and is trying to run it.

Inputs vs. Outputs

In computer terms, input means values needed before a calculation can be carried out. Likewise, output means value(s) produced from such calculations.

One thing that causes problems at this point for many people is that no longer are all inputs coming from the keyboard and all outputs going to the screen. A function often gets information from the function caller (the programmer who is calling it). Such information is known as function input. Functions also often return information to the caller. This information is known as function output.

To make the distinction between console and function I/O more clear, let's settle on the following definitions:

Again, function I/O is information passed to/from a function and some calling part of the program (some other function). Console I/O is information passed across the program boundary to/from the user.

Function Head: Prototype and Definition

In any programming language you need to describe to the compiler what your function looks like to those who call it. In other words, you need to show it somehow what inputs and what output your function expects/provides. Since it is just a machine, it doesn't care about semantics — it doesn't care about the meaning of the inputs and output. It only cares about the types (short, char, etc.) and the order in which they are listed. The compiler also needs to know a name by which your function will be called.

To group all of these things together, the language designers formed the function header. The header of a function starts with the type of the output from the function. Then comes the function's name. Finally comes a parenthesized, comma-separated list of inputs. In computer language terms, an input is called an argument and an output is called a return value. An argument typically consists of both a type and a name. The type is for the compiler to know what types of inputs to expect. The name is so those calling your function can know the meaning of the inputs. For instance, it is legal for a function to have a header such as:

   double pow(double, double)

But this is difficult to understand. We know that the function is known as pow and that it will return a double. We also know that it will accept two inputs of type double. But we have no idea what those two inputs mean — what they are. It makes much more sense to human programmers trying to call the function to know that the first input is a number and the second input is the power to which the number is to be taken:

   double pow(double base, double exponent)

We might even want to put a comment on such a function to make sure we are understood:

   // Function pow takes a base and exponent and returns the base
   // taken to the exponent power:
   // 
   //           exponent
   //       base
   // 
   double pow(double base, double exponent)

Now, to put this together, we need to tell the compiler HOW to actually perform this operation. For this we need to do as we've been doing with main all along: give it a function body. This is known as a function definition. It is the header of the function followed by a brace-enclosed series of statements which end in a return statement:

   // Function pow takes a base and exponent and returns the base
   // taken to the exponent power:
   // 
   //           exponent
   //       base
   // 
   double pow(double base, double exponent)
   {
      double power;
      // code to raise base to the exponent'th power
      return power;
   }

Notice that here we are returning the value of a local variable. This variable will exist only within this function and therefore won't interfere with other variables in other functions which happen to have the same name. (You would replace the comment in the body with actual code, of course; but this isn't necessary to our purpose here.)

If you use a Pascal-style layout for your program, you can put the function definitions before the functions are called and all will work perfectly well. However, in a C-style program layout, the function definitions all follow main. In order for the compiler to know what is going on before a function gets called, we must introduce it to the function in some way. It need not know the entire definition of the function before it is called (one of the magic things about the compiler), but it does need to know what the header looks like. So, we place the header above main so that it might understand the call(s) to the function that it will see in main. But it would look funny to have those headers up there on lines alone. So we append a semi-colon to the end of them and call them a prototype (a function declaration, if you will):

   // Function pow takes a base and exponent and returns the base
   // taken to the exponent power:
   // 
   //           exponent
   //       base
   // 
   double pow(double base, double exponent);

Types Used With Functions

Any of the normal types (short, float, long, char, etc.) can be used with input or output types. There is, in addition a special type to be used with special functions that require no input from their caller or return no output to their caller: void. A void in the real world is like a vacuum — empty, devoid, lacking. Therefore, what you are saying by using the type void is that there is nothing coming in (or going out):

   void func_name(type arg, type arg, ...)        // function that
                                                  // returns nothing

   ret_type func_name(void)                       // function that
                                                  // takes nothing

   void func_name(void)                           // function that
                                                  // neither takes
                                                  // nor returns
                                                  // anything

Function Design

Some people worry that they'll never understand all of this function nonsense. Balderdash! It just takes time. How long did it take you to learn to tie your shoes? Ride a bike? Walk and chew gum at the same time? Learning any new skill takes time and practice! But, here are a few tips to make your learning (hopefully) easier:

Calling Functions: Actual vs. Formal Arguments

Calling a function in C++ is done much like calling a function in algebra. To call the function pow mentioned above, for instance, you would do something like:

   double result, base, exponent;
   base = 2.0;
   exponent = 3.0;
   result = pow(base, exponent);   // result gets 8.0 assigned to it

Note that this looks much like the algebra expression y = f(x). The primary difference is that in C++, functions can take many arguments or no arguments; or they might even return no value. The calls all look similar:

   void print_greeting(void);
   short get_short(void);
   short twice(short x);
   void print_answer(short y);

   int main(void)
   {
      short x, y;
      print_greeting();
      x = get_short();
      y = twice(x);
      print_answer(y);
      return 0;
   }

   // function definitions here

Note that there are no types listed in the function calls. Only the variables (if any) are mentioned — not their types. This is because the compiler already knows the types of the variables and it also knows the types of the arguments. Since they match, all is well.

Note also one very important point: you must always have a set of parentheses on a function call — even if they are empty! To store a returned value, you must use an assignment statement. If, on the other hand, you don't care to store the value, but merely want to use it, you can do things like:

   void print_greeting(void);
   short get_short(void);
   short twice(short x);
   void print_answer(short y);

   int main(void)
   {
      print_greeting();
      print_answer(twice(get_short()));
      return 0;
   }

   // function definitions here

In other words, pass the result of the inner-most function to the next outer function as an argument. This is known as function call nesting. You've probably seen it in algebra: y = f(g(x)). It saves on variable space, but can make things more difficult to read.

It does bring up a good point, though. twice is expecting a short named x, but here it gets some result from get_short. This result happens to be a short, but it doesn't really have a name (unless you want to call it get_short). And yet this code works just fine. That implies to us that it isn't the names of arguments that matter to the compiler. Indeed, it is only the type of the argument and the position of the argument within the argument list that determines what is what to the compiler. It ignores names. So we could re-write our first function call example in several ways. One is to call the function with differently named variables:

   double result, x, y;
   x = 2.0;
   y = 3.0;
   result = pow(x, y);   // result gets 8.0 assigned to it

It doesn't matter to pow that the arguments that it gets are of a different name than the ones it expects. This is the difference between actual arguments (those provided by the caller) and formal arguments (those expected by the function). The arguments in a function's header (formal ones) are merely local names for values that the caller sends. This allows the function to work in widely ranging applications.

Note that this is similar to algebra where it didn't matter what value you passed to f(x), it would still give the correct answer. x was just a variable whose value could change. We could have equally well used the variable u or maybe one called t.

The compiler merely looks at the actual argument list and the formal one and matches the arguments up by position and type. If all works out, it makes the call — copying the values from the actual arguments into the formal ones:

 //double       double              double
   result = pow(x,                  y);
   double   pow(double base, double exponent);

It notes that the first actual argument is a double and that the corresponding formal argument is also a double: good. Then it looks at the next argument: again, double lines up with double. Now it copies the value of the first actual argument (x) into the first formal argument (base) and likewise with the second actual and formal arguments (y & exponent). Now, when pow executes, base will have the same value as x and exponent will have the same value as y. Thus, the returned value will still be the result of raising x to the yth power — even though the names don't match exactly.

Oh, and on returning, the compiler notes that the answer that pow returns is of type double and that the variable being assigned this value (result) is also of type double and so the assignment works fine, too.

Some other ways to call functions are also now evident (since the names don't matter):

   ans = pow(x, y);                         // result name doesn't matter
   ans = pow(x, 4.0);                       // literal instead of variable
   ans = pow(4.0, y);                       // same, but other argument
   ans = pow(x, y*4);                       // expression instead of variable
   ans = pow(x*3, 4);                       // expression instead of variable
                                            // and literal for other argument
   cout << pow(x, y) << endl;               // nest function call in printing
                                            // call

Thus, the fact that names of arguments don't matter to the compiler gives the function call mechanism MUCH more power than it could otherwise have (no pun intended).

For another complete example, see the examples section. Also check out the notes there — especially the dataflow diagram!

Fancy Arguments

Reference Arguments

Up until now, we've been limited to returning one or no values from our functions. In math this was always the case, but in C++ it doesn't have to be. Programming is all about simulating real-world processes, after all; and tasks in the real world often have more than one result. So, C++ allows a mechanism to return multiple values from a function. However, it doesn't use the return value to do it. It uses a modification to the argument list for returning multiple values:

   void get_coordinate(double & x, double & y);

This function would take two arguments into itself which were not for input, but for output. The & placed between the type and name of the arguments says that these arguments are actually for output — not input. What it means is that no values are copied, but the actual variable's memory space is accessed by the function:

   void get_coordinate(double & x, double & y);

   int main(void)
   {
      double x, y;
      get_coordinate(x, y);
      cout << "You entered (" << x << ", "
           << y << ")." << endl;
      return 0;
   }

   void get_coordinate(double & x, double & y)
   {
      char t;
      cin >> t >> x >> t >> y >> t;
      return;
   }

Note how the return statement is empty even though we have two outputs. This is because the return statement matches with the return value (void) and not with the number of outputs. Also note that the names still don't have to match, even though we are really passing the actual argument's memory space to the formal argument:

   void get_coordinate(double & x, double & y);

   int main(void)
   {
      double point1_x, point1_y, point2_x, point2_y;
      get_coordinate(point1_x, point1_y);
      get_coordinate(point2_x, point2_y);
      cout << "Travelling from (" << point1_x << ", "
           << point1_y << ") to (" point2_x << ", "
           << point2_y << ")." << endl;
      return 0;
   }

   void get_coordinate(double & x, double & y)
   {
      char t;
      cin >> t >> x >> t >> y >> t;
      return;
   }

See how we called the function twice to do our bidding — even with different actual arguments!

But, notice how the get_coordinate function gives the same prompt for both the starting point and the ending point? We can fix this by altering the main slightly:

   void get_coordinate(double & x, double & y);

   int main(void)
   {
      double point1_x, point1_y, point2_x, point2_y;
      cout << "First I need your starting point:" << endl;
      get_coordinate(point1_x, point1_y);
      cout << "Now I need your destination point:" << endl;
      get_coordinate(point2_x, point2_y);
      cout << "Travelling from (" << point1_x << ", "
           << point1_y << ") to (" point2_x << ", "
           << point2_y << ")." << endl;
      return 0;
   }

   void get_coordinate(double & x, double & y)
   {
      char t;
      cin >> t >> x >> t >> y >> t;
      return;
   }

Now the user will see that the first XY coordinate is for a starting point and the second one is for a destination point — and we didn't even change the function itself!

Please note, though, that reference arguments (as those with the & are called) MUST be variables. They cannot be literal values.

Default Arguments

Another fancy thing you can do with arguments is with input arguments. Often in the real world, there are certain values that occur over and over. It would be tedious if the caller had to enter these values into their input list (actual argument list) all the time. It would be nice if they could just let some default value be there. Well, they can!

To do this, you merely place [what appears to be] an assignment on the formal argument:

   bool flip(double heads = 0.5);

Here we have a function that flips a 2-sided coin and returns true if it is heads and false if it is tails. Since fair coins are by-and-large the default in the real world, we have set the argument (a percent chance of a head occuring) to be 0.5 by default. This function might be defined as:

   bool flip(double heads)
   {
      return (rand()%1001/1000.0) >= heads;
   }

Notice how the default value doesn't appear here in the definition — it was only in the prototype. The compiler doesn't like to see default values more than once. So, only place it in the first place it sees (the prototype).

How does this affect calling the function? Well we could now call flip as:

   bool result;

   result = flip(0.5);             // pass 0.5 as heads
   // or
   result = flip();                // let argument default to 0.5
   // or
   result = flip(0.7);             // pass 0.7 as heads — unfair coin

Thus, the function flip can now have no or one input arguments. If it receives none, its formal argument heads will have the value 0.5. If it receives an actual argument, however, the formal argument will get a copy of that actual arguments' value (as normal).

Of course, there is a caveat: default arguments must be filled in from right to left in the argument list. So, you have to have default arguments at the end of your argument list and have the ones most likely to be changed further left within the default arguments.

Also, don't use default arguments just because you feel like it. Only use them when there is a value that will be sent to you more than half the time. If a value is likely to be different almost every time the function is called, it will not make a useful default argument.

Fancy Functions: Overloading

Normally the compiler only likes having one thing visible with a certain name at once — otherwise it doesn't know to which you are referring. For instance, this code will fail utterly:

   #include <iostream>
   #include <cmath>

   using namespace std;

   int main(void)
   {
      double pow, x, y;
      cout << "Enter base and exponent:  ";
      cin >> x >> y;
      pow = pow(x, y);
      cout << "Result is " << pow << "." << endl;
      return 0;
   }

This is because the compiler cannot distinguish between the function pow (from the math library) and the local variable pow (used to store the result).

However, there are circumstances when the compiler can recognize multiple things with the same name. This occurs when all the things are functions. The caveat: the functions must differ in the number or types of arguments (be they input or output arguments). This can come in handy when you want to have the same name for a function that works on different types of data in a similar way:

   double calc_area(double radius);                   // circle area
   double calc_area(double width, double length);     // rectangle area
   double calc_area(double width, double length,      // rectangular solid
                    double height);                   // surface area

All of these could be distinguished because they have a different number of arguments. However, remember that the compiler ignores argument names (for the most part) and so you couldn't add:

   double calc_area(double base, double height);      // triangle area

To the mix above as it is indistinguishable to the compiler from the rectangular calc_area function (two double arguments).

Many of you have witnessed overloading in action when you tried to call the pow function from your distance function in lab:

   double distance(short x1, short x2, short y1, short y2)
   {
      return sqrt(pow(x1-x2,2)+pow(y1-y2,2));
   }

Gave many of you errors saying that the compiler couldn't decide between the functions: double pow(double,double) and long pow(long,long). This means that the cmath library has already overloaded the pow function for both double arguments and long arguments. Since short can be converted equally well to both long and double, the compiler got confused as to which you wanted. So you had to let it know by changing the 2 (exponent) to a double:

   double distance(short x1, short x2, short y1, short y2)
   {
      return sqrt(pow(x1-x2,2.0)+pow(y1-y2,2.0));
   }

Or by changing your arguments to doubles:

   double distance(double x1, double x2, double y1, double y2)
   {
      return sqrt(pow(x1-x2,2)+pow(y1-y2,2));
   }

Or both:

   double distance(double x1, double x2, double y1, double y2)
   {
      return sqrt(pow(x1-x2,2.0)+pow(y1-y2,2.0));
   }

So that it would, indeed, call the double version of pow.

For another example of reference arguments and overloading, see the examples section.

Function Call Mechanism Workings

As mentioned above, when actual arguments are passed into formal arguments, the values of the actual arguments are copied into the formal arguments. This implies that the formal arguments get their own memory space. Indeed, this is true. Let's examine the following program:

   #include <iostream>
   #include <cmath>

   using namespace std;

   void get_coordinate(double & x, double & y);
   double distance(double x1, double y1, double x2, double y2);

   int main(void)
   {
      double start_x, start_y,             // starting position
             end_x, end_y,                 // ending position
             dist_between;                 // distance between start
                                           // and end positions

      cout << "First enter information about where you'll be starting:"
           << endl;
      get_coordinate(start_x, start_y);
      cout << "Next enter information about where you'll be ending:"
           << endl;
      get_coordinate(end_x, end_y);

      dist_between = distance(start_x, start_y, end_x, end_y);

      cout << "While travelling from (" << start_x << ", "
           << start_y << ") to (" end_x << ", "
           << end_y << ")\nyou'll go "
           << dist_between << " miles." << endl;

      return 0;
   }

   double distance(double x1, double y1, double x2, double y2)
   {
      return sqrt( pow(x1-x2, 2.0) + pow(y1-y2, 2.0) );
   }

   void get_coordinate(double & x, double & y)
   {
      char t;
      cin >> t >> x >> t >> y >> t;

      return;
   }

In memory, main looks something like this:

 +--------------------------------------------------------------+
 |      +------------+                                          |
 | main |            |                                          |
 |      +------------+                                          |
 +--------------------------------------------------------------+
 |         +------------+                +------------+         |
 | start_x |            |        start_y |            |         |
 |         +------------+                +------------+         |
 |         +------------+                +------------+         |
 |   end_x |            |          end_y |            |         |
 |         +------------+                +------------+         |
 |              +------------+                                  |
 | dist_between |            |                                  |
 |              +------------+                                  |
 +--------------------------------------------------------------+

Each variable has its own box and main has a box for its return value.

Let's assume for the moment that all coordinates have been read in already. Let's look at how the distance function is called to calculate the distance between our two points. First, before the call, memory might look like this:

 +--------------------------------------------------------------+
 |      +------------+                                          |
 | main |            |                                          |
 |      +------------+                                          |
 +--------------------------------------------------------------+
 |         +------------+                +------------+         |
 | start_x |     42     |        start_y |      2     |         |
 |         +------------+                +------------+         |
 |         +------------+                +------------+         |
 |   end_x |     42     |          end_y |     12     |         |
 |         +------------+                +------------+         |
 |              +------------+                                  |
 | dist_between |            |                                  |
 |              +------------+                                  |
 +--------------------------------------------------------------+

During the call, the actual arguments are lined up with the formal arguments and the values are copied position-wise from left to right:

   distance(       start_x,        start_y,         end_x,        end_y);
                   ||              ||               ||            ||
                   \/              \/               \/            \/
   distance(double x1,      double y1,       double x2,    double y2);

Now distance is fleshed out in memory as:

 +--------------------------------------------------------------+
 |      +------------+                                          |
 | main |            |                                          |
 |      +------------+                                          |
 +--------------------------------------------------------------+
 |         +------------+                +------------+         |
 | start_x |     42     |        start_y |      2     |         |
 |         +------------+                +------------+         |
 |         +------------+                +------------+         |
 |   end_x |     42     |          end_y |     12     |         |
 |         +------------+                +------------+         |
 |              +------------+                                  |
 | dist_between |            |                                  |
 |              +------------+                                  |
 +--------------------------------------------------------------+
 +--------------------------------------------------------------+
 |          +------------+                                      |
 | distance |            |                                      |
 |          +------------+                                      |
 +--------------------------------------------------------------+
 |         +------------+                +------------+         |
 |      x1 |     42     |             y1 |      2     |         |
 |         +------------+                +------------+         |
 |         +------------+                +------------+         |
 |      x2 |     42     |             y2 |     12     |         |
 |         +------------+                +------------+         |
 +--------------------------------------------------------------+

With the values copied appropriately into new memory locations.

Now the return value of distance is calculated as 10.0 and stored in the box next to it. Also, all local memory space (formal arguments included) is wiped:

 +--------------------------------------------------------------+
 |      +------------+                                          |
 | main |            |                                          |
 |      +------------+                                          |
 +--------------------------------------------------------------+
 |         +------------+                +------------+         |
 | start_x |     42     |        start_y |      2     |         |
 |         +------------+                +------------+         |
 |         +------------+                +------------+         |
 |   end_x |     42     |          end_y |     12     |         |
 |         +------------+                +------------+         |
 |              +------------+                                  |
 | dist_between |            |                                  |
 |              +------------+                                  |
 +--------------------------------------------------------------+
 +--------------------------------------------------------------+
 |          +------------+                                      |
 | distance |    10      |                                      |
 |          +------------+                                      |
 +--------------------------------------------------------------+

Next the assignment in main copies the 10.0 from distance to the local variable dist_between and distance is wiped:

 +--------------------------------------------------------------+
 |      +------------+                                          |
 | main |            |                                          |
 |      +------------+                                          |
 +--------------------------------------------------------------+
 |         +------------+                +------------+         |
 | start_x |     42     |        start_y |      2     |         |
 |         +------------+                +------------+         |
 |         +------------+                +------------+         |
 |   end_x |     42     |          end_y |     12     |         |
 |         +------------+                +------------+         |
 |              +------------+                                  |
 | dist_between |     10     |                                  |
 |              +------------+                                  |
 +--------------------------------------------------------------+

Next the last cout sends its information to the screen:

   While travelling from (42, 2) to (42, 12)
   you'll go 10 miles.

Finally the return in main puts a 0 in the box on main and main's variables are wiped:

 +--------------------------------------------------------------+
 |      +------------+                                          |
 | main |      0     |                                          |
 |      +------------+                                          |
 +--------------------------------------------------------------+

When the operating system retrieves this value, main itself will be wiped. (At this point you'll return to the OS prompt.)

But what about get_coordinate? How did we get those points in the first place? Well, the arguments on get_coordinate are reference arguments (outputs) and act differently from your garden-variety input argument. An output argument merely refers back to space allocated for the actual argument. In other words, it doesn't get its own memory space, but merely uses someone else's. So, when get_coordinate is called for the first time, it lines up as:

    get_coordinate(        start_x,         start_y);
                           /\               /\
                           ||               ||
                           \/               \/
    get_coordinate(double & x,      double & y);

(Note how the arrow goes both ways to show they are linked — not just copied.) Then, in memory, get_coordinate will look something like this:

     +--------------------------------------------------------+
     |      +------------+                                    |
     | main |            |                                    |
     |      +------------+                                    |
     +--------------------------------------------------------+
     |         +------------+                +------------+   |
 |---|>start_x |            |        start_y |            |<--|---|
 |   |         +------------+                +------------+   |   |
 |   |         +------------+                +------------+   |   |
 |   |   end_x |            |          end_y |            |   |   |
 |   |         +------------+                +------------+   |   |
 |   |              +------------+                            |   |
 |   | dist_between |            |                            |   |
 |   |              +------------+                            |   |
 |   +--------------------------------------------------------+   |
 |   +--------------------------------------------------------+   |
 |   |                                                        |   |
 |   | get_coordinate                                         |   |
 |   |                                                        |   |
 |   +--------------------------------------------------------+   |
 |   |                                                        |   |
 |---|-------x                             y------------------|---|
     |                                                        |
     +--------------------------------------------------------+

This shows that anything that happens to x within get_coordinate is immediately reflected in the referred actual argument (start_x) in the calling function (main). Likewise for y and start_y. Thus, when the user enters 42 2, we see something like this in memory:

     +--------------------------------------------------------+
     |      +------------+                                    |
     | main |            |                                    |
     |      +------------+                                    |
     +--------------------------------------------------------+
     |         +------------+                +------------+   |
 |---|>start_x |     42     |        start_y |      2     |<--|---|
 |   |         +------------+                +------------+   |   |
 |   |         +------------+                +------------+   |   |
 |   |   end_x |            |          end_y |            |   |   |
 |   |         +------------+                +------------+   |   |
 |   |              +------------+                            |   |
 |   | dist_between |            |                            |   |
 |   |              +------------+                            |   |
 |   +--------------------------------------------------------+   |
 |   +--------------------------------------------------------+   |
 |   |                                                        |   |
 |   | get_coordinate                                         |   |
 |   |                                                        |   |
 |   +--------------------------------------------------------+   |
 |   |                                                        |   |
 |---|-------x                             y------------------|---|
     |                                                        |
     +--------------------------------------------------------+

Nothing happens to x and y themselves because they have no memory space. The values read in are stored directly in start_x and start_y.

When the return on get_coordinate is executed, all of the memory for get_coordinate is wiped (no return value to hold onto or store):

     +--------------------------------------------------------+
     |      +------------+                                    |
     | main |            |                                    |
     |      +------------+                                    |
     +--------------------------------------------------------+
     |         +------------+                +------------+   |
     | start_x |     42     |        start_y |      2     |   |
     |         +------------+                +------------+   |
     |         +------------+                +------------+   |
     |   end_x |            |          end_y |            |   |
     |         +------------+                +------------+   |
     |              +------------+                            |
     | dist_between |            |                            |
     |              +------------+                            |
     +--------------------------------------------------------+

Next, when get_coordinate is called a second time, the actual and formal arguments are lined up again:

    get_coordinate(        end_x,           end_y);
                           /\               /\
                           ||               ||
                           \/               \/
    get_coordinate(double & x,      double & y);

And get_coordinate is loaded into memory again:

     +--------------------------------------------------------+
     |      +------------+                                    |
     | main |            |                                    |
     |      +------------+                                    |
     +--------------------------------------------------------+
     |         +------------+                +------------+   |
     | start_x |     42     |        start_y |      2     |   |
     |         +------------+                +------------+   |
     |         +------------+                +------------+   |
 |---|-->end_x |            |          end_y |            |<--|---|
 |   |         +------------+                +------------+   |   |
 |   |              +------------+                            |   |
 |   | dist_between |            |                            |   |
 |   |              +------------+                            |   |
 |   +--------------------------------------------------------+   |
 |   +--------------------------------------------------------+   |
 |   |                                                        |   |
 |   | get_coordinate                                         |   |
 |   |                                                        |   |
 |   +--------------------------------------------------------+   |
 |   |                                                        |   |
 |---|-------x                             y------------------|---|
     |                                                        |
     +--------------------------------------------------------+

Now x is linked to end_x and y refers to end_y. When the user types 42 12, we see:

     +--------------------------------------------------------+
     |      +------------+                                    |
     | main |            |                                    |
     |      +------------+                                    |
     +--------------------------------------------------------+
     |         +------------+                +------------+   |
     | start_x |     42     |        start_y |      2     |   |
     |         +------------+                +------------+   |
     |         +------------+                +------------+   |
 |---|-->end_x |    42      |          end_y |     12     |<--|---|
 |   |         +------------+                +------------+   |   |
 |   |              +------------+                            |   |
 |   | dist_between |            |                            |   |
 |   |              +------------+                            |   |
 |   +--------------------------------------------------------+   |
 |   +--------------------------------------------------------+   |
 |   |                                                        |   |
 |   | get_coordinate                                         |   |
 |   |                                                        |   |
 |   +--------------------------------------------------------+   |
 |   |                                                        |   |
 |---|-------x                             y------------------|---|
     |                                                        |
     +--------------------------------------------------------+

Again, as get_coordinate's return executes, the whole function leaves memory and we are back to where we assumed input (far) above:

 +--------------------------------------------------------------+
 |      +------------+                                          |
 | main |            |                                          |
 |      +------------+                                          |
 +--------------------------------------------------------------+
 |         +------------+                +------------+         |
 | start_x |     42     |        start_y |      2     |         |
 |         +------------+                +------------+         |
 |         +------------+                +------------+         |
 |   end_x |     42     |          end_y |     12     |         |
 |         +------------+                +------------+         |
 |              +------------+                                  |
 | dist_between |            |                                  |
 |              +------------+                                  |
 +--------------------------------------------------------------+

Putting Functions Together for Re-Use: Libraries

When you have gathered a group of logically related functions that you might like to use on more than just one application, you can put them together into a library. To do this, you'll be creating two (2) files: an interface (or 'header') file and an implementation file.

To start, though, pick a name for your library. For example, if the functions are all about mathematical operations, and your name is Bob, you might call the library Bob's Math Library. Something catchy like that.

In the interface file, you should put the prototypes for all of the library's functions. Save this file as libname.h (where libname is a space-less abbreviation of your library's name; for the library above, you might use bobmath.h or bob_math.h, for instance).

Then, into the implementation file, place all of the functions' definitions. Save this file as libname.C or libname.cpp (again, this might be bobmath.cpp or bob_math.C for the above library example). Oh! And don't forget to #include in the implementation file any standard library headers on which you depend (iostream, cmath, etc.).

Now you have two separate files. To use them together as a library, you must connect them logically. To do so, you should add to the implementation file's #include section a line like:

   #include "libname.h"

Replacing libname with your library's name. Note how the library's header's name goes in double quotes ("") instead of angle brackets (<>) like the standard library headers.

Then, to prevent the compiler getting a headache from #includeing files over and over, you need to put in a bit of logic in the libray header:

#ifndef LONG_NAME_THAT_SAYS_YOUR_HEADER_IS_INCLUDED
#define LONG_NAME_THAT_SAYS_YOUR_HEADER_IS_INCLUDED
                     // these two identifiers must match!

// prototypes in here

#endif

Now you are all set. To use this library in an application, you do two things. First #include the header into the application's .C file (use double quotes just as you did in the implementation file). Then, when you compile the application's .C file (CPP app for instance), include the name of the implementation file on the line after the application's .C file:

   $ CPP app libname
   app.C***
   libname.C...

   $ _

You can have as many libraries as you feel necessary. Just try to make each one a logical group of functions.

See the examples section for a complete example.