Aller au contenu

%ELEM

Nombre d'éléments d'un tableau

Renvoie le nombre d'éléments d'un tableau : sa dimension déclarée, ou, pour un tableau dim(*auto), le nombre d'éléments actuellement utilisés.

Syntaxe

%ELEM(tableau)
%ELEM(tableau : *MAX)
tableau
Un tableau de zones, ou un tableau de structures de données (dcl-ds … dim(n)).
*MAX
Pour un tableau dim(*auto : max) seulement : renvoie la dimension maximale max au lieu du nombre d'éléments en cours.
Résultat
Un entier. Pour un tableau à dimension fixe, c'est une constante connue à la compilation (on peut donc l'utiliser dans un dcl-c). Pour un tableau dim(*auto), c'est le nombre d'éléments ajoutés ; il peut aussi être affecté pour réduire ou vider le tableau.

À quoi ça sert

On écrit for i = 1 to %elem(villes) plutôt que for i = 1 to 5 : si la dimension change dans la déclaration, toutes les boucles suivent, sans aller les chercher une par une.

Avec dim(*auto), le tableau devient une vraie liste : tableau(*next) = valeur ajoute un élément, %elem dit combien il y en a, et on n'a plus besoin d'un compteur à part.

Exemple 1 : Tableau à dimension fixe

**free
// %ELEM : nombre d'elements d'un tableau, dimension fixe ou dim(*auto).
ctl-opt dftactgrp(*no) actgrp(*new);

dcl-s villes char(12) dim(5);
dcl-ds ligne qualified dim(3);
  numcli packed(5:0);
  nom    char(20);
end-ds;
dcl-s i int(10);
// %elem est une constante calculee a la compilation.
dcl-c NB_VILLES %elem(villes);

ligne(1).numcli = 100;
ligne(1).nom = 'Dupont SA';
villes(1) = 'Montpellier';
villes(2) = 'Lyon';

// La dimension est fixe : 5 elements, meme si 2 seulement sont remplis.
snd-msg 'Elements de villes : ' + %char(%elem(villes));
snd-msg 'Elements de ligne  : ' + %char(%elem(ligne));

// Parcours complet grace a %elem : le compilateur garde la borne a jour.
for i = 1 to %elem(villes);
  snd-msg 'villes(' + %char(i) + ') = [' + villes(i) + ']';
endfor;

snd-msg 'Constante NB_VILLES = ' + %char(NB_VILLES);

*inlr = *on;

Résultat réel, compilé et exécuté sur IBM i 7.5 :

Elements de villes : 5
Elements de ligne  : 3
villes(1) = [Montpellier ]
villes(2) = [Lyon        ]
villes(3) = [            ]
villes(4) = [            ]
villes(5) = [            ]
Constante NB_VILLES = 5

Le tableau villes a 5 éléments dont 2 seulement sont remplis : %elem répond 5. Il en va de même pour le tableau de structures ligne, dont la dimension est 3. Comme la valeur est connue à la compilation, elle peut servir à définir la constante NB_VILLES.

Exemple 2 : dim(*auto) : un tableau qui grandit

**free
// %ELEM avec dim(*auto) : le nombre d'elements suit le contenu du tableau.
ctl-opt dftactgrp(*no) actgrp(*new);

dcl-s noms varchar(20) dim(*auto : 100);
dcl-s i int(10);

snd-msg 'Au depart : ' + %char(%elem(noms));
snd-msg 'Maximum   : ' + %char(%elem(noms : *max));

noms(*next) = 'Dupont SA';
noms(*next) = 'Martin et fils';
noms(*next) = 'Leroy SARL';
snd-msg 'Apres 3 ajouts : ' + %char(%elem(noms));

for i = 1 to %elem(noms);
  snd-msg 'noms(' + %char(i) + ') = [' + noms(i) + ']';
endfor;

// Reduire ou vider : on affecte %elem.
%elem(noms) = 1;
snd-msg 'Apres reduction : ' + %char(%elem(noms));
%elem(noms) = 0;
snd-msg 'Apres vidage    : ' + %char(%elem(noms));

*inlr = *on;

Résultat réel, compilé et exécuté sur IBM i 7.5 :

Au depart : 0
Maximum   : 100
Apres 3 ajouts : 3
noms(1) = [Dupont SA]
noms(2) = [Martin et fils]
noms(3) = [Leroy SARL]
Apres reduction : 1
Apres vidage    : 0

Au départ le tableau est vide : %elem vaut 0, alors que %elem(noms : *max) donne le maximum (100). Chaque noms(*next) = … ajoute un élément et %elem suit. On peut ensuite affecter %elem pour réduire le tableau (1) ou le vider (0).

Exemple 3 : Dépasser le maximum de dim(*auto)

**free
// dim(*auto : 2) : le maximum est une vraie limite, %elem ne le depasse jamais.
ctl-opt dftactgrp(*no) actgrp(*new);

dcl-s ville varchar(20) dim(*auto : 2);

ville(*next) = 'Lyon';
ville(*next) = 'Brest';
snd-msg 'Elements : ' + %char(%elem(ville)) + ' sur ' + %char(%elem(ville : *max));

// Le troisieme ajout depasse le maximum : le programme s'arrete.
ville(*next) = 'Rennes';
snd-msg 'Cette ligne n''est jamais atteinte';

*inlr = *on;

Résultat réel, compilé et exécuté sur IBM i 7.5 :

Elements : 2 sur 2
Erreur : RNQ0124 - 3 n'est pas un nombre d'éléments valide pour le tableau (C G D F).

Le maximum déclaré (2) est une vraie limite : le troisième (*next) arrête le programme avec le message RNQ0124. Il faut donc prévoir un maximum assez large.

Le piège

Sur un tableau à dimension fixe, %elem ne compte pas les éléments remplis. Il renvoie toujours la dimension déclarée : 5 pour villes dans le premier exemple, alors que deux éléments seulement contiennent une valeur. Les autres sont à blanc (ou à zéro pour un tableau numérique) et une boucle sur %elem les parcourt aussi.

Pour un nombre d'éléments utiles, il faut soit un compteur tenu à la main, soit un tableau dim(*auto). Et avec dim(*auto), on ne dépasse pas le maximum : le troisième exemple s'arrête sur RNQ0124.