Le langage Pascal


précédentsommairesuivant

Procédures et Fonctions

Nous avons déjà vu un certain nombre de procédures (WRITELN) et fonctions (SQRT, SIN...) prédéfinies par le compilateur. Mais si l'on en désire d'autres, il suffit de les définir.

Généralités

On peut regrouper un ensemble d'instructions sous un même nom. On forme alors un sous-programme ou procédure. On utilise les procédures :

  • Chaque fois qu'une même suite d'instructions doit être répétée plusieurs fois dans un programme;
  • Quand une suite d'instructions forme une action globale. Le programme est alors plus clair et les erreurs plus facilement détectables.

Pour pouvoir utiliser une procédure, il faut d'abord la déclarer. La déclaration des procédures et fonctions se fait après toutes les autres déclarations.

Structure d'une entité de programme (routine)

  • Entête
  • Déclaration des :
    - Labels; (pour les GOTO, déconseillé)
    - Constantes;
    - Types;
    - Variables.
  • Définition des sous-routines; (sous-programmes)
  • BEGIN
    ... Instructions ...
    END.

Le programme principal comme les procédures et les fonctions ont toujours cette structure. L'entête est composée d'un mot clef (PROGRAM, PROCEDURE ou FUNCTION), suivi de l'identificateur (nom) de la routine, et de la liste des arguments entre parenthèses. Les arguments forment la liaison avec l'extérieur de la routine (clavier, écran et éventuellement fichiers pour le programme).

 
Sélectionnez

PROGRAM remplir (output);
   {entête du prog principal}

VAR i : integer;
   {déclarations prog princ.} 

   {dont déclaration LIGNE}
PROCEDURE ligne(n:integer);
   {entête de la procédure} 
var j : integer;
   {déclarations procédure}
BEGIN
  {corps de la procédure}
  for j := 1 to n do write('*');
  writeln 
END;

BEGIN
  {instructions du prog princ}
  for i := 1 to 25 do ligne(70)
END.

La procédure LIGNE écrit N caractères '*' sur une même ligne. Le programme remplit donc l'écran (25 lignes 70 colonnes) d'étoiles.

On peut appeler une procédure déclarée dans une routine n'importe où dans cette routine en indiquant simplement son nom comme si c'était une instruction. A l'appel d'une procédure, le programme interrompt son déroulement normal, exécute les instructions de la procédure, puis retourne au programme appelant et exécute l'instruction suivante. Tout ce passe donc comme si le nom de la procédure était remplacé dans le programme par les instructions de la procédure (avec n = 70).

Portées des déclarations

Celle-ci est symbolisée dans l'exemple ci-dessus par deux cadres : la variable I et la procédure LIGNE (avec un argument entier) sont déclarées dans REMPLIR, et donc connues dans tout le programme (rectangle extérieur). Par contre N et J sont déclarés dans LIGNE et ne sont connus (et utilisables) que dans le rectangle intérieur.

En d'autres termes :

  • Une variable est locale pour une procédure X si elle est déclarée dans X. Elle n'existe que dans X (et dans les procédures déclarées à l'intérieur de X). La routine qui comporte la procédure X ne peut donc pas accéder à cette variable locale.
  • Une variable est globale pour une procédure X si elle est déclarée dans une routine englobant la procédure X. Elle peut être utilisée dans la procédure. La modifier la modifie également dans la routine appelante (englobante).

Si l'on avait déclaré une variable I dans la procédure LIGNE (au lieu de N ou J), celle-ci aurait été locale à la procédure, c'est à dire que, dans le programme principal, I désigne une autre case mémoire que dans la procédure. Modifier la variable localeI ne modifie pas la variable globaleI (momentanément inaccessible).

Remarque : Ceci s'applique à toutes les déclarations. En particulier, une procédure déclarée localement à l'intérieur d'une procédure est indéfinie à l'extérieur.

Arguments(ou paramètres)

Les échanges d'informations entre une routine et une sous-routine peuvent se faire par l'intermédiaire des variables globales. Mais il est beaucoup plus intéressant d'utiliser les paramètres : (6)

 
Sélectionnez
 
PROGRAM machin (input,output);

VAR
  a, b, c, d : real;

PROCEDURE aff_somme(x,y:real);
var z : real;
begin
  z := x + y;
  writeln(x ,' + ', y ,' = ', z)
end;

BEGIN {	programme principal }
  writeln('Entrez 4 valeurs :');
  readln(a,b,c,d); 
  aff_somme(a,b); 
  aff_somme(3,5); 
  aff_somme(c+a,d) 
END.

En appelant AFF_SOMME(A,B), la procédure prend pour x la valeur de a, et pour y la valeur de b. On dit que les arguments sont passés par valeur. Mais si la procédure modifiait x ou y, a et b ne seraient pas modifiés dans le programme appelant. Pour répercuter les modifications des arguments, il faut les déclarer comme variables (ils sont alors dits passés par adresse).

 
Sélectionnez
 
PROCEDURE echange (VAR x, y : real); 
var z : real; 
begin 
  z := x; 
  x := y; 
  y := z 
end; {cette procédure échange les contenus des 2 arguments} 

Les fonctions

Tout ce qui a été dit pour les procédures s'applique également aux fonctions. La différence avec une procédure est qu'une fonction renvoie un résultat.

L'entête est du type :

 
Sélectionnez

FUNCTION nom_fonction (liste_parametres) : type_de_la_fonction

La liste des paramètres (en général passés par valeur) est de la même forme que pour une procédure, le type de la fonction étant le type du résultat retourné. On retourne le résultat par :

 
Sélectionnez

NOM_FONCTION := ...

Exemple :

 
Sélectionnez
 
PROGRAM classer (input,output); 

VAR a, b, c : real; 

FUNCTION max (x, y : real) : real; 
begin 
  if x >= y then 
    max := x 
  else max := y 
end; 

BEGIN
  writeln('Entrez deux valeurs : '); 
  readln(a,b); 
  c := max(a,b); 
  writeln('Le plus grand est ',c) 
END. 

La fonction max a deux paramètres réels (x et y) et renvoie un réel.

Récursivité

C'est ainsi que l'on appelle le fait qu'une routine puisse s'appeler elle-même.

 
Sélectionnez
 
function factorielle (n : integer) : integer; 
begin 
  if n <= 1 then 
    factorielle := 1 
  else 
    factorielle := n * factorielle(n - 1) 
end;

Par exemple, en appelant factorielle(3), on calcule 3 * factorielle(2). Or, factorielle(2) = 2 * factorielle(1), qui lui vaut 1. Donc factorielle(3) = 3 * (2 * 1) (ce qui me parait juste). Faites un petit dessin, à chaque appel on recrée de nouvelles variables locales, donc on obtient 3 cases n distinctes valant 3, 2 et 1, on les supprime petit à petit en passant sur le END.

Remarque : Il faut toujours vérifier qu'en aucun cas on ne puisse avoir une boucle infinie qui bloquerait la machine. Ce serait le cas en mettant le test IF N = 1 et en appelant factorielle pour une valeur négative ou nulle.

Une procédure devant toujours être déclarée pour pouvoir être utilisée, on utilise FORWARD pour les cas de récursivité passant par deux procédures :

 
Sélectionnez
 
function prem (a, b : real) : boolean; FORWARD; { déclaration anticipée de l'entête }

procedure deux (x, y : real);
var vbool : boolean;
begin
  ......
  vbool := prem(x,y); { on peut utiliser PREM car déjà déclarée }
  ......
end;

function prem; { ne plus donner les arguments car déjà déclarés }
begin
  ......
  if pas_fini then
     deux(a,b); { DEUX déjà déclarée }
  ......
end; 

Exercicerec :
Ecrire le programme qui calcule le déterminant d'une matrice carrée NxN sachant que celui-ci vaut :
sigma
où M[i,1] est l'élément de la matrice (ligne i, 1ère colonne),
DETn-1 est le déterminant de la sous-matrice d'ordre n-1 obtenu en ôtant la ligne i et la 1ère colonne.
Le déterminant d'une matrice 1x1 est son seul élément.
On utilisera bien évidement une fonction récursive, et l'on séparera le calcul de sous-matrice dans une procédure.
Remarque : Il existe des méthodes numériques permettant d'accéder au résultat beaucoup plus rapidement que par cette méthode.
Voir la correction


précédentsommairesuivant
Note de la rédaction : La meilleure manière de penser une sous-routine est de la considérer comme un tout autonome et donc de lui fournir tout ce dont elle a besoin par l'intermédiaire de paramètres.

Utilisation de ce document libre pour tout usage personnel. Utilisation autorisée pour tout usage public non commercial, à condition de citer son auteur (Patrick Trau, IPST, Université Louis Pasteur Strasbourg) et de me signaler tout usage intensif. Utilisation commerciale interdite sans accord écrit de ma part.