|
|
Chapitre 14 — Groupement de Données en tableaux
Pour des raisons qui deviendront apparentes, les tableaux sont souvent utilisés
en conjonction avec les boucles, étudiées précédemment. Pour illustrer le besoin de tableaux, faisons comme si
vous travailliez sur un jeu de
« Space Invaders ».
Quelque part vers la fin du code, vous avez besoin de savoir s'il reste des extra-terrestres
en vie pour que vous puissiez commencer un nouveau niveau.
Si chaque « alien » a une variable pour dire s'il est toujours
vivant, vous pourriez faire ceci :
REM ...
NouvoNiveau=TRUE : REM Nouveau niveau supposé
IF Alien1Vivant THEN NouvoNiveau=FALSE
IF Alien2Vivant THEN NouvoNiveau=FALSE
IF Alien3Vivant THEN NouvoNiveau=FALSE
IF NouvoNiveau THEN
REM mettre en place le nouveau niveau
ENDIF
REM ...
La première ligne suppose qu'un nouveau niveau est demandé. Le programme inspecte
alors le drapeau (flag) de chaque AlienXVivant l'un après l'autre,
et si cet alien est toujours vivant, remet le drapeau NouvoNiveau à faux.
S'il termine son contrôle et que le drapeau soit toujours vrai, tous les aliens doivent être morts,
aussi alignez-les et recommencez.
Question : que se passe-t-il s'il y a 40 aliens ? Ou 100 ?
En utilisant cette méthode, cela fait beaucoup de lignes de code. Il doit y avoir une meilleure façon :
DIM AlienVivant(50)
REM ...
NouvoNiveau=TRUE : REM Nouveau niveau supposé
FOR I%=1 TO 50
IF AlienVivant(I%) THEN NouvoNiveau=FALSE
NEXT I%
IF NouvoNiveau THEN
REM mettre en place le nouveau niveau
ENDIF
REM ...
La première chose rencontrée, c'est le mot-clé
DIM.
DIM
veut dire DIMension et c'est une instruction donnée à l'ordinateur
pour réserver une zone de mémoire pour une variable tableau. On dit au
BASIC
combien de variables le tableau contient en l'indiquant entre parenthèses après le nom.
Dans ce cas, nous disons à l'ordinateur que nous avons 50 aliens, aussi lui demandons-nous
de réserver 50 emplacements, un pour chacun. Précédemment, nous avons laissé le
BASIC
définir nos variables la première fois qu'on s'en servait, mais un tableau est différent.
En définissant la taille d'un tableau, le
BASIC
peut effectuer un contrôle chaque fois qu'il est utilisé dans le code. Si nous essayons d'accéder
à l'extérieur du tableau, le
BASIC
nous préviendra en arrêtant le programme et en produisant un message amical (c'est-à-dire que le programme
se bloque). Bien que ce ne soit pas obligatoire, c'est une bonne habitude de déclarer tous les
tableaux au début du programme. Cela permet de les ranger tous ensemble au même endroit et d'avoir
mis de côté toutes les allocations de mémoire quand le programme commence.
Une fois qu'il a été déclaré, nous pouvons utiliser le tableau pratiquement comme n'importe
quelle autre variable ; on accède à chaque élément individuel en spécifiant son numéro :
AlienVivant(1), AlienVivant(39) ou, comme dans la ligne IF AlienVivant(I%)...,
en nous servant du compteur d'une boucle
FOR
pour décider quel élément nous voulons examiner. En utilisant cette méthode, nous pouvons vérifier
autant d'aliens que nous le voulons, le tout dans le même nombre de lignes de code.
Voici un exemple complet qui stocke les niveaux pour un certain nombre d'élèves, puis fait
quelque chose avec les données :
REM Programme de niveau des élèves
DIM Niveau%(5)
REM D'abord, recueillir les données
FOR I%=1 TO 5
PRINT "Élève n° ";I%;". - Niveau : ";
INPUT Niveau%(I%)
NEXT I%
REM Calculer la moyenne
Ttal%=0
FOR I%=1 TO 5
Ttal%=Ttal%+Niveau%(I%)
NEXT I%
REM Afficher la moyenne
PRINT "Le niveau moyen était ";Ttal%/5
REM Trouver le niveau minimum
Minimum%=999
FOR I%=1 TO 5
IF Niveau%(I%)<Minimum% THEN
Minimum%=Niveau%(I%)
ENDIF
NEXT I%
REM Afficher le minimum
PRINT "Le niveau minimum était ";Minimum%
END
Faites de la place pour 100 élèves, si vous voulez, en changeant les lignes concernées, mais vous risquez
de vous ennuyer à entrer toutes ces données !
BBC BASIC
donne en fait un véritable élément supplémentaire : lorsque vous déclarez Niveau%(5) vous obtenez
6 éléments : Niveau%(0) à Niveau%(5). Dans la pratique, il est
le plus souvent plus facile d'ignorer le premier élément parce qu'il est dans la nature humaine de penser
aux élèves sous la forme élève 1, élève 2, etc., et non élève 0. Mais l'élément zér
est là si vous en avez besoin.
Tous les éléments d'un tableau sont mis à zéro – dans le cas des chaînes,
ils sont définis comme des chaînes nulles – au moment de la déclaration, et une fois qu'ils
ont été déclarés vous ne pouvez pas redimensionner le tableau en le déclarant à nouveau plus tard.
Ce peut être utile de songer à un tableau comme à une collection de boîtes, aussi si nous avons,
pour les élèves ci-dessus, entré des valeurs de 40, 80, 60, 70 et 55, voici comment elles seraient
stockées :
| Élément | 0 | 1 | 2 | 3 | 4 | 5 |
| Valeur | 0 | 40 | 80 | 60 | 70 | 55 |
Vous pouvez déclarer des tableaux à plus d'une dimension. Si vous pensez à
une grille (comme la grille imaginaire qu'on utilise pour placer des caractères sur l'écran) nous aurions
un tableau à deux dimensions :
DIM Grille%(5,5)
Ceci définirait une grille de 6 par 6 cellules (souvenez-vous de l'élément 0). Voici comment cela se présenterait dans notre schéma de boîtes :
| Élément | 0 | 1 | 2 | 3 | 4 | 5 |
| 0 | | | | | | |
| 1 | | | | | | |
| 2 | | | | | | |
| 3 | | | | | | |
| 4 | | | | | | |
| 5 | | | | | | |
Chaque ligne a 6 colonnes, comme on le voit ci-dessus. On y accède par Grille%(0,0),
Grille%(0,1), Grille%(0,2) ... Grille%(0,5) et puis Grille%(1,0),
Grille%(1,1) ... Grille%(1,5), etc., jusqu'à Grille%(5,5). Dans chacun de ces emplacements
nous pouvons mettre une valeur, c'est-à-dire dans 36 emplacements en tout. Comme vous pouvez le voir, ceci nous
donne une façon puissante de regrouper les informations.
On peut définir un tableau à 3 dimensions :
DIM Grille%(10,10,10)
Si vous imaginez une grille à deux dimensions sous la forme d'une page, nous venons de déclarer 11 pages,
chacune contenant une grille carrée de 11 éléments de côté. Si vous travaillez avec la
version de démonstration,
les tableaux sont une magnifique façon de se trouver à court de mémoire. Réfléchissez-y : il y a
11*11*11 = 1331 éléments dans ce tableau, aussi faites très attention avant de vous laisser
emporter. Pour être réaliste, à la différence d'autres langages
BASIC, avec
« BB4W »
vous pouvez déclarer autant de dimensions que vous voulez, mais dans la pratique les programmeurs
en utilisent rarement plus de 3.
Initialisation des tableaux
READ, DATA et RESTORE
Les tableaux peuvent être utilisés pour stocker des données, mais l'un des problèmes, c'est de
faire entrer les données dans le tableau. Dans le programme de niveau d'élèves ci-dessus, il est facile
d'entrer les données parce que chaque fois que vous exécutez le programme, vous voudrez probablement
entrer des valeurs différentes. Considérez ceci :
REM Jours du mois
DIM Mois%(12)
REM D'abord, recueillir les données
FOR I%=1 TO 12
PRINT "Nombre de jours du mois ";I%;" : ";
INPUT Mois%(I%)
NEXT I%
REM Maintenant demander un mois
INPUT "Entrez le numéro du mois : " M%
PRINT "Le mois ";M%;" a ";Mois%(M%);" jours."
END
Cela semble vraiment aller à l'encontre de nos intentions, n'est-ce pas ? Le
BASIC,
bien sûr, est arrivé avant nous et nous fournit une façon de fixer les variables et les tableaux
qui seront les mêmes à chaque fois.
REM Jours du mois
DIM Mois%(12)
REM D'abord, recueillir les données
FOR I%=1 TO 12
READ Mois%(I%)
NEXT I%
REM Maintenant demander un mois
INPUT "Entrez le numéro du mois : " M%
PRINT "Le mois ";M%;" a ";Mois%(M%);" jours."
END
DATA 31,28,31,30,31,30,31,31,30,31,30,31
Et voilà : c'est beaucoup mieux. Il y a deux mots-clés ici :
READ
et
DATA.
DATA
contient simplement cela : une collection de données (data), numériques ou chaînes,
qui peuvent être utilisées dans le programme. Ce que représentent les data et l'ordre dans lequel
vous les mettez, cela ne regarde que vous. Quand le programme rencontre une instruction
READ,
il part à la recherche de la prochaine instruction
DATA.
Il reporte ensuite la valeur trouvée dans la variable donnée, un peu comme
INPUT. Le
BASIC
se souvient de l'endroit où il était arrivé, aussi la prochaine fois qu'il rencontre
READ,
il continue à partir de cet endroit.
Bien évidemment, il doit y avoir autant de données que d'instructions
READ
(y compris le nombre de fois que
READ
est appelé dans une boucle) sinon le programme va être bouleversé. Vous n'avez pas l'obligation d'utiliser
READ
avec des tableaux seulement ; il est tout à fait acceptable de définir des variables uniques
en utilisant cette méthode, mais avec une boucle il est possible d'initialiser un tableau
avec très peu de lignes de code.
Les instructionsDATA
peuvent être découpées de la façon qui vous convient, par exemple, nous aurions pu écrire :
DATA 31,28,31,30,31
DATA 30,31,31,30,31
DATA 30,31
ou même :
DATA 31
DATA 28
DATA 31
DATA 30
DATA 31
DATA 30
DATA 31
DATA 31
DATA 30
DATA 31
DATA 30
DATA 31
Le programmeur, c'est vous : ça dépend de vous. Assurez-vous seulement qu'il y a autant de données
DATA
à lire qu'il y a de
READ.
Vous pouvez mêler et assortir des données, pour autant que vous lisiez le type de données correct
dans la variable correcte.
REM Jours du mois
DIM Mois%(12), Nom$(12)
REM D'abord, recueillir les données
FOR I%=1 TO 12
READ Mois%(I%)
READ Nom$(I%)
NEXT I%
REM Maintenant demander un mois
INPUT "Entrez le numéro du mois : " M%
PRINT Nom$(M%);" a ";Mois%(M%);" jours."
END
DATA 31,janvier,28,février,31,mars
DATA 30,avril,31,mai,30,juin
DATA 31,juillet,31,août,30,septembre
DATA 31,octobre,30,novembre,31,décembre
Les instructions
DATA
peuvent être placées n'importe où dans le programme, le
BASIC
se contentera de les ignorer jusqu'à ce qu'on lui dise de les utiliser. Elles sont habituellement placées
au bas du programme après
END,
ainsi elles n'encombrent pas le code, à l'exception de ce qui est indiqué ci-dessous.
Il y a des occasions où il est nécessaire de relire une série de données.
Supposez que vous ayez un jeu de valeurs par défaut qui pourraient être réinitialisées à partir d'une option
dans un menu. Pour forcer le pointeur des données à retourner à un endroit précis, nous utilisons la commande
RESTORE.
RESTORE a quelques options, dont la première ne prend pas d'argument et réinitialise
le pointeur de données à la première instruction
DATA
du programme.
Un autre usage est de spécifier un numéro de ligne. (Les numéros de lignes sont discutés
dans l'Appendice A. Si vous n'êtes pas familiarisé avec ces numéros, le consensus général
aujourd'hui est que vous ne manquez pas grand chose mais vous pourriez avoir envie d'y aller jeter
un coup d'œ rapide.) En utilisant
RESTORE
avec un numéro de ligne on réinitialise le pointeur de données à la première donnée de la ligne indiquée.
Ce peut être utile pour spécifier des séries de données alternatives.
10 REM Les mois en français et en anglais
20 DIM Mois$(12)
30 REM D'abord, recueillir les données
40 INPUT "Les mois en anglais ? (o/n) " Rep$
50 IF Rep$="N" OR Rep$="n" THEN
60 RESTORE 210
70 ELSE
80 RESTORE 170
90 ENDIF
100 FOR I%=1 TO 12
110 READ Mois$(I%)
120 NEXT I%
130 REM Maintenant demander un mois
140 INPUT "Entrez le numéro du mois : " M%
150 PRINT "Le mois ";M%;" est ";Mois$(M%)
160 END
170 DATA January,February,March
180 DATA April,May,June
190 DATA July,August,September
200 DATA October,November,December
210 DATA janvier,février,mars
220 DATA avril,mai,juin
230 DATA juillet,août,septembre
240 DATA octobre,novembre,décembre
Le numéro de ligne peut être calculé si nécessaire.
Pour ôter les numéros de lignes,
RESTORE
nous fournit encore une autre option. Là, nous spécifions un décalage à partir de la ligne
qui contient l'instruction
RESTORE
(et PAS la ligne avec la première instruction
DATA).
Le nombre donné dit au
BASIC
de combien de lignes il doit avancer à partir de la position actuelle. Pour indiquer cela, on se sert
d'un décalage et non d'un numéro de ligne ; le nombre doit être précédé par un signe +.
Voici le programme précédent sans les numéros de lignes, en nous servant de cette méthode. Examinez les nombres
dans les lignes
RESTORE
et comptez vers le bas pour voir où chacune pointe.
REM Les mois en français et en anglais
DIM Mois$(12)
REM D'abord, recueillir les données
INPUT "Les mois en anglais ? (o/n) " Rep$
IF Rep$="N" OR Rep$="n" THEN
RESTORE +15
ELSE
RESTORE +9
ENDIF
FOR I%=1 TO 12
READ Mois$(I%)
NEXT I%
REM Maintenant demander un mois
INPUT "Entrez le numéro du mois : " M%
PRINT "Le mois ";M%;" est ";Mois$(M%)
END
DATA January,February,March
DATA April,May,June
DATA July,August,September
DATA October,November,December
DATA janvier,février,mars
DATA avril,mai,juin
DATA juillet,août,septembre
DATA octobre,novembre,décembre
Ici, on ne peut aller qu'en avant, c'est-à-dire vers le bas. Essayez de spécifier un décalage négatif et le
BASIC
va se plaindre. Les lignes sont ici les lignes physiques réelles, y compris les lignes en blanc et les lignes
REM,
et pas seulement celles qui contiennent du code. Comme on peut le voir, si le programme devait être étendu,
nous pourrions facilement perdre la trace des décalages et créer le chaos. Peut-être cette méthode
est-elle mieux employée quand les
DATA
sont proches de l'instruction
RESTORE.
REM ...
IF Rep$="N" OR Rep$="n" THEN
RESTORE +8
ELSE
RESTORE +2
ENDIF
DATA January,February,March
DATA April,May,June
DATA July,August,September
DATA October,November,December
DATA janvier,février,mars
DATA avril,mai,juin
DATA juillet,août,septembre
DATA octobre,novembre,décembre
Dans chacune des méthodes ci-dessus, s'il n'y a pas de données à la ligne indiquée par
RESTORE, le
BASIC
cherche la ligne suivante qui contient des
DATA
et l'utilise à la place.
Initialisation sans READ ni DATA
Il est possible d'initialiser un tableau directement avec du code. Ceci évite d'utiliser
les instructions
DATA et
READ,
et c'est plus en accord avec la façon dont des langages comme le
C
font cette sorte de choses. Le premier exemple initialise tous les éléments après la déclaration du tableau.
N'oubliez pas que MonTableau%(3) a 4 éléments de 0 à 3, aussi
avons-nous besoin de 4 valeurs.
REM Initialisation en ligne
DIM MonTableau%(3)
MonTableau%() = 1,2,3,4
FOR I%=0 TO 3
PRINT MonTableau%(I%)
NEXT I%
END
Ceci peut être fait à tout moment, et pas seulement juste après la déclaration du tableau.
REM Initialisation en ligne
DIM MonTableau%(3)
MonTableau%() = 1,2,3,4
FOR I%=0 TO 3
PRINT MonTableau%(I%)
NEXT I%
MonTableau%() = 5,6,7,8
FOR I%=0 TO 3
PRINT MonTableau%(I%)
NEXT I%
END
Si vous donnez moins de nombres qu'il y a d'éléments, seuls les nombres donnés sont initialisés.
REM Initialiser les trois premiers éléments
DIM MonTableau%(3)
MonTableau%() = 1,2,3
FOR I%=0 TO 3
PRINT MonTableau%(I%)
NEXT I%
END
Cependant – et ceci est vraiment utile – on peut prédéfinir un tableau tout entier
si l'on ne donne qu'une seule valeur. C'est excellent pour initialiser de gros tableaux.
REM Affecter 50 à chaque élément
DIM MonTableau%(100)
MonTableau%() = 50
FOR I%=0 TO 100
PRINT MonTableau%(I%)
NEXT I%
END
Les tableaux multidimensionnels ne posent pas de problème, tant que vous respectez l'ordre :
de droite à gauche. Dans cet exemple, la ligne est partagée en deux. Ça ne fait rien, mais vous devez
pourtant inclure une virgule à la fin de la ligne coupée, exactement comme vous feriez si
elle était continue.
REM Initialisation tableau multidimensionnel
DIM MonTableau%(2,3)
MonTableau%() = 1,2,3,4,10,20,30, \
\ 40,100,200,300,400
FOR I%=0 TO 2
FOR J%=0 TO 3
PRINT MonTableau%(I%,J%)
NEXT J%
NEXT I%
END
Quelqu'un vient-il de parler de chaînes ? Vous pouvez faire la même chose,
mais là, vous vous y attendiez.
REM Initialisation d'un tableau de chaînes
DIM Mois$(12)
Mois$() = "","janvier","février", \
\ "mars","avril","mai","juin", \
\ "juillet","août","septembre", \
\ "octobre","novembre","décembre"
FOR I%=1 TO 12
PRINT Mois$(I%)
NEXT I%
END
Quand vous servez-vous de données en ligne et pas de
READ et
DATA ?
C'est vous qui décidez. L'un des avantages de la méthode en ligne, c'est qu'elle contourne la crainte
de la dépendance aux lignes numérotées en utilisant
RESTORE.
D'un autre côté, si vous avez de grandes quantités de
DATA,
vous préfèrerez sans doute les empêcher d'encombrer le code.
Trouver la taille d'un tableau
L'instruction
DIM
peut être utilisée comme fonction. On peut lui passer un ou deux arguments. Le premier paramètre est toujours
le nom du tableau. Lorsqu'il n'y a que le nom,
DIM
répondra en donnant le nombre de dimensions du tableau.
REM Trouver la taille d'un tableau
DIM Tableau1D(10)
DIM Tableau2D(10,9)
DIM Tableau3D(10,9,8)
PRINT "Tableau","Dimensions"
PRINT "Tableau1D",DIM(Tableau1D())
PRINT "Tableau2D",DIM(Tableau2D())
PRINT "Tableau3D",DIM(Tableau3D())
END
Comme on l'a dit précédemment, il est possible d'avoir un nom de tableau qui soit le même
que celui d'une variable, aussi utilisons-nous le nom du tableau suivi par des parenthèses vides
pour le distinguer d'une variable ordinaire.
Une fois que vous connaissez le nombre de dimensions, il devient possible de demander à
DIM
la taille de chaque dimension en lui passant le nombre de la dimension souhaitée comme second paramètre.
REM Pour trouver la taille d'un tableau
DIM Tableau3D(10,9,8)
PRINT "La dimension 2 a "; \
\ DIM(Tableau3D(),2);" éléments."
END
Pour combiner les deux points ci-dessus, nous pouvons maintenant trouver le nombre de dimensions
et la taille de chacune.
REM Pour trouver la taille d'un tableau
DIM Tableau3D(10,9,8)
N%=DIM(Tableau3D())
FOR I%=1 TO N%
PRINT "Dimension :";N%;
PRINT " Éléments :";DIM(Tableau3D(),I%)
NEXT I%
END
Nous mentionnerons à nouveau cette utilisation de
DIM
dans la section qui concerne les procédures et les fonctions et qui va bientôt arriver. Ensuite,
vous serez capable de voir pourquoi nous avons voulu faire cela. Dans l'attente, souvenez-vous en simplement.
Exercice
14.1
• Voici les chiffres en rapport avec les six premiers mois des ventes de sucettes
sucrées glacées chocolatées aux trois fruits chez un revendeur local :
Janvier : 105 — Février : 261 — Mars : 482
Avril : 195 — Mai : 347 —Juin : 626
• Définissez un tableau pour contenir ces valeurs. Ajoutez ensuite au programme ce qui convient
pour qu'il fasse une boucle dans les diverses valeurs pour arriver aux résultats suivants
qu'il affichera :
a) le mois qui a connu le moins de ventes ;
b) le mois qui a connu le plus grand nombre de ventes ;
c) le nombre total de ventes.
• Vous pouvez utiliser la même boucle
FOR
pour atteindre les trois résultats, ou bien les traiter séparément : c'est votre choix.
• Modifiez le programme pour obtenir un tableau des noms de mois ; initialisez-le et adaptez
le programme ci-dessus pour afficher les vrais noms des mois.
Fin du Chapitre 14
|