|
~ Introduction to Programming: C ~ Session 17 - Introduction to Functions |
In This Session...
In this session we will be covering the following topics:-
In session 13, we covered:-
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.
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:-
If you give your functions descriptive names, they act to describe what is happening in your program
If you need to change how the function works (e.g. you decide you want to add an error element of 2% to all volume measurements) then you only have to change the code inside the function, not in every place where the function is used. This can save you a lot of time if you ever need to change how a reusable piece of code.
You have a description of the inputs and outputs of the function, which can help you to understand its purpose
You are splitting the task from the program, thus making the main program easier to understand.
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 contents of length are copied to the lngth parameter variable
The contents of breadth are copied to the brdth parameter variable
The contents of height are copied to the ht parameter variable
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.

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.
Name the function to calculate VAT something like calc_vat.
It should take a single input - call the parameter variable cost
and make sure it is takes a float type variable. Similarly, the
result from the function should also be a float. The calculation for
VAT is currently cost*1.175 (i.e. 17.5% of the amount).
If you like, you can define the VAT as a constant at the top of the program
(called it VAT_RATE and make it 17.5) - this would change the formula
to cost * (VAT_RATE / 100)
In the main() function, you will need three variables - one for cost, one for vat and one for total - make these all float type variables.
Prompt for the cost, and read in the cost using scanf - make sure you use the appropriate format specifier ("%character") for a float variable.
Calculate the VAT amount using the calc_vat function, taking the cost variable as the input parameter, and storing the result in the vat variable.
Calculate the total cost of the item by adding the contents of the vat variable to the contents of the cost variable and storing the result in the total variable.
Display the results so they look as below (you may need to look at how to use %5.2f in a printf statement etc.)
Use getch(); as usual to pause the display until a key is pressed before the program is terminated
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):-
Ensure the program is not already running. If it is, press a key to finish the program's execution.
Click on the Run menu and select the Step Over option. Alternatively, press the F8 key which does the same thing.
On your program listing, the first line (the main() function header) will be highlighted with an arrow next to it. This is the line which is about to be executed (it hasn't yet). The IDE is waiting to see what you want to do before it executes the next line.
Press F8 again. The program line skips to the printf statement. This has yet to be executed.
On the line: float cost, vat, total; try hovering your cursor over each of the variable names in turn, pausing over each one. This shows you the contents of each of the variable. Notice that they are something rather meaningless at the moment - e.g. 1.401257473E-39 which is a very small but meaningless number.
Press F8 again. The arrow and highlighter have disappeared. If you click the output window on the taskbar, you can see that this is because the scanf function is waiting for you to type something out. Type out 100 and press enter to carry on.
The program listing reappears, with the next program line highlighted - the vat calculation. If you hover over the cost variable again (anywhere in the listing - but not where it says &cost - this gives you the position in memory where the cost variable is kept), you should see that the value is now 100. If you hover over the vat variable anywhere in the listing, you can see that it is still a meaningless number.
Now either click the Run menu and select the Trace Into option, or alternatively press the F7 key which does the same thing.
Rather than skipping over the line and performing the calculation, this will show you how any functions that make up the command are executed - so in this case, the calc_vat function is used, the the execution line now highlights the header line of the calc_vat function. If you hover over the cost variable on the highlighted execution line, you can see that the value of 100 has been passed into it. This variable will now be available for the result of the calc_vat function.
Press F8 to skip onto the next line, and F8 again to perform the calculation, and F8 again to finish execution of the function, and return execution to the main listing.
The vat variable has now been calculated. Hover over this value to see what is contains - it should now be 17.5.
Hover over the parameter variable cost in the header of the calc_vat function. It no longer shows a value. This is because the parameter variable has been disposed of, and is no longer available.
Hover your cursor over the cost and vat variable on the highlighted line. They should be 100 and 17.5 respectively. You can predict that the result of the calculation will be 117.5 and will be placed in the total variable.
Press F8 to calculate the value of cost+vat
Hover your cursor over the total variable on the preceding line. This should show a value of 117.5 as we predicted.
Press F8 again to show the results on the screen.
Switch over to the output screen on the task bar. You can see the results of the printf command on the console window.
Switch back to C++ Builder on the task bar.
Press F8. This executed the getch(); command which will wait for you to press a key on the console window. Therefore, as input is expected, the execution highlighter bar disappears
Switch back over to the output screen and press a key.
Execution resumes, and the closing } of the main() function is highlighted. This is the end of the program.
Press F8 again, and execution finishes.
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.
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 we will be covering the following topics:-
The Software Development Lifecycle
An introduction to Jackson Structured Programming
Splitting programs up into logical units using functions.
A look at applying this to the "Stone Knife Paper" game
![]()
(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