II. Procédures

Une procédure est un sous-programme. Écrire des procédures permet de découper un programme en plusieurs morceaux.

Chaque procédure définit une nouvelle instruction, que l’on peut appeler en tout endroit du programme. On peut ainsi réutiliser le code d’un sous-programme.

Lorsqu’on découpe un problème en terme de procédures, puis qu’on implémente ces procédures, on fait ce qu’on appelle une analyse descendante: on va du plus général au détail.

1.Procédure sans paramètre

 Principe

Il s’agit simplement de donner un nom à un groupe d’instructions.

Ensuite, l’appel de ce nom à divers endroits du programme provoque à chaque fois l’exécution de ce groupe d’instructions.

Exemple

PROGRAM exemple1;
Uses Wincrt;
VAR x, y, t : integer;{ Declaration de la procedure Echange_xy } 
PROCEDURE Echange_xy;
BEGIN { Corps de la procedure }t := x;
x := y;
y := t; 
END; {On met un point virugule (;) pas un point à la fin (.) }

BEGIN
 { Programme principal }
 x := 3; y := 4;      {On déclare x=3 et y=4}
writeln (’x=’x, ’ et y=’, y);
Echange_xy; { 1er appel de la procédure et premier échange entre le 3 et le 4}
writeln (’x=’x, ’ et y=’, y);
Echange_xy; { 2ème appel de la procédure et 2ème échange entre le 4 et le 3}
writeln (’x=’x, ’ et y=’, y);
END.

Ce programme affiche

x=3 et y=4

x=4 et y=3

x=3 et y=4

 

Remarques
* Le nom de la procédure est un indentificateur.
* On déclare toute procédure avant le BEGIN du programme principal.

Appels

On peut très bien appeler une procédure Proc1 depuis une procédure Proc2, mais il faut que la procédure Proc1 aie été déclarée avant la procédure Proc2.
Exemple donnant le même résultat.

 

PROGRAM exemple2;
Uses Wincrt;
VAR x, y, t : integer;
PROCEDURE Affiche_xy;
BEGIN
writeln (x, ’ ’, y); 
END;
PROCEDURE Echange_xy;
BEGIN
t := x; x := y; y := t;
Affiche_xy;
END;
BEGIN
 x := 3; y := 4;
        Affiche_xy;
        Echange_xy;
        Echange_xy;
END.

 Variables locales

Les objets du programme qui ne sont utiles que dans la procédure peuvent être définis dans les déclarations locales de la procédure.
Exemple Reprenons exemple1 et changeons t :

PROGRAM exemple3;
Uses Wincrt;
VAR x, y : integer;
PROCEDURE Echange_xy;
 VAR t : integer; { Déclaration locale }
BEGIN
t := x; x := y; y := t; 
END;
BEGIN
 { ... }
END.

– Une variable déclarée localement n’existe que pendant l’exécution de la procédure, et ne sert qu’à cette procédure.
– Le programme principal n’a jamais accès à une variable locale de procédure.
– Une procédure n’a jamais accès à une variable locale d’une autre procédure.

→ Améliore la lisibilité du programme.

Portée des variables

Les variables déclarées dans le VAR du programme principal sont appelées variables globales. Elles existent pendant toute la durée du programme et sont accessible de partout.

Une variable locale à une procédure Proc, portant le même nom x qu’une variable globale, masque la variable globale pendant l’exécution de Proc.
Exemple

PROGRAM exemple4;
Uses Wincrt;
PROCEDURE RMB;
VAR x : integer;
BEGIN
x := 20;
writeln(’RMB x = ’, x) ;
END;
BEGIN
x := 2;
writeln(’glob x = ’, x); 
RMB;
writeln(’glob x = ’, x);
END.

Ce programme affiche

glob x = 2

RMB x =  20

glob x = 2

 

Effet de bord

Voici le scénario catastrophe :

  •   On est dans une procédure Proc et on veut modifier une variable x locale à Proc.
  •   Il existe déjà une variable globale ayant le même nom x.
  •   On oublie de déclarer la variable locale x au niveau de Proc.
  •   À la compilation tout va bien !
  •   À l’exécution, Proc modifie le x global alors que le programmeur ne l’avait pas voulu.
  •   Conséquence: le programme ne fait pas ce qu’on voulait, le x global a l’air de changer de valeur tout seul !→ Erreur très difficile à détecter ; être très rigoureux et prudent !

2.Procédure paramétrée

Pseudo-passage de paramètres

Ecrivons une procédure Produit qui calcule z = xy.

PROGRAM exemple5;
Uses Wincrt;
VAR  x, y, z, a, b, c, d : real;
PROCEDURE Produit; 
BEGIN
z := x * y; 
END;

Exercice: On veut se servir de Produit pour calculer c=ab  et d=(a−1)(b+1).

BEGIN
writeln (’ donner la valuer de a et b  ’);
readln (a, b); {on pourrait aussir écrire readln(a); readln(b);}

x := a; y := b; { données }
Produit; { Produit veut deux valeurs connues x et y: traitement }
c := z; { resultat }
x := a-1; y := b+1;    { données }

Produit; { traitement }
d := z; { resultat }
writeln (’c = ’, c, ’ d = ’, d); 
END.
Paramétrage
La solution élégante consiste à déclarer des paramètres à la procédure :
PROGRAM exemple5bis;
Uses Wincrt;
VAR a, b, c, d : real;PROCEDURE Produit (x, y : real; var z : real); { parametres }
BEGIN
z := x * y;
END;
BEGIN
writeln (’donner la valeur de a et b’);
readln (a, b);

Produit (a,b, c);  {ici a prend la valeur de x, b de y et c du résultat z } { passage }
Produit (a-1, b+1, d); {de même pour a-1,b+1 et d}                          { de paramètre } 
writeln (’c = ’, c, ’ d = ’, d);
END.

Comment ça marche

• À l’appel, on donne des paramètres dans les parenthèses, séparés par des virgules, et dans un certain ordre (ici a puis b puis c).

L’exécution de la procédure commence; la procédure reçoit les paramètres et identifie chaque paramètre à une variable dans le même ordre (ici x puis y puis z).

[ Dessiner des flêches ax , by , cz ]
• Les types doivent correspondre; ceci est vérifié à la compilation.

• Il y a deux sorte de passage de paramètres : le passage par valeur et le passage par référence.

  •   Passage par valeur : à l’appel, le paramètre est une variable ou une expression. C’est la valeur qui est transmise, elle sert à initialiser la variable correspondante dans la procédure (ici x est initialisé à la valeur de a et y à la valeur de b).

 

  •   Passage par référence : à l’appel, le paramètre est une variable uniquement (jamais une expression). C’est l’adresse mémoire (la référence) de la variable qui est transmise, non sa valeur. La variable utilisée dans la procédure est en fait la variable de l’appel, mais sous un autre nom (ici z désigne la même variable (zone mémoire) que a).

C’est le mot-clé var qui dit si le passage se fait par valeur (pas de var) ou par référence (présence du var).

Pas de var = donnée ; présence du var = donnée/résultat. [ dessiner une double flêche c ←→ z ]

Erreurs classiques

  •   Mettre un var quand il n’en faut pas : on ne pourra pas passer une expression en paramètre.
  •   Oublier le var quand il en faut un : la valeur calculée ne pourra pas « sortir » de la procédure

Exemples d’erreurs à l’appel de Produit (a-1, b+1, d);

PROCEDURE Produit (var x : real; y : real; var z : real);

ne compile pas à cause du paramètre 1 var x, où une variable est attendue et c’est une expression qui est passée.

PROCEDURE Produit (x, y, z : real);

produit une erreur à l’exécution : d ne reçoit jamais le résultat z car il s’agit de 2 variables distinctes.

• Portée des variables :
dans Exemple5bis, les paramètres x, y, z de la procédure Produit sont des variables locales à Produit.

Leur nom n’est donc pas visible de l’extérieur de la procédure.

Attention: redéclarer un paramètre comme variable locale → erreur à la compilation.

Exemple:

PROCEDURE Produit (x, y : real; var z : real);
VAR
t : real;                  { déclaration d’une var locale : OK :D }
x : real; BEGIN z := x * y;{ redéclaration d’un paramètre : NON NON ET NON }
END;

Bons réflexes

Le seul moyen pour une procédure de communiquer avec l’extérieur, c’est à dire avec le reste du programme, ce sont les variables globales et les paramètres.

Il faut toujours éviter soigneusement les effets de bords. Le meilleur moyen est de paramétrer complètement les procédures, et d’éviter la communication par variables globales.

Les variables de travail tels que compteur, somme partielle, etc doivent être locales à la procédure, surtout pas globale.

Prendre l’habitude de prendre des noms de variables différents entre le programme principal et les procédures : on détecte plus facilement à la compilation les effets de bords.

Chaque fois que l’on appelle une procédure, on vérifie particulièrement le bon ordre des paramètres et la correspondance des types. La compilation est très pointilleuse sur les types, mais par contre elle ne détecte pas les inversions de paramètres de même type.

Facebook