home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The C Users' Group Library 1994 August
/
wc-cdrom-cusersgrouplibrary-1994-08.iso
/
vol_200
/
252_01
/
chap05.txt
< prev
next >
Wrap
Text File
|
1990-02-14
|
32KB
|
705 lines
Chapter 5
FUNCTIONS, VARIABLES, AND PROTOTYPES
OUR FIRST USER DEFINED FUNCTION
____________________________________________________________
Load and examine the file SUMSQRES.C for an ==============
example of a C program with functions. SUMSQRES.C
Actually this is not the first function we ==============
have encountered because the main program we
have been using all along is technically a
function, as is the printf() function. The printf() function
is a library function that was supplied with your compiler.
Notice the executable part of this program which begins in
line 8 with a line that simply says "header();", which is the
way to call any function. The parentheses are required
because the C compiler uses them to determine that it is a
function call and not simply a misplaced variable. When the
program comes to this line of code, the function named
header() is called, its statements are executed, and control
returns to the statement following this call. Continuing on
we come to a for loop which will be executed 7 times and which
calls another function named square() each time through the
loop, and finally a function named ending() will be called and
executed. For the moment ignore the variable name index in
the parentheses of the call to square. We have seen that this
program calls a header, 7 square calls, and an ending. Now
we need to define the functions.
DEFINING THE FUNCTIONS
____________________________________________________________
Following the main program you will see another program
beginning in line 14 that follows all of the rules set forth
so far for a main program except that it is named header().
This is the function which is called from line 8 of the main
program. Each of these statements are executed, and when they
are all complete, control returns to the main program.
The first statement sets the variable named sum equal to zero
because we plan to use it to accumulate a sum of squares.
Since the variable named sum is defined prior to the main
program, it is available to be used in any of the following
functions. It is called a global variable, and its scope is
the entire program and all functions. It is also sometimes
referred to as a file variable because it is available
throughout the file. More will be said about the scope of
variables near the end of this chapter. The statement in line
17 outputs a header message to the monitor. Program control
Page 5-1
Chapter 5 - Functions, Variables, & Prototypes
then returns to the main program since there are no additional
statements to execute in this function. Essentially, we drop
out of the bottom of the function and return to the caller.
It should be clear to you that the two executable lines from
this function could be moved to the main program, replacing
the header call, and the program would do exactly the same
thing that it does as it is now written. This does not
minimize the value of functions, it merely illustrates the
operation of this simple function in a simple way. You will
find functions to be very valuable in C programming.
PASSING A VALUE TO A FUNCTION (CLASSIC METHOD)
____________________________________________________________
Going back to the main program, and the for loop specifically,
we find the new construct from the end of the last lesson used
in the last part of the for loop, namely the index++ used in
line 9. You should get familiar with this construct, as you
will see it in a lot in C programs.
In the call to the function named square(), we have an added
feature, namely the variable name index within the
parentheses. This is an indication to the compiler that when
you go to the function, you wish to take along the value of
index to use in the execution of that function. Looking ahead
at the function named square(), we find that another variable
name is enclosed in its parentheses, the variable number.
This is the name we prefer to call the variable passed to the
function when we are in the function. We can call it anything
we wish as long as it follows the rules of naming an
identifier. Since the function must know what type the
variable is, it is defined following the function name but
before the opening brace of the function itself. Thus, line
21 containing "int number;" tells the function that the value
passed to it will be an integer type variable. With all of
that out of the way, we now have the value of index from the
main program passed to the function square(), but renamed
number, and available for use within the function. This is
the classic style of defining function variables and has been
in use since C was originally defined. A newer method is
gaining in popularity due to its many benefits and will be
discussed later in this chapter.
Following the opening brace of the function, we define another
variable named numsq for use only within the function itself,
(more about that later) and proceed with the required
calculations. We set the variable named numsq equal to the
square of the value of number, then add numsq to the current
total stored in the variable named sum. Remember that "sum
+= numsq;" has the identical meaning as "sum = sum + numsq;"
from the last lesson. We print the number and its square in
line 27, and return to the main program.
Page 5-2
Chapter 5 - Functions, Variables, & Prototypes
MORE ABOUT PASSING A VALUE TO A FUNCTION
____________________________________________________________
When we passed the value of the variable named index to the
function, a little more happened than meets the eye. We did
not actually pass the value of index to the function, we
actually passed a copy of the value. In this way the original
value is protected from accidental corruption by a called
function. We could have modified the variable named number
in any way we wished in the function named square(), and when
we returned to the main program, the variable named index
would not have been modified. We thus protect the value of
a variable in the main program from being accidentally
corrupted, but we cannot return a value to the main program
from a function using this technique. We will find a well
defined method of returning values to the main program or to
any calling function when we get to arrays and another method
when we get to pointers. Until then the only way you will be
able to communicate back to the calling function will be with
global variables. We have already hinted at global variables
above, and will discuss them in detail later in this chapter.
Continuing in the main program, we come to the last function
call, the call to the function named ending() in line 11.
This line calls the last function which has no local variables
defined. It prints out a message with the value of the
variable sum contained in it to end the program. The program
ends by returning to the main program and finding nothing else
to do. Compile and run this program and observe the output.
NOW TO CONFESS A LITTLE LIE
____________________________________________________________
I told you a short time ago that the only way =============
to get a value back to the main program was SQUARES.C
through use of a global variable, but there =============
is another way which we will discuss after
you load and display the file named
SQUARES.C. In this file we will see that it is simple to
return a single value from a called function to the calling
function. But once again, it is true that to return more than
one value, we will need to study either arrays or pointers.
In the main program, we define two integers and begin a for
loop in line 6 which will be executed 8 times. The first
statement of the for loop is "y = squ(x);", which is a new and
rather strange looking construct. From past experience, we
should have no trouble understanding that the squ(x) portion
of the statement is a call to the function named squ() taking
along the value of x as a variable. Looking ahead to line 15
of the function itself, we find that the function prefers to
call the input variable in, and it proceeds to square the
Page 5-3
Chapter 5 - Functions, Variables, & Prototypes
value of in and call the result square. Finally, a new kind
of a statement appears in line 21, the return statement. The
value within the parentheses is assigned to the function
itself and is returned as a usable value in the main program.
Thus, the function call "squ(x)" is assigned the value of the
square and returned to the main program such that the variable
named y is then set equal to that value. If the variable
named x were therefore assigned the value 4 prior to this
call, y would then be set to 16 as a result of this line of
code.
Another way to think of this is to consider the grouping of
characters squ(x) as another variable with a value that is the
square of x, and this new variable can be used any place it
is legal to use a variable of its type. The values of the
variables x and y are then printed out.
To illustrate that the grouping of squ(x) can be thought of
as just another variable, another for loop is introduced in
line 11 in which the function call is placed in the printf()
statement rather than assigning it to a new variable.
One last point must be made, the type of variable returned
must be defined in order to make sense of the data, but the
compiler will default the type to integer if none is
specified. If any other type is desired, it must be
explicitly defined. How to do this will be demonstrated in
the next example program.
Be sure to compile and run this program which also uses the
classic method of defining function variables.
FLOATING POINT FUNCTIONS
____________________________________________________________
Load the program FLOATSQ.C for an example of =============
a function with a floating point type of FLOATSQ.C
return. It begins by defining a global =============
floating point variable named z which we will
use later. Then in the main part of the
program, an integer is defined, followed by two floating point
variables, and then by two strange looking definitions. The
expressions sqr() and glsqr() look like function calls and
they are. This is the proper way in C to define that a
function will return a value that is not of type int, but of
some other type, in this case float. This tells the compiler
that when a value is returned from either of these two
functions, it will be of type float. This is, once again, the
classic method of defining functions.
Now refer to the function named sqr() starting in line 22 and
you will see that the function name is preceded by the keyword
float. This is an indication to the compiler that this
Page 5-4
Chapter 5 - Functions, Variables, & Prototypes
function will return a value of type float to any program that
calls it. The function is now compatible with the call to it.
The line following the function name contains float inval;,
which indicates to the compiler that the variable passed to
this function from the calling program will be of type float.
The function named glsqr() beginning in line 31, will also
return a float type variable, but it uses a global variable
for input. It does the squaring right within the return
statement and therefore has no need to define a separate
variable to store the product.
The overall structure of this program should pose no problem
and will not be discussed in any further detail. As is
customary with all example programs, compile and run this
program.
THE CLASSIC STYLE
____________________________________________________________
The three programs we have studied in this chapter so far use
the classic style of function definition. Although this style
was the first defined for C, it is rapidly being replaced with
the modern method of function definition because it does so
much for you in detecting and flagging errors. As you read
articles on C, you will see programs written in the classic
style, so you need to be capable of reading them. It would
be highly recommended, however, that you learn and use the
modern method which will be covered shortly in this tutorial.
The remainder of this tutorial will use the modern method as
recommended and defined by the ANSI standard. If you have an
older compiler, it may not work on some of these files and it
will be up to you to modify the programs as needed to conform
to the classic style.
SCOPE OF VARIABLES
____________________________________________________________
Load the next program, SCOPE.C, and display =============
it for a discussion of the scope of variables SCOPE.C
in a program. You can ignore the 4 =============
statements in lines 2 through 5 of this
program for a few moments. We will discuss
them later.
The first variable defined is a global variable named count
which is available to any function in the program since it is
defined before any of the functions. It is always available
because it does not come and go as the program is executed.
(That will make sense shortly.) Farther down in the program,
another global variable named counter is defined in line 25
Page 5-5
Chapter 5 - Functions, Variables, & Prototypes
which is also global but is not available to the main program
since it is defined following the main program. A global
variable is any variable that is defined outside of any
function. Note that both of these variables are sometimes
referred to as external variables because they are external
to any functions, and they are sometimes called file
variables.
Return to the main program and you will see the variable named
index defined as an integer in line 11. Ignore the word
register for the moment. This variable is only available
within the main program because that is where it is defined.
In addition, it is an automatic variable, which means that it
only comes into existence when the function in which it is
contained is invoked, and ceases to exist when the function
is finished. This really means nothing here because the main
program is always in operation, even when it gives control to
another function. Another integer is defined within the for
braces named stuff. Any pairing of braces can contain a
variable definition which will be valid and available only
while the program is executing statements within those braces.
The variable will be an automatic variable and will cease to
exist when execution leaves the braces. This is convenient
to use for a loop counter or some other very localized
variable.
MORE ON AUTOMATIC VARIABLES
____________________________________________________________
Observe the function named head1() in line 26 which looks a
little funny because of void being used twice. The purpose
of the uses of the word void will be explained shortly. The
function contains a variable named index, which has nothing
to do with the variable named index in line 11 of the main
program, except that both are automatic variables. When the
program is not actually executing statements in this function,
this variable named index does not even exist. When head1()
is called, the variable is generated, and when head1()
completes its task, the variable in head1() named index is
eliminated completely from existence. (The automatic variable
is stored on the stack. This topic will be covered later.)
Keep in mind however that this does not affect the variable
of the same name in the main program, since it is a completely
separate entity.
Automatic variables therefore, are automatically generated and
disposed of when needed. The important thing to remember is
that from one call of a function to the next call, the value
of an automatic variable is not preserved and must therefore
be reinitialized.
Page 5-6
Chapter 5 - Functions, Variables, & Prototypes
WHAT ARE STATIC VARIABLES?
____________________________________________________________
An additional variable type must be mentioned at this point,
the static variable. By putting the keyword static in front
of a variable definition within a function, the variable or
variables in that definition are static variables and will
stay in existence from call to call of the particular
function.
By putting the same keyword in front of an external variable,
one outside of any function, it makes the variable private and
not accessible to use in any other file. (This is a
completely different use of the same keyword.) This implies
that it is possible to refer to external variables in other
separately compiled files, and that is true. Examples of this
usage will be given in chapter 14 of this tutorial.
USING THE SAME NAME AGAIN
____________________________________________________________
Refer to the function named head2(). It contains another
definition of the variable named count. Even though count has
already been defined as a global variable, it is perfectly all
right to reuse the name in this function. It is a completely
new variable that has nothing to do with the global variable
of the same name, and causes the global variable to be
unavailable in this function. This allows you to write
programs using existing functions without worrying about what
names were used for variables in the functions because there
can be no conflict. You only need to worry about the
variables that interface with the functions.
WHAT IS A REGISTER VARIABLE?
____________________________________________________________
Now to fulfill a promise made earlier about what a register
variable is. A computer can keep data in a register or in
memory. A register is much faster in operation than memory
but there are very few registers available for the programmer
to use. If there are certain variables that are used
extensively in a program, you can designate that those
variables are to be stored in a register in order to speed up
the execution of the program. The method of doing this is
illustrated in line 11. Your compiler probably allows you to
use one or more register variables and will ignore additional
requests if you request more than are available. The
documentation for your compiler will list how many registers
are available with your compiler. It will also inform you of
what types of variables can be stored in a register. If your
compiler does not allow the use of register variables, the
register request will simply be ignored.
Page 5-7
Chapter 5 - Functions, Variables, & Prototypes
WHERE DO I DEFINE VARIABLES?
____________________________________________________________
Now for a refinement on a general rule stated earlier. When
you have variables brought to a function as arguments to the
function, and you are using the classic style of programming,
they are defined immediately after the function name and prior
to the opening brace for the executable statements. Other
variables used in the function are defined at the beginning
of the function, immediately following the opening brace of
the function, and before any executable statements.
WHAT IS PROTOTYPING?
____________________________________________________________
A prototype is a model of a real thing and when programming
with a good up-to-date C compiler, you have the ability to
define a model of each function for the compiler. The
compiler can then use the model to check each of your calls
to the function and determine if you have used the correct
number of arguments in the function call and if they are of
the correct type. By using prototypes, you let the compiler
do some additional error checking for you. The ANSI standard
for C contains prototyping as part of its recommended
standard. Every good C compiler will have prototyping
available, so you should learn to use it. Much more will be
said about prototyping throughout the remainder of this
tutorial.
Returning to lines 3, 4, and 5 in SCOPE.C, we have the
prototypes for the three functions contained within the
program. The first void in each line tells the compiler that
these particular functions do not return a value, so that the
compiler would flag the statement index = head1(); as an error
because nothing is returned to assign to the variable named
index. The word void within the parentheses tells the
compiler that this function requires no parameters and if a
variable were included, it would be an error and the compiler
would issue a warning message. If you wrote the statement
head1(index);, it would be a error. This allows you to use
type checking when programming in C in much the same manner
that it is used in Pascal, Modula-2, or Ada, although the type
checking in C is very weak.
Note the addition of the word void in line 9. This is an
indication to the system that we do not plan to return a value
to the operating system when we terminate operation of this
program. The main program also can return a value in the same
manner as any other function.
You should enable prototype checking at this time, if it is
available with your compiler. Check your documentation for
Page 5-8
Chapter 5 - Functions, Variables, & Prototypes
the details of how to do it. Prototyping will be used
throughout the remainder of this tutorial. If your compiler
does not support prototyping and the modern method of function
definition, you will have to modify the remaining example
programs. A much better solution would be to purchase a
better compiler.
Line 2 of SCOPE.C tells the system to go to the include files
and get the file named STDIO.H which contains the prototypes
for the standard input and output functions so they can be
checked for proper variable types. Don't worry about the
include yet, it will be covered in detail later in this
tutorial. Be sure to compile and execute this program.
STANDARD FUNCTION LIBRARIES
____________________________________________________________
Every compiler comes with some standard predefined functions
which are available for your use. These are mostly
input/output functions, character and string manipulation
functions, and math functions. We will cover most of these
in subsequent chapters. Prototypes are defined for you by the
writer of your compiler for all of the functions that are
included with your compiler. A few minutes spent studying
your reference guide will give you an insight in where the
prototypes are defined for each of the functions.
Most compilers have additional functions predefined that are
not standard but allow the programmer to get the most out of
his particular computer. In the case of the IBM-PC and
compatibles, most of these functions allow the programmer to
use the BIOS services available in the operating system, or
to write directly to the video monitor or to any place in
memory. These will not be covered in any detail as you will
be able to study these unique aspects of your compiler on your
own. Many of these kinds of functions are used in the example
programs in chapter 14.
WHAT IS RECURSION?
____________________________________________________________
Recursion is another of those programming ==============
techniques that seem very intimidating the RECURSON.C
first time you come across it, but if you ==============
will load and display the example program
named RECURSON.C, we will take all of the
mystery out of it. This is probably the simplest recursive
program that it is possible to write and it is therefore a
stupid program in actual practice, but for purposes of
illustration, it is excellent.
Page 5-9
Chapter 5 - Functions, Variables, & Prototypes
Recursion is nothing more than a function that calls itself.
It is therefore in a loop which must have a way of
terminating. In the program on your monitor, the variable
named index is set to 8 in line 9, and is used as the argument
to the function named count_dn(). The function simply
decrements the variable, prints it out in a message, and if
the variable is not zero, it calls itself, where it decrements
the variable again, prints it, etc. etc. etc. Finally, the
variable will reach zero, and the function will not call
itself again. Instead, it will return to the prior time it
called itself, and return again, until finally it will return
to the main program and from there return to DOS.
For purposes of understanding you can think of it as having
8 copies of the function named count_dn() available and it
simply called all of them one at a time, keeping track of
which copy it was in at any given time. That is not what
actually happened, but it is a reasonable illustration for you
to begin understanding what it was really doing.
WHAT DID IT DO?
____________________________________________________________
A better explanation of what actually happened is in order.
When you called the function from itself, it stored all of the
variables and all of the internal flags it needs to complete
the function in a block somewhere. The next time it called
itself, it did the same thing, creating and storing another
block of everything it needed to complete that function call.
It continued making these blocks and storing them away until
it reached the last function when it started retrieving the
blocks of data, and using them to complete each function call.
The blocks were stored on an internal part of the computer
called the stack. This is a part of memory carefully
organized to store data just as described above. It is beyond
the scope of this tutorial to describe the stack in detail,
but it would be good for your programming experience to read
some material describing the stack. A stack is used in nearly
all modern computers for internal housekeeping chores.
In using recursion, you may desire to write a program with
indirect recursion as opposed to the direct recursion
described above. Indirect recursion would be when a function
A calls the function B, which in turn calls A, etc. This is
entirely permissible, the system will take care of putting the
necessary things on the stack and retrieving them when needed
again. There is no reason why you could not have three
functions calling each other in a circle, or four, or five,
etc. The C compiler will take care of all of the details for
you.
The thing you must remember about recursion is that at some
point, something must go to zero, or reach some predefined
Page 5-10
Chapter 5 - Functions, Variables, & Prototypes
point to terminate the loop. If not, you will have an
infinite loop, and the stack will fill up and overflow, giving
you an error and stopping the program rather abruptly.
Be sure to compile and run this program.
ANOTHER EXAMPLE OF RECURSION
____________________________________________________________
The program named BACKWARD.C is another ==============
example of recursion, so load it and display BACKWARD.C
it on your screen. This program is similar ==============
to the last one except that it uses a
character array. Each successive call to the
function named forward_and_backwards() causes one character
of the message to be printed. Additionally, each time the
function ends, one of the characters is printed again, this
time backwards as the string of recursive function calls is
retraced.
This program uses the modern method of function definition and
includes full prototype definitions. The modern method of
function definition moves the types of the variables into the
parentheses along with the variable names themselves. The
final result is that the line containing the function
definition looks more like the corresponding line in Pascal,
Modula-2, or Ada. The prototype in line 5 is simply a copy
of the function header in line 18 followed by a semicolon.
The designers of C even allow you to include a variable name
along with each type. The name is ignored by the compiler but
including the name in the prototype could give you a good idea
of how the variable is used, acting like a comment.
Don't worry about the character array defined in line 9 or the
other new material presented here. After you complete chapter
7 of this tutorial, this program will make sense. It was felt
that introducing a second example of recursion was important
so this file is included here.
Compile and run this program with prototype checking enabled
and observe the results.
IF YOU CAN'T USE PROTOTYPING WITH YOUR COMPILER
____________________________________________________________
If your compiler does not support prototyping remove line 5
from BACKWARD.C and replace line 18 with the following lines;
forward_and_backwards(line_of_char, index)
char line_of_char[];
int index;
Page 5-11
Chapter 5 - Functions, Variables, & Prototypes
Load and display the program named FLOATSQ2.C =============
which is an exact copy of the program FLOATSQ2.C
FLOATSQ.C which we considered earlier with =============
prototyping added. The use of prototyping is
a good practice for all C programmers to get
into.
Several things should be mentioned about this program. First,
the word float at the beginning of lines 27 and 35 indicate
to the compiler that these functions are functions that return
float type values. Also, since the prototypes are given
before main, the functions are not required to be identified
in line 12 as they were in line 7 of FLOATSQ.C earlier in this
chapter.
Notice also that the type of the variable named inval is
included within the parentheses in line 27. It would be very
educational for you to modify this program so that you
included a call to sqr() with a variable of type int within
the parentheses to see what kind of a warning you would get.
Do the same thing in the program without prototype checking,
FLOATSQ.C.
PROGRAMMING EXERCISES
____________________________________________________________
1. Rewrite TEMPCONV.C, from an earlier chapter, and move
the temperature calculation to a function.
2. Write a program that writes your name on the monitor 10
times by calling a function to do the writing. Move the
called function ahead of the main function to see if your
C compiler will allow it.
3. Add prototyping to the programs named SUMSQRES.C and
SQUARES.C, and change the function definitions to the
modern method.
Page 5-12