Aller au contenu principal

Tableaux et fonctions

Ce que ce chapitre apporte

  • Déclarer un tableau, lire et écrire une case par son indice, de 0 à Size(t) - 1.
  • Parcourir un tableau pour accumuler, compter, chercher le maximum et son indice.
  • Lire un texte caractère par caractère avec Len et Char.
  • Utiliser une fonction intégrée comme une boîte noire : arguments en entrée, valeur rendue en sortie.
  • Écrire une fonction avec ses paramètres et sa variable de retour, puis l'appeler du programme principal.

Un capteur qui relève le niveau d'une cuve toutes les heures produit 24 valeurs par jour : les ranger dans 24 variables rendrait le programme illisible et impossible à étendre. Le tableau range toute la série sous un seul nom, et une boucle la parcourt. Quand le programme grossit, les fonctions le découpent en étapes nommées, que l'on écrit une fois, que l'on teste à part et que l'on réutilise.

Ranger une série de valeurs dans un tableau

Vingt-quatre relevés horaires, ce ne sont pas vingt-quatre variables releve0, releve1, releve2, etc. Chacune demanderait sa propre forme de saisie, sa propre ligne dans chaque calcul, et passer à un relevé toutes les demi-heures obligerait à tout réécrire.

Définition

Un tableau est une variable qui contient plusieurs valeurs du même type. Il se déclare avec une taille, le nombre de ses cases. Chaque case est désignée par son indice, écrit entre crochets : les indices vont de 0 à taille - 1. Un tableau de 4 cases va de debits[0] à debits[3]. La fonction intégrée Size(debits) rend le nombre de cases.

Organigramme, tel que l'affiche Flowgorithm
Exécuter comme dans Flowgorithm, en continu ou forme par forme.
MainReal Array debits[4]debits[0] = 12.5debits[1] = 14debits[2] = 9.5debits[3] = 11Output "Débit à l'indice 2 : " & debits[2] & " L/min"Output "Nombre de cases : " & Size(debits)End

Quatre débits de pompe rangés sous un seul nom. La déclaration porte la taille ; chaque affectation vise une case par son indice.

Dérouler ce programme en pas à pas : juste après la déclaration, la fenêtre des variables affiche debits[0] à debits[3], encore vides, puis chaque affectation remplit une case. Le programme affiche Débit à l'indice 2 : 9.5 L/min, c'est-à-dire la troisième valeur rangée, puis Nombre de cases : 4.

Le premier élément est à l'indice 0

debits[2] n'est pas le deuxième débit mais le troisième. La dernière case d'un tableau de 4 cases porte l'indice 3, et debits[4] n'existe pas. Pour désigner la dernière case sans compter, écrire debits[Size(debits) - 1].

Parcourir un tableau

Un indice n'est pas forcément un nombre écrit en dur : c'est une expression, et le plus souvent la variable d'une boucle For. La boucle pour i de 0 à Size(t) - 1 passe par toutes les cases, dans l'ordre, et le même programme reste juste si la taille du tableau change.

Organigramme, tel que l'affiche Flowgorithm
Exécuter comme dans Flowgorithm, en continu ou forme par forme.
NextDoneFalseTrueFalseTrueNextDoneMainReal Array temperatures[6]Integer i, depassements, indicePicReal sommei = 0 to Size(temperatures) - 1Input temperatures[i]somme = 0depassements = 0indicePic = 0i = 0 to Size(temperatures) - 1somme = somme + temperatures[i]temperatures[i] > 30depassements = depassements + 1temperatures[i] > temperatures[indicePic]indicePic = iOutput "Moyenne : " & ToFixed(somme / Size(temperatures), 1) & " °C"Output "Relevés au-dessus de 30 °C : " & depassementsOutput "Pic : " & temperatures[indicePic] & " °C à l'indice " & indicePicEnd

Six températures d'un local technique. Une première boucle remplit le tableau ; une seconde le parcourt pour accumuler, compter et chercher le pic.

Avec les saisies proposées, le programme affiche Moyenne : 25.9 °C, Relevés au-dessus de 30 °C : 2 et Pic : 33.5 °C à l'indice 4. En pas à pas, la forme somme ← somme + temperatures[i] s'exécute 6 fois, une par case, et la fenêtre des variables montre i qui désigne la case lue. Changer une saisie, par exemple 33.5 en 29, puis observer le compteur et le pic.

TraitementAvant la boucleDans la boucle
Accumuler (somme, moyenne)somme ← 0somme ← somme + t[i]
Compternb ← 0nb ← nb + 1, seulement si la condition est vraie
Chercher le maximumindicePic ← 0, la première caseindicePic ← i si t[i] dépasse la case retenue

Pour le maximum, retenir l'indice plutôt que la valeur donne les deux à la fois : la valeur se relit dans la case. L'affectation indicePic ← i s'exécute ici 4 fois, chaque fois qu'une température dépasse la case retenue. Partir de la première case, et non d'une valeur choisie comme 0, garantit que le résultat est une valeur réellement présente dans le tableau.

Organigramme, tel que l'affiche Flowgorithm
Exécuter comme dans Flowgorithm, en continu ou forme par forme.
NextDoneMainReal Array debits[4]Integer ii = 0 to Size(debits)debits[i] = 0Output "Débits remis à zéro"End

Une remise à zéro qui va une case trop loin : la borne de fin a perdu son - 1.

Un indice hors du tableau arrête l'exécution

Exécuter ce programme : les quatre premiers tours remplissent debits[0] à debits[3], puis la boucle fait un cinquième tour, où i vaut 4. La case debits[4] n'existe pas : l'exécution s'arrête sur une erreur, avant la sortie. Une erreur d'indice se lit toujours de la même façon : quelle valeur avait l'indice, et jusqu'où vont les cases ?

En Python, le tableau s'appelle une liste, dont les indices commencent aussi à 0. Le parcours s'écrit for i in range(len(temperatures)) : la borne de fin de range est exclue, ce qui absorbe le - 1.

Le texte, caractère par caractère

Un texte se parcourt comme un tableau : Len(s) rend son nombre de caractères, et Char(s, i) rend le caractère d'indice i, en comptant à partir de 0. Le premier caractère est Char(s, 0), le dernier Char(s, Len(s) - 1).

Organigramme, tel que l'affiche Flowgorithm
Exécuter comme dans Flowgorithm, en continu ou forme par forme.
FalseTrueNextDoneFalseTrueMainString code, lettreInteger i, nbInput codeInput lettrenb = 0i = 0 to Len(code) - 1Char(code, i) == lettrenb = nb + 1Output "Le code contient " & nb & " fois " & lettreChar(code, 0) == "P"Output "Autre référence"Output "Référence de pièce détachée"End

Un code produit lu caractère par caractère : compter une lettre, puis vérifier la première.

Pour le code PB-2047-B et la lettre B, le programme affiche Le code contient 2 fois B, puis Référence de pièce détachée. La boucle fait 9 tours, un par caractère, tirets compris. Relancer avec un autre code et une autre lettre, en observant i et nb. Flowgorithm ne propose aucune fonction qui extrait un morceau de texte, par exemple les quatre chiffres d'une référence : tout traitement se construit caractère par caractère, avec Len, Char et une boucle.

Les fonctions intégrées, des boîtes noires

Size, Len, Char et ToFixed sont des fonctions intégrées. Pour s'en servir, inutile de savoir comment elles calculent : il suffit de savoir ce qu'elles reçoivent, les arguments entre parenthèses, et ce qu'elles rendent. La valeur rendue prend la place de l'appel dans l'expression.

FonctionReçoitRend
ToFixed(r, i)un réel et un nombre de décimalesle réel écrit en texte avec i décimales
Len(s), Char(s, i)un texte (et un indice)sa longueur, ou le caractère d'indice i
Size(t)un tableauson nombre de cases
Random(n)un entierun entier au hasard, de 0 à n - 1

Random sert à simuler une mesure. Random(101) rend un entier de 0 à 100, comme un niveau en pourcentage :

Organigramme, tel que l'affiche Flowgorithm
Exécuter comme dans Flowgorithm, en continu ou forme par forme.
FalseTrueMainInteger niveauniveau = Random(101)Output "Niveau simulé : " & niveau & " %"niveau > 90Output "Niveau acceptable"Output "Débordement imminent"End

Un capteur simulé. Chaque exécution tire une nouvelle valeur.

Exécuter ce programme plusieurs fois : la valeur change à chaque exécution. C'est précisément ce qui le rend impossible à tester. Pour vérifier le cas 90, qui doit afficher « Niveau acceptable », il faudrait attendre que le hasard le tire, et un résultat que l'on ne peut pas reproduire ne se vérifie pas. Pour tester, remplacer l'affectation par lire: niveau : la valeur est alors choisie, et chaque cas se rejoue à volonté. Random ne revient qu'une fois le programme vérifié.

Écrire ses propres fonctions

Une fonction définie par l'utilisateur répond à trois besoins. Nommer une étape : CalculerTaux(volume, capacite) se lit mieux qu'une formule au milieu du programme. Réutiliser : la formule écrite une fois sert à chaque appel, et une correction s'applique partout. Tester à part : la fonction se vérifie seule, sur des valeurs choisies, avant d'être branchée dans le programme.

Paramètre, argument, variable de retour

Chaque fonction a son propre diagramme, qui commence par une pilule portant son nom et finit par sa propre pilule de fin. Un paramètre est une variable de la fonction, déclarée avec un type dans son en-tête. Un argument est la valeur transmise au moment de l'appel : le paramètre reçoit l'argument. Une fonction qui retourne une valeur a un type de retour et une variable de retour, déclarée dans la fonction : la fonction rend le contenu de cette variable quand elle se termine. Il n'existe pas de forme « Return ».

Organigramme, tel que l'affiche Flowgorithm
Exécuter comme dans Flowgorithm, en continu ou forme par forme.
MainReal puissance, duree, energieInput puissanceInput dureeenergie = CalculerEnergie(puissance, duree)AfficherBilan("Presse 2", energie)EndCalculerEnergieReal resultatresultat = puissanceKw * dureeHReturn resultatAfficherBilanOutput machine & " : " & ToFixed(kwh, 1) & " kWh"End

Le programme principal et deux fonctions, chacune dans son diagramme. CalculerEnergie retourne une valeur ; AfficherBilan affiche et ne retourne rien.

Dérouler en pas à pas avec une puissance de 7,5 kW pendant 6 h : à l'affectation, l'exécution entre dans CalculerEnergie, la fenêtre des variables montre puissanceKw, dureeH et resultat, puis revient au programme principal, où energie reçoit la valeur rendue. L'appel suivant entre dans AfficherBilan, qui affiche Presse 2 : 45.0 kWh. L'argument puissance est reçu par le paramètre puissanceKw, et l'argument duree par le paramètre dureeH : les noms n'ont pas à correspondre, et un argument peut aussi être une valeur écrite directement, comme "Presse 2".

La fonction…Elle s'appelle…Exemple
retourne une valeurdans une expression : affectation, sortieenergie ← CalculerEnergie(puissance, duree)
ne retourne rienpar la forme CallAfficherBilan("Presse 2", energie)
Organigramme, tel que l'affiche Flowgorithm
Exécuter comme dans Flowgorithm, en continu ou forme par forme.
MainReal puissance, duree, energieInput puissanceInput dureeenergie = CalculerEnergie(puissance)Output "Énergie : " & ToFixed(energie, 1) & " kWh"EndCalculerEnergieReal resultatresultat = puissanceKw * dureeReturn resultat

Une version fautive : la fonction ne reçoit que la puissance, et calcule avec la durée du programme principal.

Chacun ses variables : celles d'une fonction ne se voient pas depuis le programme principal, et inversement. Exécuter cette version : l'exécution entre dans CalculerEnergie et s'arrête sur l'affectation, car duree n'y est pas déclarée. Elle n'existe que dans le programme principal. Tout ce dont une fonction a besoin doit lui arriver par un paramètre.

Un paramètre peut être un tableau. La fonction ci-dessous compte les relevés qui dépassent un seuil ; elle lit les cases du tableau reçu sans les modifier, et sert deux fois avec deux seuils différents.

Organigramme, tel que l'affiche Flowgorithm
Exécuter comme dans Flowgorithm, en continu ou forme par forme.
NextDoneFalseTrueNextDoneMainReal Array niveaux[6]Integer i, nbi = 0 to Size(niveaux) - 1Input niveaux[i]nb = CompterDepassements(niveaux, 50)Output "Relevés au-dessus de 50 : " & nbOutput "Au-dessus de 60 : " & CompterDepassements(niveaux, 60)EndCompterDepassementsInteger compte, kcompte = 0k = 0 to Size(valeurs) - 1valeurs[k] > seuilcompte = compte + 1Return compte

Un paramètre tableau. Dans la fonction, Size(valeurs) rend la taille du tableau transmis.

Le programme affiche Relevés au-dessus de 50 : 3 puis Au-dessus de 60 : 1. Le second appel figure directement dans la sortie : la valeur rendue s'insère dans le texte, sans passer par une variable. En Python, une fonction se définit avec def, et l'instruction return rend la valeur, là où Flowgorithm rend le contenu de la variable de retour.

Fil rouge : la cuve de traitement

Étape 5. La cuve (rayon 1,5 m, hauteur 4 m) est équipée d'un capteur qui relève le volume d'eau, en litres, à chaque heure pleine, de 0 h à 23 h. Le programme range les 24 relevés dans un tableau, calcule le volume moyen, trouve le pic et l'heure du pic, et exprime chacun en taux de remplissage. Le calcul du taux, qui sert deux fois, est isolé dans la fonction CalculerTaux. L'indice d'une case est directement l'heure du relevé.

Organigramme, tel que l'affiche Flowgorithm
Exécuter comme dans Flowgorithm, en continu ou forme par forme.
NextDoneFalseTrueNextDoneMainReal Array volumes[24]Integer i, heurePicReal capacite, somme, moyenne, tauxMoyen, tauxPiccapacite = pi * 1.5 ^ 2 * 4 * 1000i = 0 to Size(volumes) - 1Input volumes[i]somme = 0heurePic = 0i = 0 to Size(volumes) - 1somme = somme + volumes[i]volumes[i] > volumes[heurePic]heurePic = imoyenne = somme / Size(volumes)tauxMoyen = CalculerTaux(moyenne, capacite)tauxPic = CalculerTaux(volumes[heurePic], capacite)Output "Volume moyen : " & ToFixed(moyenne, 1) & " L, soit " & ToFixed(tauxMoyen,1) & " %"Output "Pic : " & ToFixed(volumes[heurePic], 0) & " L à " & heurePic & " h, soit " &ToFixed(tauxPic, 1) & " %"EndCalculerTauxReal tauxtaux = volume / capacite * 100Return taux

Étape 5 du fil rouge. Une boucle remplit le tableau, une seconde accumule et cherche le pic ; la fonction CalculerTaux est appelée deux fois.

Avec les 24 relevés proposés, le programme affiche Volume moyen : 20187.5 L, soit 71.4 % puis Pic : 26100 L à 12 h, soit 92.3 %. À 12 h, le taux dépasse le seuil haut de 90 %. En pas à pas, observer les cases volumes[0] à volumes[23] se remplir, puis heurePic changer 7 fois pendant la seconde boucle, chaque fois qu'un relevé dépasse le pic retenu. L'exécution entre ensuite deux fois dans CalculerTaux : son paramètre capacite porte le même nom que la variable du programme principal, mais c'en est une autre, qui reçoit sa valeur à l'appel.

Exercices type

Organigramme, tel que l'affiche Flowgorithm
NextDoneFalseTrueNextDoneMainReal Array debits[6]Integer i, correctionsi = 0 to Size(debits) - 1Input debits[i]corrections = 0i = 0 to Size(debits) - 1debits[i] < 0debits[i] = 0corrections = corrections + 1Output "Corrections : " & correctionsEnd

Un débitmètre en dérive renvoie parfois des valeurs négatives, physiquement impossibles : le programme les remplace par 0.

L'opérateur saisit 2.4, -0.3, 3.1, -1.2, 0 et 2.8. Que contient le tableau debits à la fin, et qu'affiche le programme ?

La seconde boucle visite les six cases. Seules les cases d'indices 1 et 3 contiennent une valeur strictement négative : elles reçoivent 0, et le compteur augmente deux fois. La case d'indice 4 contient déjà 0, la condition debits[i] < 0 est fausse, et rien ne change. Le tableau contient 2,4 ; 0 ; 3,1 ; 0 ; 0 ; 2,8 et le programme affiche Corrections : 2. Une case se modifie par une affectation dont la cible est debits[i], exactement comme une variable. Et la valeur limite, 0 ici, décide si la comparaison doit être stricte : un débit nul est une mesure valable, qu'il ne faut pas compter comme une correction.

Une station affiche le débit de ses deux pompes en m³/h, alors que les capteurs mesurent en L/min. Écrire la conversion dans une fonction appelée deux fois, et donner l'affichage pour 250 L/min en entrée et 180 L/min en sortie.

La conversion multiplie par 60 (minutes par heure) et divise par 1000 (litres par m³). Écrite une seule fois dans ConvertirDebit, elle est appelée pour chaque pompe :

Organigramme, tel que l'affiche Flowgorithm
Exécuter comme dans Flowgorithm, en continu ou forme par forme.
MainReal pompeEntree, pompeSortie, m3Entree, m3SortieInput pompeEntreeInput pompeSortiem3Entree = ConvertirDebit(pompeEntree)m3Sortie = ConvertirDebit(pompeSortie)Output "Pompe d'entrée : " & ToFixed(m3Entree, 1) & " m3/h"Output "Pompe de sortie : " & ToFixed(m3Sortie, 1) & " m3/h"EndConvertirDebitReal m3Heurem3Heure = litresMinute * 60 / 1000Return m3Heure

Une fonction de conversion, deux appels. Le paramètre litresMinute reçoit 250 au premier appel, 180 au second.

Le programme affiche Pompe d'entrée : 15.0 m3/h puis Pompe de sortie : 10.8 m3/h. Recopier la formule dans les deux affectations aurait donné le même résultat aujourd'hui. Mais une erreur de facteur corrigée dans une copie et oubliée dans l'autre produit deux débits incohérents. Avec la fonction, la formule n'existe qu'à un endroit.

Organigramme, tel que l'affiche Flowgorithm
MainReal volume, capacite, tauxInput volumeInput capacitetaux = 0CalculerTaux(volume, capacite)Output "Taux : " & ToFixed(taux, 1) & " %"EndCalculerTauxReal resultatresultat = v / c * 100Return resultat

Un programme qui appelle CalculerTaux, puis affiche le taux.

Pour un volume de 21500 L et une capacité de 28274 L, ce programme affiche un taux nul, alors que la fonction est juste. Où est l'erreur ?

La fonction calcule bien resultat et le rend. Mais la forme Call sert aux fonctions qui ne retournent rien : ici, la valeur rendue n'est rangée nulle part. La variable taux du programme principal garde la valeur 0 qu'elle avait reçue avant l'appel, et le programme affiche Taux : 0.0 %.

La correction remplace la forme Call par une affectation : taux ← CalculerTaux(volume, capacite), et le programme affiche alors Taux : 76.0 %. Sans l'initialisation taux ← 0, l'erreur serait plus visible : l'exécution s'arrêterait sur la sortie, qui lirait une variable n'ayant jamais reçu de valeur. Donner à resultat le nom taux n'y changerait rien : la variable de retour appartient à la fonction, et le programme principal ne la voit pas. Une valeur rendue se récupère seulement en plaçant l'appel dans une expression.

Vérification

Vérification rapideon peut se reprendre

1.Un tableau est déclaré avec 10 cases. Quels sont ses indices ?

2.Comment désigner la dernière case d'un tableau t, quelle que soit sa taille ?

3.Quelles valeurs Random(10) peut-il rendre ?

4.Le tableau Tab contient 5, 3, 8, 1 et 6, aux indices 0 à 4. Que vaut Tab[Tab[1]] ?

5.La fonction CalculerTaux retourne une valeur. Comment récupérer cette valeur dans le programme principal ?

6.Dans l'appel ConvertirDebit(pompeEntree), avec l'en-tête ConvertirDebit(litresMinute en Real), qu'est-ce que pompeEntree ?

La méthode

  1. Déclarer le tableau avec sa taille, puis écrire chaque boucle de parcours de 0 à Size(t) - 1.
  2. Situer chaque instruction : l'initialisation avant la boucle, l'accumulation ou le test dedans, l'affichage après.
  3. Chercher un maximum en retenant l'indice de la première case, puis en le remplaçant quand une case le dépasse.
  4. Lire un texte caractère par caractère avec Char(s, i), de 0 à Len(s) - 1.
  5. Tester avec des saisies, jamais avec Random : un cas se vérifie seulement s'il se rejoue.
  6. Isoler une étape dans une fonction : lister ce qu'elle reçoit (paramètres) et ce qu'elle rend (variable de retour, déclarée dans la fonction), puis l'appeler dans une expression si elle retourne une valeur, par la forme Call sinon.

Synthèse

  • Un tableau range une série de valeurs du même type sous un seul nom ; ses indices vont de 0 à Size(t) - 1, et un indice hors de cet intervalle arrête l'exécution.
  • Le parcours par une boucle For sert à accumuler, compter et chercher ; pour le maximum, retenir l'indice, en partant de la première case.
  • Une fonction intégrée reçoit des arguments et rend une valeur : Len(s) et Char(s, i) lisent un texte caractère par caractère, à partir de l'indice 0 ; Random(n) rend un entier de 0 à n - 1, et se remplace par une saisie pour tester.
  • Une fonction a son propre diagramme ; ses paramètres reçoivent les arguments de l'appel ; elle rend le contenu de sa variable de retour, sans forme Return. Elle s'appelle dans une expression ; la forme Call sert aux fonctions qui ne retournent rien.
  • Les variables locales d'une fonction et celles du programme principal ne se voient pas : tout passe par les paramètres et la valeur rendue.

Mettre en pratique