TIGCC Programming Lessons
The following is part of a series of lessons designed to help teach
people to program in C for the TI-89, 92+, and V200 calculators
using the TIGCC development environment.
If you wish, you can download the program source code, project
files, and binaries
here.
Lesson 4: Functions
Step 1 - An Introduction to Functions
Functions are the building blocks of C programs. They encapsulate pieces
of code to perform specific operations. Functions allow us to accomplish
the same or similar kinds of tasks over and over again without being
forced to keep adding the same code into your program over and over
again. Functions perform tasks such as string printing (i.e. the
DrawStr() and printf() functions), keyboard reading functions
(OSdequeue(), ngetchx(), and kbhit()), graphics drawing (Sprite8(),
Sprite16(), and Sprite32()), and any other task that will need to be
repeated many times. Even though we did not write any of these
functions, and do not how they are written, we can still use them. And
we can use them over and over again without ever being forced to include
the code in our program multiple times.
Functions allow us to put pieces of code together to accomplish a
specific task, and then assign an appropriate name to that task so we do
not have to copy the code. This makes programming much much easier by
allowing us to reuse code from other people, simply by including their
functions. This is how the TIGCC library works. It did not write many of
the functions we use, it simply provides an interface for us to use the
built-in system routines from the AMS software which powers the
calculator. I hope it has already been properly illustrated how this can
speed up programming significantly. In the times before we had this kind
of access, we had to write all these functions by ourselves. The most
powerful adage you will ever learn in computer programming is "Don't
reinvent the wheel". If you're unfamiliar with this, it just means, if
someone else has already done what you are trying to do, then don't
waste your time trying to duplicate the same thing. Just use theirs!
This is the power of modular function based programming.
Step 2 - An Overview of C Functions
In C, functions are defined in 4 pieces:
- the function return type,
- the function name (which must be unique),
- the functions arguments, and
- the function prototype.
Let's examine a simple function declaration:
int
random(int
randmax). The first three pieces have been outlines in
green,
purple, and red. Let's
examine them further:
The function return type is the type of value the function will return
when it is called. Many functions will return values that give the user
some indication of what happened. These can be values like true (which
in C is usually 1), and false (0), or they can be values the function
has calculated or found for us (like the ngetchx() function returns the
keycode), or it may not return a value at all. In this case, the
function return type is void, which
means, we do not return a value. So if we had a function
void
PrintNumber(
int number), it would not return any
value at the end of the function.
If a function has a return type, you can store that return type in a
variable by using the statement: variable =
function(arguments); We have seen this before, as in
key = ngetchx(); But the ngetchx()
function takes no arguments.
The function name is the name we give to the function. It can be
anything, so long as it is unique. This means you cannot duplicate the
name of any other function you define, and you cannot duplicate the name
of any function you have included. This means if you use the TIGCC
library, you cannot define a function called DrawStr(), or printf(), or
ngetchx(), or any other function that is used by the TIGCC library. This
is because the C compiler cannot differentiate between the various
functions.
The function arguments are values we pass to the function so it can use
them to do its work. If we choose to print a string, we need to know
what string to print. Functions can take any number of arguments, so
long as they are properly configured. The argument list is a series of
variables separated by a comma. So, if we have one variable, the
argument list is like this (type varName). If we have two, then it looks
like (type var1, type var2), where type is the variable type (int, char,
float, etc).
The last part of a proper function declaration is the function
prototype. This is what we use to tell the compiler how this function
should look when it finds it. It is primarily used because you may be
using functions that have not been linked or compiled yet. This is how
the TIGCC library works. We do not have the functions we use from the
TIGCC library, because they are defined already in the AMS. But the
compiler still has to know about them, so we setup a series of
prototypes so the compiler will understand that this function exists
somewhere. That is all we need to worry about, because the linker takes
care of finding the functions we don't define (like those in the TIGCC
library).
A function prototype for a particular function should be declared either
at the top of a C source file, or in a C header file (a .h file). We
haven't used our own .h files yet, but we will be doing so in this
lesson. Header files simply store information for the program source
code. They hold things like #define directive values, and special types
and structures (which we will cover in a future lesson), function
prototypes, external variable declarations, and other things we may
cover in the future.
So, what is a function prototype? Simple, it's just the signature of a
function (i.e. the return type, name, and arguments) with a trailing
semi-colon (it's a statement in C, and all statements end in a
semi-colon, as you should know). However, in declaring function
prototypes, we do not need to know the names of the arguments, only the
types. So, if we have the function int random(int randMax) { // some
code here }, its function prototype would be:
int random(int);
If we have multiple arguments, we can separate their types with commas,
but we do not need names. For example, the function void DrawStr(int x,
int y, char *str, int attribute) { // enter code here } becomes:
void DrawStr(int, int, char *, int);
Do not forget the '*' asterisk in the character pointer. Otherwise, the
compiler will think we want a single character, when we really want a
pointer to a character. If the compiler does not know what to look for,
it cannot identify the function, and it will complain. C doesn't like
not knowing about something, so you always have to make sure it has all
the information it needs.
This also works with type modifiers, as in the function long int
double(long int single) { // code }. This would become:
long int double(long int);
You will see more in the example program, and it's easier to illustrate
that way, so I will forego any further examples, because they are just
too numerous. If you want more examples, take a look at the
Nibbles 68k Source Code in the
nibbles.h file, and you will see the function prototypes for the
nibbles.c file.
Step 3 - A Simple Example Program Using C Functions
Open TIGCC and start a new project. Create a new C Source File
called mathtest. Now we need to create a new Header File. The process is
very similar to creating a C Source File. Select the File Menu, then the
New option, then the C Header File option. You can name this mathtest
as well. Here is the code for our two files.
mathtest.c
/*
MathTest 1.0
A Simple Mathematics Test Program to Illustrate the Use of Functions in C
Copyright (C) 2000,2007 Techno-Plaza
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <tigcclib.h>
#include "mathtest.h" // include our special header file
// return double the value of the argument
int times2(int number) {
return (number * 2);
}
// returns the square of the number given
int square(int number) {
return (number * number);
}
// returns the base number raised to the power of the exponent
long int power(int base, int exponent) {
int loop;
long int bigNumber = base;
// since exponentials are just multiplication the number of
// the exponent, loop and multiply
for (loop = 1; loop < exponent; loop++) {
bigNumber*=base;
}
// return this big number
return bigNumber;
}
// return the sum of the numbers from start to end
int sum(int start, int end) {
int loop, sum = 0;
// keep track of the sun
for (loop = start; loop <= end; loop++) {
sum+=loop;
}
// return the calculated sum
return sum;
}
// return a number between 0 and 9 based on user input
short int getNumber(void) {
short int key = 0;
// wait for valid input
while (key < '0' || key >'9') {
key = ngetchx();
}
// calculate the number 0 as the value of keycode minus
// the value of the keycode '0'
key -= '0';
// return the corrected number
return key;
}
// pause the program
inline void pause(void) {
printf("Press any key...");
ngetchx();
}
// Main Function
void _main(void)
{
int done = 0, number, base, exponent, start, end;
long int bigNumber;
short int key = 0;
// loop until we're finished
while (!done) {
// clear the screen
clrscr();
// display the messages using printf
printf("Pick a Function or\nPress ESC to Quit\n\n");
printf("1: Double\n2: Square\n3: Exponent\n4: Sum\n\n? ");
// wait for valid input
while ((key < '1' || key > '4') && key != KEY_ESC) {
key = ngetchx();
}
// if we pressed ESC, invalidate the loop
if (key == KEY_ESC) {
done = 1;
// go to the next loop iteration
continue;
}
// calculate the numeric value of the keycode and print
// the selection
key -= '0';
printf("%d\n\n", key);
// perform actions based on the input
switch (key) {
// we chose the double function (times2() function)
case 1:
// wait for input and display the selection
printf("Enter a number (0-9) ? ");
key = getNumber();
printf("%d\n\n", key);
// calculate the value and print the result
number = times2(key);
printf("If you double the number\n");
printf("%d, you get %d\n\n", key, number);
// exit the switch statement
break;
// we chose the square() function
case 2:
// wait for input and display the result
printf("Enter a number (0-9) ? ");
key = getNumber();
printf("%d\n\n", key);
// calculate the value and print the result
number = square(key);
printf("If you square the number\n");
printf("%d, you get %d\n\n", key, number);
// exit the switch statement
break;
// we chose the exponent function (power() function)
case 3:
// ask for the base number
printf("Choose base (0-9) ? ");
key = getNumber();
base = key;
// print the result
printf("%d\n", key);
// ask for the exponent
printf("Choose exponent (0-9) ? ");
key = getNumber();
exponent = key;
// print the result
printf("%d\n\n", key);
// calculate the value and print the result
bigNumber = power(base, exponent);
printf("If you raise the number\n");
printf("%d to the power of %d, you\n", base, exponent);
printf("get the number %ld\n\n", bigNumber);
// exit the switch statement
break;
// we chose the sum function
case 4:
// ask for the start number
printf("Choose Start Number? ");
key = getNumber();
start = key;
// print the result
printf("%d\n", key);
// ask for the end number
printf("Choose End Number? ");
key = getNumber();
end = key;
// print the result
printf("%d\n\n", key);
// if we have valid input
if (end >= start) {
// calculate the value and print the result
number = sum(start,end);
printf("If you summed the numbers\n");
printf("from %d to %d, you would\n", start, end);
printf("end up with the number %d\n\n", number);
} else {
// otherwise yell at the user
printf("You have made an invalid\n");
printf("selection. Try again.\n\n");
}
// exit the switch statement
break;
}
// pause the program so the user can see the result
pause();
}
}
Now edit the mathtest header file. You can do this in much the same way
as you do the mathtest source file, just by clicking on the mathtest
file name on the source tree in the left window pane under the Header
Files. Edit this file so it looks like this:
/*
MathTest 1.0
A Simple Mathematics Test Program to Illustrate the Use of Functions in C
Copyright (C) 2000,2007 Techno-Plaza
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
Begin function prototyping here
*/
// returns the value of its argument times 2
int times2(int);
// returns the square of its argument
int square(int);
// returns the first argument raised to the
// power of the second argument
long int power(int, int);
// returns the sum of the numbers between the
// first argument and the second argument
int sum(int, int);
// gets a number between 0 and 9 from the user
// using keyboard input
short int getNumber(void);
// displays a short pause messsage and waits
// for user input before continuing
inline void pause(void);
// the entry point of the program
void _main(void);
/*
End of Function Prototypes
*/
You need to add an #include directive in your C Source File when you
make your own header files. You'll notice we have done this at the top
of our C Source File.
Step 4a - Compile and Run the Program
Now save the project and all the files, then build it and send it to
TiEmu. Run the program, and you will see something very similar to this:
Step 4b - Program Analysis
You knew we would be getting here sooner or later. We covered the basic
outlines of functions in C, and you have seen how they are used in
practice by using functions like ngetchx() and DrawStr(), so this lesson
should be very simple. It is presented here mainly as a way to cover all
the bases of functions explicitly.
You will notice a slight difference between this example program and
example programs from the past. This one does not have all the code
contained inside the _main() function. This is because we are now
learning how to make real programs, and real programs rarely put all the
code into the _main() function. They branch it out into several
functions to accomplish tasks without being forced to duplicate code. If
you have the same (or very similar) code in more than one place, it's
likely to be inefficient. It's better to define a function for such a
segment of code and contain it in one place. This makes programs
smaller and cuts down on memory usage.
Continue the Analysis in Part II
|