Mini-cours sur les algorithmes

Partie IV

Voilà, vous savez tout !
Enfin, presque. Encore deux petites choses à savoir : les tableaux et les fonctions.

Évidemment, un programme ne sert pas à traiter que deux informations, mais parfois des milliers (surtout lorsqu'elles sont dans un fichier ou dans une base de données)

Comme les variables doivent être déclarées avant d'être utilisées, il faudrait alors déclarer des milliers de variables, et donc écrire de milliers de lignes de code ...

On a donc inventé une variable qui peut contenir plusieurs valeurs du même type, le tableau.

Par exemple, une grosse variable qui contient 100 valeurs.

Le tableau

On peut se représenter un tableau comme un ensemble de cases juxtaposées dans la mémoire de l'ordinateur où toutes les cases ont la même taille.

Dans le cas d'un tableau de string, les cases contiendront non pas une chaîne de caractères, mais un nombre (de type int) qui représente le numéro de la case dans la mémoire de l'ordinateur qui contient cette chaîne de caractères.

Comme pour une variable simple, le tableau a un nom et un type de données. Et, comme il peut contenir plusieurs valeurs, il faut aussi dire combien de valeurs il pourra contenir.

La déclaration d'un tableau se présente sous la forme : TypeDeVariable NomDeTableau[taille]

La taille = le nombre d'éléments (de cases).
Ce qui est entre crochet une expression dont le résultat de l'évaluation est un entier positif.

  /* Déclaration de tableaux

  Rappel : il est obligatoire de déclarer les tableaux
  avant de les utiliser */

  int tab_nombrePremiers[10]
  string tab_nomJoueurs[nombreDeJoueurs]
  bool tab_tests[nombreDeJoueurs*2]
  float tab_montantFactures[50*2]

Parfois, pour être plus clair, on préfixe le nom du tableau par tab_
Parfois même, lorsqu'il existe qu'un seul tableau, on nomme le tableau par tableau !

Le tableau peut être vu comme un ensemble de cases. Pour accéder à une case, il faut donner le nom de cette grosse variable et indiquer entre crochets le numéro de cette case. Ce numéro est appelé indice; c'est un nombre entier positif, allant de 0 à taille -1

  /* Déclaration et initialisation des variables simples*/
  int nombreDeFactures = 100
  int compteur = 0
  float somme = 0
  float moyenne = 0

  /* Déclaration du tableau contenant le montant des factures */
  float montantFactures[nombreDeFactures]

  /* Initialisation du tableau */

  /* NB : Il ne faut pas oublier d'indiquer la taille du tableau
  dans une fonction qui doit gérer un tableau, car le programme
  ne peut pas deviner la taille. C'est le cas des programmes écrits en C.

  Toutefois, certains langages orientés objet, tel que le C++,
  permettent de déclarer des objets. Parmi ces objets, il existe
  les conteneurs ... */

  initialiserTableau(montantFactures,nombreDeFactures)

  /* Ici, le tableau est rempli lors de l'encodage
  En pratique, un tableau est rempli via une boucle. */

  montantFactures[0] = 12.74
  montantFactures[1] = 45.24
  montantFactures[2] = 98.67
  /* ... */
  montantFactures[99] = 34.37

  /* Attention :
  montantFactures[100] = 134.58
  montantFactures[189] = 44.89
  montantFactures[-2]  = 29.51

  provoqueront une erreur (et le plantage du programme)
  car l'indice indiqué est hors limite.
  Si la taille est 100, les limites sont 0 à 99.
  */

  /* Pour afficher tous les montants, via une boucle
  et calculer la somme */

  FAIRE TANT QUE (compteur < nombreDeFactures )

    afficher(montantFactures[compteur])
    somme = somme + montantFactures[compteur]

    compteur = compteur + 1
  REFAIRE

  /* Calcul de la moyenne */
  moyenne = somme / nombreDeFactures

  /* Afficher les résultats */
  afficher("Le total des factures est : ", somme)
  afficher("Le montant moyen d'une facture est : ", moyenne)

Vu le très grand nombre d'éléments qu'un tableau peut contenir, l'utilisation de boucles s'impose dans la gestion des tableaux.

Notez qu'une case d'un tableau peut contenir un tableau !

Ainsi, int tableau[100,100] contient dix mille cases. On peut se représenter ce tableau (à deux dimensions, à deux indices) comme une grille. Conventionnellement, le premier indice représente le numéro de la ligne et le second indice, le numéro de la colonne. Grâce à deux nombres on peut parfaitement situer une case de la grille. tableau[57,3]=17 placera 17 dans la case située à l'intersection de la ligne 57 et de la colonne 3.

On peut même déclarer des tableaux tridimensionnels. int tableau[100,100,100] est un tableau contenant un million de cases !!! Et avec 4 indices, on peut ? Oui ! Mais, en pratique, on n'utilise jamais des tableaux de plus de 3 dimensions.

Tous les langages de programmation offrent des fonctions de base.
Les autres fonctions doivent être développées par vous !

Créer sa fonction

Écrire ses fonctions présente deux avantages.

Premièrement, cela permet de continuer à développer l'algorithme principal comme si le sous-problème était résolu.

Deuxièmement, cela permet d'obtenir une meilleure lisibilité de l'algorithme, si le sous-problème se présente plusieurs fois dans l'algorithme principal.

Exemple. On ne sait pas comment envoyer un littéral - "Bonjour !" - à l'écran, alors on écrit dans l'algorithme afficher("Bonjour !"). On ne sait pas comment envoyer la valeur de la variable resultat dans un fichier, alors on écrit dans l'algorithme enregistrer(resultat). Facile, non ?

Il suffit de mettre en parenthèses les données à traiter par la fonction.

Cela ne vous rappelle rien ?
Une fonction, c'est comme un programme !
Le programme résout un problème. La fonction résout un sous-problème.
En réalité, un programme est une fonction qui appelle des fonctions.

C'est tellement vrai que la plupart des langages de programmation appelle LA fonction, celle qui appelle les autres, donc "principale" : main(). Ce qui signifie, en français, principal.

En fait, l'algorithme principal fait appel à un ou plusieurs algorithmes secondaires (qu'on n'a pas encore écrits)

Ajoutons qu'une fonction peut appeler une autre fonction (hormis la principale).

Pour créer une fonction, rien de plus simple.

  FUNCTION type nom_de_la_fonction (type parametre1, type parametre2, ...)

    /* Description de la fonction */

    /* Les instructions */

    RETURN expression

  END_FUNCTION

Les langages informatiques étant anglais, on écrit FUNCTION (et non FONCTION). Et, RETURN (et non RETOUR).
Ici, pour plus de lisibilité, les noms réservés sont mis en majuscules. Toutefois, dans certains langages de programmation, les mots réservés sont écrits en minuscules.

Une fonction appelée retourne un résultat, affectant souvent une variable de la fonction appelante.

La valeur retournée doit être du type indiqué devant le nom de la fonction dans la déclaration.

La valeur de retour ne peut pas être un tableau. Notons que dans certains langages orientés objet une fonction peut retourner un objet. Et, un objet peut contenir beaucoup de choses ...

Les données passées à une fonction sont appelés paramètres.
Les paramètres sont séparés par une virgule.

Dans la déclaration de la fonction, ces paramètres sont mis entre les parenthèses et sont appelés paramètres formels. Un paramètre formel est déclaré comme une variable. C'est le nom de ce paramètre qui sera utilisé dans le corps de la fonction.
Dans la fonction appelante, ces paramètres sont mis entre les parenthèses et sont appelés paramètres effectifs. Un paramètre effectif est un littéral ou un nom de variable.

Ajoutons que, par défaut, la valeur du paramètre effectif est automatiquement copié dans une nouvelle variable du nom du paramètre formel; de sorte que la modification de la valeur de la variable du nom du paramètre formel n'ait aucune influence sur la valeur de la variable passée en paramètre.

BY REF

Exemple :

FUNCTION int intialiserTableau(float nomTableau, int taille)

  /* Cette fonction permet d'initialiser à zéro toutes les cellules
  d'un tableau de type float */

  /* Déclarer et initialiser un compteur */
  int compteur = 0

  FAIRE TANT QUE (compteur < taille )
    nomTableau[compteur] = 0.0
    compteur = compteur + 1
  REFAIRE

  RETURN 0

END_FUNCTION

Notons qu'au lieu de remplir le tableau lors de l'encodage, on pourrait - et, c'est plus normal - le faire remplir par l'utilisateur.

FUNCTION remplirTableau(float nomTableau, int taille)

  /* Cette fonction permet de faire remplir par l'utilisateur toutes les cellules
  d'un tableau de type float */

  /* Déclarer et initialiser un compteur */
  int compteur = 0

  FAIRE TANT QUE (compteur < taille )

    /* Demander à l'utilisateur du programme d'introduire un nombre réel */

    Afficher("Veuillez introduire le nombre (", compteur, ") : ")
    nomTableau[compteur] = lireClavier()

    /* Ne pas oublier d'incrémenter le compteur */
    compteur = compteur + 1

  REFAIRE

END_FUNCTION

Incrémenter signifie ajouter un.

Quelques causes de plantage

  1. Au niveau des boucles.
    Oublier d'ajouter un au compteur à chaque tour, le compteur restera alors toujours à 0 et on restera toujours dans la boucle. On parle alors de boucle infinie. Le programme n'atteindra jamais la fin !
  2. Au niveau des tableaux.
    Tenter de mettre une valeur dans une case qui n'existe pas (mauvais indice)
    Tenter de lire le contenu d'une case qui n'existe pas.
  3. Au niveau de la division.
    Tenter de diviser un nombre par zéro.

Résumé

Maintenant, vous savez :

Pour aller plus loin

Livres recommandés :

Liens recommandés :

Outils pour dessiner son algorithme :


Stop. Pour aujourd'hui, vous en avez appris assez !
Dormez et demain relisez tout.

Et, dans une semaine, relisez tout.
Et, dans un mois, relisez tout.
Et, dans un an, relisez tout.
Et, tous les ans, relisez tout.
À force de relire, cela restera dans la mémoire ...

À trente ans, arrêtez de relire. Cela n'entrera plus !