Menu
Accueil
Forum
Liste des membres
Livre d'or
S'inscrire
Maths
Modules pour CrazyCMS
Consommation électricité
Me contacter
Espace Membre
Statistiques
livre_dor
Pas de commentaires dans le livre d'orRetour au menu
Lesson 6 – Procedures and
function
1)
Procedure
2)The different kinds of variables and the constants
3)
Parameters
4) Functions
5) The recursivity
The procedures and the functions are
very useful and powerful. It is able to decrease the size of your code and so
your program. In fact, each time you want to make a copy and a paste, you must
wonder whether you use a procedure. The big difference between a procedure and a
function is: a procedure runs only a part of your code and a function runs a
part of your code and returns a value when the function is over. Now after this
short introduction I am going to explain how it works and when you must use so
as to optimize your code.
1) Procedure
In fact, a procedure is able to
separate a part of your code and after you can call this part of your code very
easily. That is why you should avoid coping and a pasting, you can decrease the
size of your code and you can more easily read your code. As I have told you in
the introduction, each time you want to copy and paste, you should wonder
whether it is very useful or if a procedure is more convenient and efficient.
The syntax of simple procedures is
very simple:
void name ( ) {
statement
}
‘name’ is of course the name of your
procedure. The word ‘void’ means it is a procedure and not a function or rather
the function returns nothing: void, this function is a procedure; it is the
definition :-). The statement is the part of your code that you want to
separate. And the syntax to call a procedure is:
name ( );
If you are a good viewer, you can see
‘void _main(void)’ looks like a procedure. Indeed, ‘void _main(void)’ is a
procedure and it is the main procedure because it called in first by the
compiler. Besides, you cannot delete this procedure or else the compiler does
not know to start another procedure.
Now we can see where you locate the
procedure in your code. You have two choices. The easiest, which means you do
not need to declare your procedure, is when you write your procedure before the
‘_main(void)’ procedure. The second possibility is to write your procedure after
the ‘_main(void)’ procedure’ but you have to declare your procedure before the
‘_main(void)’ procedure. The declaration is simple enough: ‘void name( );’. In
fact, the compiler reads the code as a man who reads a European language; what
means the compiler reads from left to right and from top to bottom. That is the
reason why the compiler has already seen your procedure if you have written it
before the ‘_main(void)’ procedure.
To illustrate this point, I have
written three simple codes to see the differences between without and with
procedure and the two ways to write your procedures in your code. I will explain
the declaration of variables within a procedure in the next point.
Example1 without procedure:
// C Source File
// Created 26/02/2003; 17:12:58
#define USE_TI89 // Compile for TI-89
#define USE_TI92PLUS // Compile for TI-92 Plus
#define USE_V200 // Compile for V200
#define OPTIMIZE_ROM_CALLS // Use ROM Call Optimization
#define MIN_AMS 100 // Compile for AMS 1.00 or higher
#define SAVE_SCREEN // Save/Restore LCD Contents
#include <tigcclib.h> // Include All Header Files
// Main Function
void _main(void)
{
int a;
clrscr();
for (a = 0; a < 10; a++) {
printf("*");
}
printf("\n");
for (a = 0; a < 10; a++) {
printf("*");
}
ngetchx();
}
Example2 with one procedure and without declaration of this procedure:
// C Source File
// Created 26/02/2003; 17:14:28
#define USE_TI89 // Compile for TI-89
#define USE_TI92PLUS // Compile for TI-92 Plus
#define USE_V200 // Compile for V200
#define OPTIMIZE_ROM_CALLS // Use ROM Call Optimization
#define MIN_AMS 100 // Compile for AMS 1.00 or higher
#define SAVE_SCREEN // Save/Restore LCD Contents
#include <tigcclib.h> // Include All Header Files
void star() {
int a;
for (a = 0; a < 10; a++) {
printf("*");
}
}
// Main Function
void _main(void)
{
clrscr();
star();
printf("\n");
star();
ngetchx();
}
Example3 with one procedure and with the declaration of this procedure:
// C Source File
// Created 26/02/2003; 17:17:31
#define USE_TI89 // Compile for TI-89
#define USE_TI92PLUS // Compile for TI-92 Plus
#define USE_V200 // Compile for V200
#define OPTIMIZE_ROM_CALLS // Use ROM Call Optimization
#define MIN_AMS 100 // Compile for AMS 1.00 or higher
#define SAVE_SCREEN // Save/Restore LCD Contents
#include <tigcclib.h> // Include All Header Files
// declaration of your procedure
void star();
// Main Function
void _main(void)
{
clrscr();
star();
printf("\n");
star();
ngetchx();
}
void star() {
int a;
for (a = 0; a < 10; a++) {
printf("*");
}
}
Of course, you can also declare your
procedure in the second example but it is not a compulsory.
We have seen we call a procedure in the
main procedure but you can also call a procedure in any other procedure. When
you use the first way to use a procedure, the compiler has to read the procedure
before calling it or else it does not know it and it crashes! That is why the
second way with the declaration of procedure is friendlier because you do not
need to be careful with the sort of your procedures. The longer and more complex
the code, the better it is for the second solution and I strongly advise its
use. Later we will see how create a file where you locate all declarations of
procedures and it is very clear with complex code!
When you call a procedure, the Tios
takes long. Some times, the procedure is very small or you do not want to loose
time to activate it but you want to use a procedure so as to make a clearer code
and avoid a copy and a paste; therefore you can make an inline procedure. In
fact, the inline procedure is exactly like a copy and paste but it is not you
who work but the compiler which makes it instead of you. So you can take
advantage of the procedure pros and avoid the procedure cons. It is great!
The syntax of inline procedure is as
simple as a simple procedure: you add only the word ‘inline’ in first position:
inline void name ( ){
statement
}
When you declare an inline procedure,
you must also add the word ‘inline’ like: ‘inline void name ( );’ it is very
easy! :-) For example, the following code gives you at the screen the same
result than with the others examples.
// C Source File
// Created 01/03/2003; 13:38:50
#define USE_TI89 // Compile for TI-89
#define USE_TI92PLUS // Compile for TI-92 Plus
#define USE_V200 // Compile for V200
#define OPTIMIZE_ROM_CALLS // Use ROM Call Optimization
#define MIN_AMS 100 // Compile for AMS 1.00 or higher
#define SAVE_SCREEN // Save/Restore LCD Contents
#include <tigcclib.h> // Include All Header Files
inline void star() {
int a;
for (a = 0; a < 10; a++) {
printf("*");
}
}
// Main Function
void _main(void)
{
clrscr();
star();
printf("\n");
star();
ngetchx();
}
Of course, if you want to exit your
procedure before the usual end, you can add: ‘return;’ and you exit the
procedure at this moment. It is interesting when you have conditions and
according the events you choose to exit or not your procedure.
2) The different kinds of variables and the
constants
When you can see in the previous
examples, there are also declarations of variables within procedures; it is like
with the _main procedure. In fact, if the declaration of your variable is within
a procedure, this variable is called ‘local’ variable and it is available only
within this procedure. We can say: the variable is born with ‘{‘ and is dead
with ‘}’. What means you can declare a variable within any which statement, for
instance, a for statement and this variable will be only available for this
statement. Of course, it is also right for the main procedure. These variables
are called ‘automatic’ variables and it is the default variable.
If you want to keep the data of your
variable after the ‘}’ symbol, you have to add ‘static’ in your declaration of
your variable thus you have not an automatic variable. The syntax is:
static type name
If you have understood what I have
explained, you can use a local variable only within the same procedure or
statement. However, if you want to use a variable in all the procedures, you
have to use another type of variables. This type is called ‘global’. A global
variable is available anywhere what means you can use this variable in all
procedures and all files but we have not seen this point yet. The declaration of
a global variable is as simple as a local variable; only the place of the
declaration is different. You have to declare a global variable just after the
start of your code: after the include area. I advise you to use the less global
variable than you can because your code is more organized.
I am going to explain something but
it is not a piece of advice and you will avoid making it. As we have already
seen, there are two types of variables: local and global. In fact, the local
variable is more important than the global variable what means when you call two
variable with the same name, within the procedure the data of your variable has
the data of your local variable and not one of your global variable. It is very
clear for the compiler but it is very hard for an human!
There are two kinds of constants: the
constants which are like a copy and a paste and the constants which seem like a
variable. The first kind of constant is easier to use according to me. The
syntax is:
#define name value
Remember the spaces in c language
have no signification but it is more visually attractive, isn’t it? The place of
this declaration is at the top of your code, after the include area. In fact, it
is like with the inline procedure: each time the compiler sees the name of your
constant within your code, it replaces the name of your constant by its value. I
prefer this kind of constant, I think it is clearer and simpler. The syntax of
the second kind of constant is:
const type name = value;
The difference with the other
constant is that the compiler keeps a memory storage to stock the value. In
fact, this constant is like a variable which you cannot change the value.
We can see an example to understand
how all these notions work.
// C Source File
// Created 09/03/2003; 12:09:03
#define USE_TI89 // Compile for TI-89
#define USE_TI92PLUS // Compile for TI-92 Plus
#define USE_V200 // Compile for V200
#define OPTIMIZE_ROM_CALLS // Use ROM Call Optimization
#define MIN_AMS 100 // Compile for AMS 1.00 or higher
#define SAVE_SCREEN // Save/Restore LCD Contents
#include <tigcclib.h> // Include All Header Files
#define const1 56
int global = 17;
void procedure () {
int local_procedure = 5;
int local = 21;
printf ("local_proc = %d\n", local_procedure);
printf ("global = %d\n", global);
printf ("local = %d\n", local);
// the compiler doesn't know the 'local_main' variable
printf ("const1 = %d\n", const1); // this constant is like a global constant
// the compiler doesn't know the 'const2' constant
}
// Main Function
void _main(void)
{
int local_main = 13;
int local = 27;
const int const2 = 54;
clrscr();
printf ("Within the 'main' procedure:\n\n");
printf ("local_main = %d\n", local_main);
printf ("global = %d\n", global);
printf ("local = %d\n", local);
// the compiler doesn't know the 'local_procedure' variable
printf ("const1 = %d\n", const1); // this constant is like a global constant
printf ("const2 = %d\n", const2); // this constant is like a local constant
ngetchx();
clrscr();
printf ("Within the procedure:\n\n");
procedure ();
ngetchx();
}
3) Parameters
The parameters of procedures are very
powerful and increase the use of procedures. In fact, you can make your own
function, for instance you can make your own function: ‘printf’ but the real
interest is you make procedures specific at your program; you can also use these
procedures in others programs if these procedures are very useful for you.
Indeed you can make your own library but we will see it later! A perfect
procedure has to be able to use in any code, what means you must copy and paste
only, you change nothing.
As I discussed before, when we use
the notion of parameters, we have to speak about pointers. Indeed, there are two
kinds of parameters: by reference or address and by value. We are going to start
with the parameters by value because it is the simplest to understand and we do
not use pointers.
a) Parameters by
value
We can see the syntax:
void name ( type name1, type name2, …) {
statement
}
and when we call a procedure:
name (X1, X2, …);
with Xi = value, variable, pointer (with the star acronym ‘*’)
As you can see, you must declare the
parameters like a simple variable: you tell the compiler the type of your
parameters. The name of theses parameters is parameters by value because you
give at your parameters only the value of variable or just a value. In fact, at
the end of your procedure the parameters by value give back nothing. If you
change the value of your parameters within the procedure, the parameters assign
no variable. To simplify we can see a brief example:
// C Source File
// Created 12/03/2003; 17:07:41
#define USE_TI89 // Compile for TI-89
#define USE_TI92PLUS // Compile for TI-92 Plus
#define USE_V200 // Compile for V200
#define OPTIMIZE_ROM_CALLS // Use ROM Call Optimization
#define MIN_AMS 100 // Compile for AMS 1.00 or higher
#define SAVE_SCREEN // Save/Restore LCD Contents
#include <tigcclib.h> // Include All Header Files
#define height 5 // it's a constant to change easily the height of your object
void star (int number) {
int a;
for (a = 0; a < number; a++)
printf("*");
printf("\n");
}
void space (int number) {
int a;
for (a = 0; a < number; a++)
printf(" ");
}
// Main Function
void _main(void)
{
int i;
clrscr();
for (i = 0; i < height; i++) {
space (height - i);
star (i * 2);
}
for (i = height; i > 0; i--) {
space (height - i);
star (i * 2);
}
ngetchx();
}
You can see that if you do not use
the procedures, your code would be bigger because you would have to make two
“copy & paste” and in addition your code would be very much less readable. I
think you understand this example or else you must read the lesson about ‘for’
loop. :-)
b) Parameters by address or reference
The difference is when you exit your
procedure, the parameters by address get the last value within the procedure. In
fact, the value of your parameter after the running of your procedure depends on
the code of your procedure. Indeed, the parameter does not store the value when
you call a procedure but the address. That is the reason why when you assign the
parameter within the procedure, you assign the address and you change the value
of this address. As we work with the address, we have to use the pointers. In
fact, the parameters by address or reference are pointers and when we call a
procedure, we use a pointer or else we give the address of your variable. With
the parameters by address we have to use a variable or a pointer, we cannot use
only a value. After this small introduction, we can see the syntax:
Void name (type *name1, type *name2, …) {
Statement
}
and the syntax to call a procedure:
name (X1, X2, …);
with Xi = address what means a pointer without the star acronym: ‘*’ or a
variable with the dereference acronym: ‘&’.
When you use the dereference acronym,
it is to get the address of your variable and it is just you need with the
parameter by address. When you can see in the syntax, there are only parameters
by address but it is not a compulsory and you can, use parameters by value and
there is no sorting. To illustrate this point as usual usually, I have written a
code to compare the both different parameters. Remember that you would play with
notions you have learned, it is the best solution to master the programming. A
lot of fun! :-)
// C Source File
// Created 13/03/2003; 17:16:24
#define USE_TI89 // Compile for TI-89
#define USE_TI92PLUS // Compile for TI-92 Plus
#define USE_V200 // Compile for V200
#define OPTIMIZE_ROM_CALLS // Use ROM Call Optimization
#define MIN_AMS 100 // Compile for AMS 1.00 or higher
#define SAVE_SCREEN // Save/Restore LCD Contents
#include <tigcclib.h> // Include All Header Files
void addition (int x1, int x2, int *answer) {
*answer = x1 + x2;
x1 = 3;
x2 = 5; // these variables are modified only within this procedure
}
void change (int *x, int *y, int *z) {
int aux;
aux = *x;
*x = *y;
*y = aux;
*z = 27;
}
// Main Function
void _main(void)
{
int a, b, c;
int *sum;
c = 13; /* you have to initialize also this variable or else when the code is running,
this variable haven't address */
sum = &c; // the pointer have to initialize for the same explication
clrscr();
a = 13;
b = 4;
addition (a, b, &c); // you want to give the address of your variable so you use '&'
printf ("13 + 4 = %d\n", c);
addition (17, 4, sum);/* you want to give the address of your pointer so you don't use
//the '*' acronym, it's the definition of a pointer */
printf ("\n\n17 + 4 = %d", *sum);
ngetchx();
clrscr();
printf ("initial value:\n a = %d\n b = %d\n c = %d", a , b, c);
change (&a, &b, &c);
/*
the procedure gets the address of these variables and it modifies the data of these address
at the end of procedure, the address is available within the procedure and the out of
the procedure
*/
printf ("\n\nfinal value:\n a = %d\n b = %d\n c = %d", a , b, c);
ngetchx();
}
4) Functions
In fact, a procedure is a function
which returns no value: ‘void’. If you want to use a function, you have to tell
the compiler which type of value you want. The syntax is:
type name ( parameters by value or address ) {
statement
}
Of course, using parameters is not a
compulsory. When you want to call a function, it is like a procedure: you write
in your code: ‘name( );’ but as you use a procedure, it is to get a value thus
you have to assign a variable, to display the value at the screen, … you can
make hardly like with a variable. Within the function, you
must tell compiler the value which the function returns or else the function is
useless and the compiler notes a mistake. The syntax is:
return
(value);
Let us illustrate this point!
// C Source File
// Created 09/03/2003; 14:03:53
#define USE_TI89 // Compile for TI-89
#define USE_TI92PLUS // Compile for TI-92 Plus
#define USE_V200 // Compile for V200
#define OPTIMIZE_ROM_CALLS // Use ROM Call Optimization
#define MIN_AMS 100 // Compile for AMS 1.00 or higher
#define SAVE_SCREEN // Save/Restore LCD Contents
#include <tigcclib.h> // Include All Header Files
int addition (int x1, int x2) {
return (x1 + x2);
}
int multiplication (int x1, int x2) {
return (x1 * x2);
}
// Main Function
void _main(void)
{
int aux;
clrscr();
aux = addition (13, 8);
printf ("13 + 8 = %d\n\n17 * 2 = %d", aux, multiplication(17, 2));
ngetchx();
}
5) The recursivity
The recursivity seems like the loops
but it is made by procedures or functions. In fact, within the code of your
procedure, you call the same procedure: it is the same effect than with a simple
loop. The advantage is your code is smaller but the disadvantages are: firstly
the compiler stores all the calls and consequently it is less fast than a simple
loop and secondly it is more complex to understand. But sometimes, you have less
problems with recursivity. We can see two examples: one to understand how it
works and another to see the efficiency in a real example.
Example 1:
// C Source File
// Created 16/03/2003; 14:39:25
#define USE_TI89 // Compile for TI-89
#define USE_TI92PLUS // Compile for TI-92 Plus
#define USE_V200 // Compile for V200
#define OPTIMIZE_ROM_CALLS // Use ROM Call Optimization
#define MIN_AMS 100 // Compile for AMS 1.00 or higher
#define SAVE_SCREEN // Save/Restore LCD Contents
#include <tigcclib.h> // Include All Header Files
#define number 7
/*
you must be careful because number < 13 or else the result is huge and over an unsigned long int
factorial (n) = n! = n*(n-1)*(n-2)*...*3*3*1 and 0! = 1
example: 5! = 5*4*3*2*1 = 120
*/
unsigned long factorial1 (int n) {
int a;
unsigned long facto;
if (n == 0)
return(1);
facto = 1;
for (a = 2; a <= n; a++)
facto *= a;
return (facto);
}
unsigned long factorial2 (int n) {
if (n == 0)
return (1);
if (n != 1)
return (n * factorial2 (n - 1));
else
return (1);
}
// Main Function
void _main(void)
{
clrscr();
printf ("13! = %lu\n", factorial1(number));
printf ("13! = %lu", factorial2(number));
ngetchx();
}
Example 2:
This example explains how you can
make a menu and it is for me the simplest because if you do not use the
recursivity, you will use an amount of conditions with several loops and you get
the same effect because the speed is not important for a menu.
// C Source File
// Created 16/03/2003; 15:10:58
#define USE_TI89 // Compile for TI-89
#define USE_TI92PLUS // Compile for TI-92 Plus
#define USE_V200 // Compile for V200
#define OPTIMIZE_ROM_CALLS // Use ROM Call Optimization
#define MIN_AMS 100 // Compile for AMS 1.00 or higher
#define SAVE_SCREEN // Save/Restore LCD Contents
#include <tigcclib.h> // Include All Header Files
// I declare the procedure because I call procedures within procedure
// and so I don't need to sort the procedures.
char menu();
void about();
void options();
void speed();
void difficulty();
// The procedures:
/*
The function 'menu' returns a char because I use the result like a boolean value.
1 = true
0 = false
I use a char because it's not the worth to use an integer or a short. The compiler will use more
memory storage and it's unuseful. Even a char takes much memory to store only 1 or 0!
*/
char menu() {
int key;
clrscr();
printf("F1 - Game\n\n");
printf("F2 - Options\n\n");
printf("F3 - About ...\n\n");
printf("F4 - Exit");
key = ngetchx();
switch (key) {
case KEY_F1:
return (1);
break;
case KEY_F2:
options();
break;
case KEY_F3:
about();
break;
case KEY_F4:
case KEY_ESC:
return (0);
}
return (menu());
}
void about() {
clrscr();
printf ("This menu is created by:\n\n\n Frédéric RIVAL\n\nMember of the Quiche Team");
ngetchx();
}
void options() {
int key;
clrscr();
printf("F1 - Dificulty\n\n");
printf("F2 - Speed\n\n");
printf("F3 - Return");
key = ngetchx();
switch (key) {
case KEY_F1:
difficulty();
break;
case KEY_F2:
speed();
break;
case KEY_F3:
case KEY_ESC:
return;
}
options();
}
void speed() {
clrscr();
printf("Choose your speed");
ngetchx();
}
void difficulty() {
clrscr();
printf("Choose your difficulty");
ngetchx();
}
// Main Function
void _main(void)
{
while (menu()) {
clrscr();
printf("Here the game!");
ngetchx();
}
}
See another lesson
Retour au menu