GENISTA (1971) : TUTORIEL "BBC BASIC FOR WINDOWS" EN FRANÇAIS : CHAPITRE 14 : GROUPEMENT DE DONNÉES EN TABLEAUX



Logo Genista, fondé en 1971

Guide Tutoriel de BBC BASIC for Windows, Ch. 14

BBC BASIC (BB4W) Tutorial: Grouping Data in Arrays

Groupement de données en tableaux (Tutoriel BBC BASIC, Ch. 14) [Genista]

Par Peter Nairn  •  Traduction : Guy Schaffner (Texte et images) (Genista)

informatique et programmation Vous avez jusque-là découvert une grande quantité d'utilisations du langage de programmation, et vous commencez à écrire des programmes.
Dans ce Chapitre, vous allez faire la rencontre des tableaux, ou matrices. Les tableaux permettent de grouper des informations en une, deux ou trois dimensions (et parfois davantage), comme les cases internes d'un damier pour y stocker et y lire des données, puis les utiliser.
Chapitre 13   •   Chapitre 14   •   Chapitre 15      

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ément012345
Valeur  04080607055

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ément012345
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.


Définition de tableaux (matrices) à 1 dimension, 2 dimensions et 3 dimensions



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





Haut de Page  •  [Top of Page]

Page suivante (Ch. 15)  •  [Next Page (Ch. 15)]

Page précédente (Ch. 13)  •  [Previous Page (Ch. 13)]

Page d'entrée : BASIC, BBC BASIC et BB4W  •  [BASIC, BBC BASIC and BB4W  Entry Page]

Début du Guide pratique du BBC BASIC  •  [The Beginning of the BBC BASIC Tutorial]

Autres sujets  •  [Other subjects]