IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Algorithmes et programmation en Pascal

Date de publication : 17 Novembre 2010 , Date de mise à jour : 17 Novembre 2010


   

 


II. Procédures
II-1. Procédure sans paramètre
II-1.1. Principe
II-1.2. Appels
II-1.3. Variables locales
II-1.4. Portée des variables
II-1.5. Effet de bord
II-2. Procédure paramètre
II-2.1. Pseudo-passage de paramètres
II-2.2. Paramètrage
II-2.3. Comment ça marche
II-2.4. Bons réflexes


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.


II-1. Procédure sans paramètre


II-1.1. 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;
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;
BEGIN
{ Programme principal }
 x := 3; y := 4;
 writeln (x, ' ', y);
 Echange_xy; { 1er appel de la procedure }
 writeln (x, ' ', y);
 Echange_xy; { 2eme appel de la procedure }
 writeln (x, ' ', y);
END.
Ce programme affiche :
3 4
4 3
3 4

Remarques

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

II-1.2. Appels

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

PROGRAM exemple2;
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.
Remarque
On peut aussi appeler une procédure depuis elle-même : c'est la récursivité, que l'on n'étudiera pas dans ce module.


II-1.3. 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;
VAR x, y : integer;
 PROCEDURE Echange_xy;
   VAR t : integer; { Declaration 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 que à 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.
infoAméliore la lisibilité du programme.

II-1.4. 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 P, portant le même nom x qu'une variable globale, masque la variable globale pendant l'exécution de P.
Exemple

PROGRAM exemple4;
VAR x : integer;
 PROCEDURE Toto;
   VAR x : integer;
 BEGIN
   x := 4;
   writeln ('toto x = ', x);
 END;
BEGIN
  x := 2;
  writeln ('glob x = ', x);
  Toto;
  writeln ('glob x = ', x);
END.
Ce programme affiche :
glob x = 2
toto x = 4
glob x = 2


II-1.5. Effet de bord

Voici le scénario catastrophe :

  • On est dans une procédure P et on veut modifier une variable x locale à P.
  • 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 P.
  • A la compilation tout va bien !
  • A l'exécution, P modifié 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 !
infoErreur très difficile à détecter ; être très rigoureux et prudent !

II-2. Procédure paramètre


II-2.1. Pseudo-passage de paramètres

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

PROGRAM exemple5;
VAR x, y, z, a, b, c, d : real;
 PROCEDURE Produit;
 BEGIN
  z := x * y;
 END;
 On veut se servir de Produit pour calculer c = ab et d = (a - 1)(b + 1).
 BEGIN
  write ('a b ? '); readln (a, b);
  x := a; y := b; { donnees }
  Produit;
  c := z; { resultat }
  x := a-1; y := b+1; { donnees }
  Produit;
  d := z; { resultat }
  writeln ('c = ', c, ' d = ', d);
END.
Remarques

  • L'écriture est un peu lourde.
  • Il faut savoir que la procédure < communique > avec les variables x, y, z.
  • Cela interdit de se servir de x, y, z pour autre chose que de communiquer avec la procédure ; sinon gare aux effets de bord !
  • Deux sortes de paramètres : données et résultats.

II-2.2. Paramètrage

La solution élégante consiste à déclarer des paramètres à la procédure :
[ Dire que c'est équiv à 2.1 ; mettre les progs côte à côte ]

PROGRAM exemple5bis;
VAR a, b, c, d : real;
 PROCEDURE Produit (x, y : real; var z : real); { parametres }
 BEGIN
  z := x * y;
 END;
 BEGIN
  write ('a b ? '); readln (a, b);
  Produit (a, b, c); { passage de }
  Produit (a-1, b+1, d); { parametres }
  writeln ('c = ', c, ' d = ', d);
END.

II-2.3. 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 réçoit les paramètres et identifie chaque paramètre à une variable dans le même ordre (ici x puis y puis z).

    [ Dessiner des fèches a --> x , b --> y , c --> z ]
  • 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, 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 : permis }
 x : real; { redéclaration d'un paramètre : interdit }
BEGIN
 z := x * y;
END;

II-2.4. 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éerents 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.


   

 

 

Valid XHTML 1.0 TransitionalValid CSS!

Copyright © 2010 Edouard Thiel Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.