Vous êtes sur la page 1sur 5

[5] [6] } [7] } [8] int fonction (int b) [a] {int c=0; [b] c=b+8; [c] } [d] analysons

progressivement l'volution de la pile au cours du temps (en gras : variable visible) : [1] a=1 [2] a=1 | b=2 [3] a=1 | b=2 | a=3 : seul le a le plus haut est visible (a=3), l'autre vit encore (valeur 1 garde) mais n'est plus visible. [4a] a=1 | b=2 | a=3 | b=3 : entre dans la fonction, recopie de l'argument rel (a) dans l'argument formel (b). Mais a n'est plus visible. [4b] a=1 | b=2 | a=3 | b=3 | c=0 [4c] a=1 | b=2 | a=3 | b=3 | c=11 : quand le compilateur cherche la valeur de b, il prend la plus haute de la pile donc 3 (c'est la seule visible), met le rsultat dans le c le plus haut. L'autre b n'est pas modifi. [4d] a=1 | b=2 | a=3 : suppression des variables locales b et c du sommet de la pile [5] a=1 | b=2 : sortie de bloc donc libration de la pile [6a] a=1 | b=2 | b=1 : l'argument rel (a) n'est plus le mme qu'en [4a] [6b] a=1 | b=2 | b=1 | c=0 [6c] a=1 | b=2 | b=1 | c=9 [6d] a=1 | b=2 : suppression b et c [7] a=1 [8] la pile est vide, on quitte le programme Notez que la rservation et l'initialisation prennent un peu de temps chaque entre du bloc. Mais ne prsumez jamais retrouver une valeur sur la pile, mme si votre programme n'a pas utilis la pile entre temps (surtout sur systme multitche ou avec mmoire virtuelle). Une dclaration a toujours la structure suivante : [classe] type liste_variables [initialisateur]; (entre [] facultatif) Le type peut tre simple (char, int, float,...) ou compos (tableaux, structures..., voir plus loin). La liste_variables est la liste des noms des variables dsires, spares par des virgules s'il y en a plusieurs. Chaque nom de la liste peut tre prcds d'une *, ceci spcifiant un pointeur. L'initialisateur est un signe =, suivi de la valeur donner la variable lors de sa cration ( chaque entre du bloc par exemple). La valeur peut tre une constante, mais aussi une expression avec des constantes voire des variables (visibles, dj initialises). La classe peut tre :

} fonction(a);

auto (ou omise, c'est la classe par dfaut pour les variables locales) : la variable est cre l'entre du bloc (dans la pile) et libre automatiquement sa sortie (comme expliqu plus haut). register : la variable est cre, possde la mme dure de vie et visibilit qu'une classe auto, mais sera place dans un registre du (micro)processeur. Elle sera donc d'un accs trs rapide. Si tous les registres sont dj utiliss, la variable sera de classe auto. Mais le compilateur peut avoir besoin

16

des registres pour ses besoins internes ou pour les fonctions des bibliothques, s'il n'en reste plus le gain peut se transformer en perte. De plus les compilateurs optimiss choisissent de mettre en registre des variables auto, et souvent de manire plus pertinente que vous. Mais le compilateur ne sait pas l'avance quelles fonctions seront appeles le plus souvent, dans ce cas une optimisation manuelle peut tre utile, par exemples dans le cas des lments finis o une mme instruction peut tre rpte des milliards de fois. static : la variable ne sera pas dans la pile mais dans la mme zone que le code machine du programme. Sa dure de vie sera donc celle du programme. Elle ne sera initialise qu'une fois, au dbut du programme, et restera toujours rserve. En retournant dans un bloc, elle possdera donc encore la valeur qu'elle avait la prcdente sortie. Sa visibilit reste la mme (limite au bloc). Une variable statique permet en gnral un gain en temps d'excution contre une perte en place mmoire.

II- Dclarations globales


Une dclaration faite l'extrieur d'un bloc d'instructions (en gnral en dbut du fichier) est dite globale. La variable est stocke en mmoire statique, sa dure de vie est celle du programme. Elle est visible de sa dclaration jusqu' la fin du fichier. Elle sera initialise une fois, l'entre du programme (initialise 0 si pas d'autre prcision). Le format d'une dclaration globale est identique une dclaration locale, seules les classes varient. Par dfaut, la variable est publique, c'est dire qu'elle pourra mme tre visible dans des fichiers compils sparment (et relis au link). La classe static, par contre, rend la visibilit de la variable limite au fichier actuel. La classe extern permet de dclarer une variable d'un autre fichier (et donc ne pas lui rserver de mmoire ici, mais la rendre visible). Elle ne doit pas tre initialise ici. Une variable commune plusieurs fichiers devra donc tre dclare sans classe dans un fichier (et y tre initialise), extern dans les autres. Toute fonction, pour pouvoir tre utilise, doit auparavant tre soit dclare, soit dfinie. On dtaillera sa dfinition au paragraphe suivant. Une dclaration de fonction est gnralement globale, et alors connue des autres fonctions. Une dclaration de fonction est appele "prototype". Le prototype est de la forme : [classe] type_retourn nom_fonction(liste_arguments); elle est donc identique l'entte de la fonction mais : - est termine par un ; comme toute dclaration - les noms des arguments n'ont pas besoin d'tre les mmes, il peuvent mme tre omis (les types des arguments doivent tre identiques). Sans prcision de classe, la fonction est publique. Sinon, la classe peut tre extern (c'est ce que l'on trouve dans les fichiers .H) ou static (visibilit limite au fichier). Le prototype peut tre utilis pour utiliser une fonction du mme fichier, mais avant de l'avoir dfinie (par exemple si l'on veut main en dbut du fichier). En gnral, lorsque l'on cre une bibliothque (groupe de fonctions et variables regroupes dans un fichier compil sparment), on prpare un fichier regroupant toutes les dclarations extern, not .H, qui pourra tre inclus dans tout fichier utilisant la bibliothque. exemples de dclarations globales : int i,j; /* publiques, initialises 0 */ static int k=1; /* prive, initialise 1 */ extern int z; /* dclare (et initialise) dans un autre fichier */ float produit(float,float); /* prototype d'une fonction dfinie plus

17

loin dans ce fichier */ extern void change(int *a, int *b); /* prototype d'une fonction dfinie dans un autre fichier */ Avant la norme ANSI, le prototype n'existait pas. Une fonction non dfinie auparavant tait considre comme rendant un int (il fallait utiliser un cast si ce n'tait pas le cas).

III- Dclaration de type


La norme ANSI permet de dfinir de nouveaux types de variables par typedef. structure : typedef type_de_base nouveau_nom; Ceci permet de donner un nom un type donn, mais ne cre aucune variable. Une dclaration typedef est normalement globale et publique. exemple : typedef long int entierlong; /* dfinition d'un nouveau type */ entierlong i; /* cration d'une variable i de type entierlong */ typedef entierlong *pointeur; /* nouveau type : pointeur = pointeur d'entierlong */ pointeur p; /* cration de p (qui contiendra une adresse), peut tre initialis par =&i */ Remarques : Le premier typedef pouvait tre remplac par un #define mais pas le second. L'utilisation du typedef permet de clarifier les programmes, puisqu'on peut dfinir un nom de type pour dclarer des variables dont la fonction sera clairement dtaille : typedef float prix; typedef float quantite; prix a,b,c; quantite x,y; Une autre utilisation importante est pour dfinir un type complexe, o l'on dfinira petit petit les composants (exemple tableau de pointeurs de structures, on dfinit d'abord la structure, puis le pointeur de structure, puis le tableau de tout cela).

18

Fonctions
I- Dfinitions gnrales
Une fonction est dfinie par son entte, suivie d'un bloc d'instructions entte : type_retourn nom_fonction(liste_arguments) (pas de ;) Avant la norme ANSI, le type_retourn pouvait tre omis si int. Dsormais il est obligatoire, si la fonction ne retourne rien on indique : void. La liste_arguments doit tre type (ANSI), alors qu'auparavant les types taient prciss entre l'entte et le bloc : ANSI: float truc(int a, float b) {bloc} K&R: float truc(a,b) int a;float b; {bloc} Si la fonction n'utilise pas d'arguments il faut la dclarer (ANSI) nom(void) ou (K&R) nom(). L'appel se fera dans les deux cas par nom() (parenthses obligatoires). Les arguments (formels) sont des variables locales la fonction. Les valeurs fournies l'appel de la fonction (arguments rels) y sont recopis l'entre dans la fonction. Les instructions de la fonction s'excutent du dbut du bloc ({) jusqu' return(valeur) ou la sortie du bloc (}). La valeur retourne par la fonction est indique en argument de return. exemples : 1) fonction ne recevant aucun argument, et ne retournant rien. Ce n'est pas parce qu'elle ne retourne rien qu'elle ne fait rien, ici elle affiche un message l'cran. Elle ne reoit aucun argument, ici parce qu'elle n'en a pas besoin, quelquefois c'est parce qu'elle n'utilise que des variables globales (chose que je ne conseille pas).
void message(void) { int i; for(i=0;i<10;i++)printf("bonjour monde\n"); }

On appelle cette fonction par message(); Une fonction possde ses propres variables locales (ici i), mais n'a pas accs aux variables locales des autres fonctions, pas mme celles de main (mais aux variables globales, que je dconseille fortement au dbutant) 2) fonction recevant un (ou plusieurs) argument(s), et ne retournant rien. Une telle fonction a besoin d'informations pour effectuer sa tche, ce qui est le cas le plus courant.
void insiste(int combien_de_fois,char * compliment) { int i; printf("Oh que tu es "); for(i=0;i<combien_de_fois;i++)printf("%s ",compliment); printf("!!!!! \n); }

19

On appelle cette fonction par exemple par insiste(10,"belle"); ou int j=3; char i[]="fatiguant"; insiste(j*2,i); Tout ce qui importe l'appel est qu'on donne en premier argument une valeur entire et en second une chane de caractres. Leurs noms n'ont aucun rapport avec ceux utiliss dans la fonction. 3) fonction recevant un (ou plusieurs, ou aucun) argument(s), et retournant une valeur. Une telle fonction a besoin (ou non) d'informations pour effectuer sa tche, mais quand la tche est termine (en gnral c'tait un calcul), elle rend (retourne) le rsultat (une et une seule valeur). Je vous rapelle que les variables locales de la fonction ne sont pas visibles l'extrieur de la fonction, sans cela les calculs auraient t inutiles.
float produit(float a;float b) { float z; z=a*b; return(z); }

On appelle cette fonction dans une expression ncessitant un float : x=produit(2,4.5); ou


y=2+produit(sin(x)+produit(1.12,X),produit(2,2)) %f\n",z,produit(z,2));

ou printf("le

double de %f est

4) que fait-on pour retourner plusieurs valeurs ? C'est impossible directement. On peut retourner un pointeur qui permet de retourner l'adresse d'un ensemble de valeurs (tableau ou structure). On peut aussi transmettre des "rcipients" pour les valeurs rsultantes, grce au passage d'arguments par adresse. On pourait aussi utiliser des variables globales, mais ce qui prouve que vous tes un programmeur expriment est que vous savez que c'est une trs mauvaise solution.

II- Rcursivit, gestion de la pile


Une fonction peut s'appeler elle-mme :
int factorielle(int i) { if (i>1) return(i*factorielle(i-1)); else return(1); }

analysons la pile en appelant factorielle(3) : i=1 i=2 i=2 i=2 i=3 i=3 i=3 i=3 i=3 (a) (b) (c) (d) (e)

(a) appel de factorielle(3), cration de i, qui on affecte la valeur 3. comme i>1 on calcule i*factorielle(i-1) : i=3,i-1=2 on appelle factorielle(2) (b) cration i, affect de la valeur 2, i>1 donc on appelle factorielle(1) (c) cration de i, i=1 donc on quitte la fonction, on libre le pile de son sommet, on retourne o la fonction factorielle(1) a t appele en rendant 1. (d) on peut maintenant calculer i*factorielle(1), i (sommet de la pile) vaut 2, factorielle(1) vaut 1, on peut rendre 2, puis on "dpile" i (e) on peut calculer i*factorielle(2), i vaut 3 (sommet de la pile), factorielle(2) vaut 2, 3*2=6, on retourne 6, la pile est vide et retrouve sont tat initial.

20