~ Introduction to Programming: C ~

Session 17 - Introduction to Functions

<<  Back to Contents Page

Session 17 - Introduction to Functions

In This Session...

In this session we will be covering the following topics:-

Review of Last Session

In session 13, we covered:-

Introduction to Functions

We have looked at ways in which we can split our program into various different sections by spacing them out, and placing comments at the beginning of each section to help describe their function.

Another useful method for splitting up the different parts of a program is to utilise functions.

We have already used functions in our programs, right from the very first session.  The main() function lists all of the C programming instructions that are to be executed. It also tells the C Compiler where to start executing the program.

Functions are a way of performing a particular task. A function can have information passed into it (often called input) and can give results in the form of output.

For example, gets is a pre-defined function that we have been using. It takes no input into the function, but inside the function, it waits for the user to type something out, and then passes this out of the function and into a variable.

Functions can be useful where we may wish to perform a task more than once - e.g. the gets function - and also when we wish to perform a sub-task - i.e. a task that is part of another task, but is better explained on its own.

Anatomy of a function

Let's look at a simple function that calculates the volume of an object. For example, say we had a box that was 3 metres high, 3 metres wide and 3 metres deep, then the volume (i.e. space) inside the box would be 3 x 3 x 3 = 3 x 9 = 27m2.

Thus, our function will take three inputs. In this example, we will make them integer values, although in reality we would probably use floats. These will be length, breadth and height. The result will be a single value, which will also be an integer (as it is simply multiplying the three inputs together).

You can imagine that in a program for measuring the volume available in a house (for example), you might use this function many times. You could simply multiply the numbers within your program, but why not make it obvious what you are trying to find (i.e. the volume) and put the code to find the results inside a function.

Doing this has a number of advantages:-

Here's how we would define the function in C:-

int vol_calc ( int lngth, int brdth, int ht )
{
  return lngth * brdth * ht;
}

The int at the beginning tells us what type of value will be output from the function - i.e. the volume result will be an integer value.

The vol_calc which comes next gives a descriptive name of what the function does - in this case, it calculate the volume. We could just as easily have called it volume or volume_of. Generally, function names follow the same rules as variables when you use them. To keep your style consistent with other C programmer, keep them as lower case, and separate words with underscore (_) characters.

Next, we have a number of inputs. These are listed inside normal parentheses [brackets - i.e. between a ( and a )  ]. The are separated with commas, and each input is given as the type of the input (e.g. int or char or float etc.) followed by a name by which the parameter will be known inside the function. Thus, the length is an integer, and will be called lngth inside the function, the breadth is an integer and will be called brdth inside the function, and the height is also an integer and will be called ht inside the function.

You may notice that these look a little like variable definitions (except with a variable, we would have defined this by saying int lngth, brdth, ht; - we can't do that when defining inputs.  This is an appropriate way to think. We'll take a look at why this is a little later.

Exercise 54: Volume Calculator function

Type out the following program and execute it to try it out. Follow the description below to understand what's going on... 

#include <stdio.h>
#include <conio.h>
/* Calculate volume from length, breadth and height */
int vol_calc ( int lngth, int brdth, int ht )
{
  return lngth * brdth * ht;
}
 
/* main program */
main()
{
  int length, breadth, height, volume;
  printf( " Length: " ); scanf( "%d", &length);
  printf( "Breadth: " ); scanf( "%d", &breadth);
  printf( " Height: " ); scanf( "%d", &height);
 
  volume = vol_calc( length, breadth, height );
 
  printf( "Volume of L=%d/B=%d/H=%d is %d",
          length, breadth, height, volume
        );
 
  getch();
}

Execute the program with the following values: Length: 2, Breadth: 3, Height: 4. The result should be 2 x 3 x 4 = 6 x 4 = 24. Press a key to finish and return to your IDE.

 Length: 2
Breadth: 3
 Height: 4
Volume of L=2/B=3/H=4 is 24_

What is happening here? Well, the main program is using the function vol_calc by passing it the contents of the three variables, length, breadth, and height. In this case, we typed 2, 3, and 4 for these variables respectively.  The contents of these three variables are passed to the the three variable declarations (known as parameters) in the function - i.e.

The original variables are left untouched - only their values are passed into the function as input, via the parameter variables. This is known as passing by value as the values of the variables, rather than a reference to variables themselves, is passed to the function.

We now have three variables called lngth, brdth and ht containing the values 2, 3, and 4 respectively. These variables are only available inside the function - once we hit the closing } that ends the function, these variables disappear and the contents are lost. Therefore, they are used purely for passing information into the function from the program. In technical parlance, we say that the scope of a variable declared inside a function is lifetime of the function itself - i.e. from the opening curly brackets - { - to the closing curly brackets - } .

Okay, now we calculate these values using the parameter variables - i.e. lngth * brdth * ht - giving us 2 * 3 * 4 which calculates to be 24.

The return command means "pass back to the program that called vol_calc the following value". This is the output of the function. So return lngth*brdth*ht is the same as return 2*3*4 is the same as return 24 in this case. So 24, is returned from the function.

This means that the command volume = vol_calc(length,breadth,height); gets replaced with the result of the return command, so it becomes volume = 24; in this case. I.e. it resolves to volume = 24 - another term you may come across when reading about programming.

Resolution (or resolving) refers simply to the process of breaking a program down into its parts once you put values into variables etc. - it is a good way of working out how a program works by seeing how putting numbers in place of variables causes a program to act a particular way. This is also a good way of testing to see if your program works as you expect it to. We will look at how to use your IDE to help you with this later using its tracing facilities. 

 

Prototypes

The example you tried in the previous exercise gave the function before the main program.  For many people, this is a rather illogical way to work, as you want the main function of the program to be at the beginning, rather than all the bits that help make the main program clearer.

The reason why we had to do it this way is down to the way that C compiles your program. If we defined the vol_calc function after the main() function, then when we tried to all vol_calc from inside the main() function, the compiler would shout and say "I haven't come across a function called vol_calc yet - help! help! It doesn't exist" and stop in its tracks.  The compiler must have come across the function first to check that you are putting the right kinds of input into it (e.g. if you tried putting strings into the function instead of integers, this wouldn't be right).

So we have a problem - if we put the vol_calc before the main() function, the program becomes unclear to read, and if we put it afterwards, the program doesn't compile. What do we do?

The answer is to use something called a prototype. Like in the real world, this is a model of the real thing, rather than the thing itself. So a prototype shows us what the inputs and output of the function is going to be, but doesn't show how the function does it's work.  It is basically a copy of the function without anything inside the curly brackets.

This gives the compiler just enough information to work out whether you are putting the right inputs, and how to handle the output.

For the vol_calc function, the prototype is:

int vol_calc ( int lngth, int brdth, int ht );

Note the semi-colon. This tells the compiler that no opening curly bracket follows, so this must be a prototype. It will expect you to fill in the details and implement the function properly later on in your program (otherwise you'll get another nasty compiler error message!)

Having all your function declared like this at the top of your program is quite nice - it tells you what functions you have available to use in your main program at-a-glance.  This can be quite useful when putting together quite complex programs.

Exercise 55: Prototyped Volume Calculator

Okay, so what does our program look like when we put a prototype at the top, and move the vol_calc() function implementation after the main() function. Copy and paste the first line of the function above the main() function, and add a semi-colon (;) to the end of the line. That's your prototype. Then cut and paste the entire function from the top of the program down the after the closing } of the main() function

#include <stdio.h>
#include <conio.h>
/* Prototypes */
int vol_calc ( int lngth, int brdth, int ht );
 
/* main program */
main()
{
  int length, breadth, height, volume;
  printf( " Length: " ); scanf( "%d", &length);
  printf( "Breadth: " ); scanf( "%d", &breadth);
  printf( " Height: " ); scanf( "%d", &height);
 
  volume = vol_calc( length, breadth, height );
 
  printf( "Volume of L=%d/B=%d/H=%d is %d",
          length, breadth, height, volume
        );
 
  getch();
}
 
/* Calculate volume from length, breadth and height */
int vol_calc ( int lngth, int brdth, int ht )
{
  return lngth * brdth * ht;
}

See - it still works!

Exercise 56: VAT Calculator program

Use the program in exercise 55 as a basis to write a program to calculate VAT on a single item. The resulting program will actually be slightly simpler than the volume example.

Enter Cost: 100
VAT is 17.50
Total Cost is 117.50_ 

Use getch(); as usual to pause the display until a key is pressed before the program is terminated. A solution is available later.

Note that we can legitimately use the same variable name for the parameter variable as in the main() program - i.e. cost. As the value gets copied from the main program into the parameter variable, and the parameter variable is disposed of when the function completes, they don't interfere with each other. It's often good practice to use different names, in order to avoid any confusion when reading the listing.  In this example, we have used the same name just to illustrate a point.

Exercise 57: Tracing through a program

Earlier we discussed a technique called resolution or resolving where we work through a program listing and substitute values into variables as they would be input, and then substitute the values for variables inside calculations to work out what the results would be. This can involve having to look inside a function to see how it calculates its results, if necessary (although this is impossible with many of the pre-defined functions that come with C).

Functions act a bit like a black box - i.e. when we look through a program, how the function does its working out is hidden inside the function itself. The analogy is that you feed data into this black box, the calculations take part inside the black (therefore unseen) box, and out of the other side comes the output - i.e. the result of the function's calculation.

This can be useful for simplifying programs so that we can see at a glance what the program is doing, rather than how it is doing it. We look to the functions if we wish to see the detail of how the program does what it does at a more technical level. This makes understanding programs a lot simpler. We will be looking at how to do this in more detail next week, when we look at Jackson Structure Programming and how this applies to breaking down programs into different functional parts.

Rather than doing this exercise on paper, or in our heads, we can enlist the help of the IDE to do this. In this case, we will use C++ Builder to do the task, although almost all IDEs have similar functionality.

Using the program your wrote in exercise 56, follow these instructions (your tutor will give you a demo of this before you have to try it for yourself):-

You should be able to see that this is a great way of tracing through your program when it doesn't work as you expect - i.e. for debugging purposes. You can predict what you expect the program to do, and when it doesn't, you can see where it is going wrong, one line at a time.

Just as an extra note, if you have found the problem, and wish to continue execution normally (instead of stepping through line-by-line), either choose the Run menu followed by the Run menu item, press the button on the toolbar, or press the F9 key.

There are many other useful debugging tools available within C++ Builder, but this is by far the most useful tool, and is a good one to get to know.  

Addendum to Exercise 57 - Breakpoints

It can be rather time consuming if you have an idea of where the problem is in your program, but need to step through just a small section of the program to see what is happening in that specific area of your program. Using the above method, you would need to step through the whole of your program before you can get to the bit you're interested in. This is obviously time-consuming and frankly, dull.

To alleviate programmer's boredom, most IDEs allow you to set breakpoints in your program. This is simply a little marker that you can put on any chosen line in your program. When you execute your program (you don't have to step through yet), the program will run as normal until it gets to the line where you set the breakpoint.  At this point, it will pause execution, and allow you to look at variables, step through line-by-line etc. You can then restart execution again (e.g. by pressing the F9 key in Borland C++ Builder) and the program will carry on as normal until either it reaches the end of the program, or finds another breakpoint in your program (or possibly the same breakpoint, if you put the breakpoint inside a loop - a very useful technique on occasion).

To set a breakpoint in your program in C++ builder, click in the grey margin to the left of the line where you wish the program to pause. A little red blob appears in the margin, and the line is highlighted in red - something like this:-

To take the breakpoint back off again, just click in the same place again.

Alternatively, you can press the F5 key to set or clear a breakpoint on the line where the cursor is currently sitting.

You might like to try the exercise above again, but instead create a breakpoint on the line shown above, and execute the program instead of stepping from line-to-line. The program should stop at this line. You can now trace into the vol_calc function using the F7 key and when this has finished, step through the rest of the program, or just carry on execution using the F9 key.

Solution to Exercise 56

Try the following as an example solution:-

#include <stdio.h>
#include <conio.h>
/* Constant Definitions */
#define VAT_RATE 17.5
 
/* Prototypes */
float calc_vat ( float cost );
 
/* main program */
main()
{
  float cost, vat, total;
  printf( "Enter Cost: " ); scanf( "%f", &cost);
  vat = calc_vat( cost );
  total = cost + vat;
  printf( "VAT is %5.2f\nTotal Cost is %6.2f\n", vat, total );
  getch();
}
 
/* Calculate vat amount from an initial cost */
float calc_vat ( float cost )
{
  return cost * ( VAT_RATE / 100 ) ;
}

In the Next Session...

In the next session we will be covering the following topics:-

(c) Copyright 2003-4 Simon Huggins.   All Rights Reserved.
If you have any issues or questions regarding the content of this web site, please contact the author by clicking here.
Alternatively, you can leave a voice message on 00 44 (0)7050-618-297 or fax on 00 44 (0)7050-618-298

This Page was last updated: 29 January 2004 13:07