Cours de programmation n°2
Procédures, fonctions, types et tableaux
Procédures et fonctions : principe
- Regrouper les actions répétées plusieurs fois (
FaireCi, FaireCa
).
- Exemple : demander un nombre, afficher un histogramme...
- On souhaite pouvoir paramétrer ces blocs d'instructions.
- On veut contrôler l'état initial et final.
Les paramètres
- Simple lecture de valeurs et/ou modification de la variable :
in
, out
, in out
.
out
nécessite un nom de variable.
- Exemple de
get(out)
et put(in)
.
- Paramètres formels (dans l'entête et le corps de la fonction) et effectif (à l'appel).
- Affectations implicites avant et après le corps.
- Notion de variable muette.
Procédure ou fonction
- Syntaxe des fonctions.
return
arrête tout.
- Paramètres
in
, objet du return out
.
- On peut toujours transformer une fonction en procédure avec un param
out
, mais à quoi bon ?
- Effets de bord des fonctions (
eff_bord.adb
).
- Variables locales ou globales, notion de portée.
procedure Proc_Ou_Fonc is
function Plus (X, Y : Integer) return Integer is
-- plus (x,y) = x+y
begin
return X+Y ;
end Plus ;
procedure Ajouter (X, Y : in Integer ; R : out Integer) is
-- e.i. indifferent (pas de condition). notons x0 la valeur de X, y0 la valeur de Y
-- e.f. R vaut x0 + y0.
begin
R := X + Y ;
end Ajouter ;
A, B, S : Integer ;
begin
Put_Line("Entrez deux nombres");
Get (A);
Get (B);
-- Pour imprimer la somme de A et B :
Put (Plus (A, B)) ; -- une fonction s'utilise dans une expression, comme en maths
-- ou :
Ajouter (A, B, S) ; -- une procedure s'utilise comme une action,
Put (S) ; -- par exemple dans une sequence, entre des points-virgules
-- put (Ajouter (A, B, ...)) n'a pas de sens
-- Plus (A, B) tout seul n'en a pas non plus
end Proc_Ou_Fonc ;
Exercice : Faire une procédure (une fonction?) qui échange le contenu de deux variables (Integer)
Types de variables
- Intérêts : contrôle, structuration, rangement : point fort de ADA.
- Types énumérés :
type Jour is (Lundi, Mardi, Mercredi, Jeudi, Vendredi, Samedi, Dimanche);
- Tous les entiers, les booléens et les caratères sont des types énumérés.
procedure types is
type Jour is (Dimanche, Lundi, Mardi, Mercredi, Jeudi, Vendredi, Samedi);
Merc : constant Jour := Mercredi;
Day : Jour;
begin
for j in Jour'Range loop
Put_Line( Jour'Image(j) );
end loop;
Put_Line( "Le premier jour est " & Jour'Image( Jour'First ) ); -- idem 'Last
Put_Line( "Le jour suivant " & Jour'Image( Merc ) & " est " & Jour'Image( Jour'Succ( Merc ) ) ); -- idem 'Pred
-- Le résultat est Mercredi, on compte à partir de 0 !
Put_Line( "Le 3ème jour est " & Jour'Image( Jour'Val(3) ) );
-- Le résultat est 4 !
Put_Line( "Jeudi est le " & Integer'Image( Jour'Pos(Jeudi) ) & " jour de la semaine" );
Day := Samedi;
-- La ligne suivante crée une erreur d'exécution.
Put_Line( "Après " & Jour'Image( Day ) & " c'est " & Jour'Image( Jour'Succ( Day ) ) );
end types;
- Types intervalle :
subtype JourOuvrable is Jour range Lundi..Vendredi;
subtype ZeroCent is Natural range 0..100;
Nombre_de_Lignes : constant Natural := 23;
subtype Numero_de_Ligne is Natural range 1..Nombre_de_Lignes;
-- permet de faire for i in Numero_de_Ligne loop ...
Renomage de type
type nombreTorchons is new Natural;
type nombreServiettes is new Natural;
Affectation mutuelle ou avec Natural
interdits : typage fort.
Types enregistrement : record
procedure type_enregistrement is
type Couleur is (Rouge, Vert, Bleu, Jaune);
type Figure is
record
X,Y : Integer range 0..1000;
Coul : Couleur;
end record;
cercle : Figure := (100,222,Rouge);
Carre : Figure;
procedure Afficher(Fig : in Figure) is
begin
Put("La figure est placée en (");
Put(Integer'Image(Fig.X) & "," & Integer'Image(Fig.Y));
Put_Line("), elle est de couleur " & Couleur'Image(Fig.Coul));
end Afficher;
begin
Carre.X := 34;
Carre.Y := 89;
Carre.Coul := Vert;
Afficher(Cercle);
Afficher(Carre);
end type_enregistrement;
Les tableaux
- Permettent de stocker plusieurs éléments (ex notes : max, moyenne).
- L'indice est de type intervalle ou énuméré, les éléments d'un type quelconque
- Accès direct à n'importe quelle valeur :
T(i)
- Ada teste la validité de l'indice.
- Différence entre indice et rang : utiliser
T'First, T'Last
. Nombre d'éléments avec T'length
- Affectation T1 := T2 possible, si le type a été défini.
- Utilisation comme paramètre de procédure ou fonction
type Tab is array (integer range 0..99) of Positive;
t1,t2,t3 : Tab;
Pluviosite : array (1..365) of Natural;
type Mois is (Janvier, Février, Décembre);
subtype nbJoursParMois is Natural range 28..31;
DureeMois : array (Mois) of nbJoursParMois;
begin
Pluviosite(23) := 34;
DureeMois(Février) := 28; -- ou 29
end;
Tableaux non contraints
type tabint is array (integer range <>) of integer ;
Doivent être instanciés pour être utilisables :
type TabInt is array (Integer range <>) of Integer;
procedure AfficheTab(T : in TabInt) is
begin
for I in T'Range loop -- Range est très utile ici
Put_Line("La valeur de T(" & Integer'Image(I) & ") est " & Integer'Image(T(I)));
end loop;
end AfficheTab;
MonTab : TabInt(1..5); -- Il faut donner les bornes quand on en crée une variable
begin
MonTab(1) := 51; -- etc...
AfficheTab(MonTab);
end tableaux;
Tableaux dynamiques, declare
au milieu des instructions.
N : natural ;
type Truc is ... ;
begin
put("Nombre de trucs a stocker :");
get (N) ;
declare
T : array (1..N) of Trucs ;
-- noter que si l'on tape 0, le tableau est vide.
begin
-- utiliser T
-- si on modifie N, la taille de T ne change pas.
end ;
end ;
Tableaux à plusieurs dimensions
type MatriceInt is array (integer range <>, integer range <>) of integer ;
subtype carre3 is MatriceInt (1..3, 1..3);
subtype rectangle34 is MatriceInt (1..3, 1..4);
C : carre3 ;
R : rectangle34 ;
...
C (i, j) ; -- acces aux elements
Tableaux créés pré-remplis
T : array ( 1..12 ) of integer := (others => 0); -- tout à 0
T : array (1..4) of integer := (1, 6, 3, 9); -- toutes les valeurs, par position
-- ou (1 => x, 2..4 => 0); -- des intervalles d'indices
-- ou (1|3 => x, 2 => 0, ... ); -- des cas non adjacents
-- ou ( ..... , others=>0); -- tous les cas restants.
M : array (1..3, 1..4) of integer :=
( 1 => (0, 1, 2, 3),
2 => (1|3 => 4, 2|4 => 7),
3 => (others => 42)) ;
Le type String
, un tableau de Character;
Comme si on avait : type String is array (positive range <>) of Character
S : String := "toto" ; -- indices 1..4
Opérations sur les tableaux
T1 := T2; -- Affectation de toutes les cases
T1(1..5) := T2(3..7); -- Affectations de tranches
if (T1 = T2) then Put_Line("Tableaux identiques"); end if;
Parcours d'un tableau
T : array (1..12) of chose;
for i in T'Range loop
-- traiter l'objet T(i) qui est de type chose
end loop ;
- Utiliser
Range
et non 1..12
pour l'évolutivité.
- Exercice : moyenne d'un tableau d'entiers.
- Parcours 2D : plusieurs
for
imbriqués.
Recherche dans un tableau
- Problème avec le while et les intervalles d'indice : on risque de sortir de l'intervalle :
T : array (1..12) of Positive;
i : integer range T'range ;
begin
i := T'first ;
while i <= T'last loop
exit when T(i)... ;
i := i+1 ;
end loop ;
if (i > T'Last) then
-- pas trouve
else
-- T(i) vérifie la propriété
end ;
On prendra généralement un while
, sans contrainte sur i
, ou dans T'first..T'last+1
.
Combinaison de for
et exit
: on ne sait pas si on a trouvé et où :
for i in T'range loop
if T(i) .. then exit; end if;
end loop ;
Structure record
du résultat
type typelt is ... ;
type tab is array (integer range <>) of typelt ;
type resultat is record
indice : integer ;
trouve : boolean ;
end record ;
function P (x : typelt) return boolean is
begin
-- la propriété
...
end ;
function ChercherP (T : tab) return resultat is
begin
for i in T'range loop
if P(T(i)) then return (i,true) ; end if ;
end loop ;
return (0, false) ;
-- il faut bien mettre une valeur pour l'indice,
-- mais elle n'est pas significative.
end ChercherP ;
Tableau sous utilisé
- On ne connait pas exactement la taille, ou elle va varier : on prévoit un peu large.
- On conserve le nombre
L
d'éléments réélement stockés : indices valides dans T'first..T'first+L-1
- On peut aussi mettre une valeur spécifique pour marquer la fin, mais c'est moins bien.
- Exemple : insertion dans une séquence triée
procedure inserer(T : in out Tab, X : in Positive) is
i : Integer;
begin
-- On cherche tout d'abord la position d'insertion :
i:= T'first ;
while i <= T'first+L-1 and X >= T(i) loop
-- invariant : la tranche T(T'first..i) contient des elements <= X
i := i+1;
end loop ;
-- ici : i=T'first+L (et c'est encore dans T, puisqu'on a suppose qu'il reste
-- de la place, mais c'est un element non pertinent.) ou alors X < T(i).
-- dans ces deux cas, il faut inserer X dans la case d'indice i.
--On décale toute une portion de tableau pour faire de la place :
for k in reverse i+1..T'first+L loop
T(k) := T(k-1);
end loop ;
-- on a écrasé T(T'first+L) et libéré la case i
T(i) := X;
-- On met à jour la taille réelle du tableau
L := L+1;
end inserer;
Exercice : Suppression dans un tableau sous-utilisé trié
Traitement de tableaux en place
- On modifie un tableau sans mémoire auxilliaire.
- Exemple : suppression des espaces, tri.
- Exercice : Drapeau
- Exercice : Matrice 2D : Affichage, Multiplication, transposée