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

Algorithmes et programmation en Pascal


précédentsommairesuivant

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

 
Sélectionnez
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.

 
Sélectionnez
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 :

 
Sélectionnez
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.

Amé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

 
Sélectionnez
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 !

Erreur 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.

 
Sélectionnez
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 ]

 
Sélectionnez
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);

 
Sélectionnez
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.

 
Sélectionnez
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 :

 
Sélectionnez
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.


précédentsommairesuivant

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2010 Edouard Thiel. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.