Voir les cours et résoudre les problèmes en :
Le C est un langage de programmation impératif conçu pour la programmation système. Inventé au début des années 1970 avec UNIX, C est devenu un des langages les plus utilisés. De nombreux langages plus modernes se sont inspirés de sa syntaxe. Il privilégie la performance sur la simplicité de la syntaxe. [En savoir plus]
Le C++ est un langage de programmation impératif. Inventé au début des années 1980, il apporte de nouveaux concepts au langage C (les objets, la généricité), le modernise et lui ajoute de nombreuses bibliothèques. C++ est devenu l'un des langages les plus utilisés. Sa performance et sa richesse en font le langage de prédilection pour les concours. [En savoir plus]
Pascal est un langage de programmation impératif inventé dans les années 1970 dans un but d'enseignement. Quoiqu'encore utilisé à cette fin, l'absence de bibliothèque standard en limite son utilisation malgré une grande efficacité. Sa syntaxe a été reprise par d'autres langages plus modernes avec plus ou moins de succès. [En savoir plus]


Remarque : Les cours pour ce langage ne sont disponibles que jusqu'au chapitre 4, « Lecture de l'entrée ». Les corrections sont toutefois toujours fournies.
OCaml est un langage de programmation fonctionnel inventé au milieu des années 1990. Il permet aussi une programmation impérative ou objet. Il permet d'écrire des programmes courts et faciles à vérifier et est ainsi utilisé pour certains systèmes embarqués très sensibles comme ceux des avions. Il est utilisé dans l'enseignement en classes préparatoires aux grandes écoles. [En savoir plus]


Remarque : Les cours pour ce langage ne sont disponibles que jusqu'au chapitre 4, « Lecture de l'entrée ». Les corrections sont toutefois toujours fournies.
Java est un langage de programmation impératif et orienté objet. Inventé au début des années 1990, il reprend en grande partie la syntaxe du langage C++ tout en la simplifiant, au prix d'une performance un peu moins bonne. S'exécutant dans une machine virtuelle, il assure une grande portabilité et ses très nombreuses bibliothèques en font un langage très utilisé. On lui reproche toutefois la « verbosité » de son code. [En savoir plus]


Remarque : Pour un débutant souhaitant apprendre Java, nous conseillons fortement de commencer par JavaScool, plus facile à apprendre, bien que fortement similaire.
Java's Cool (alias JavaScool) est conçu spécifiquement pour l'apprentissage des bases de la programmation. Il reprend en grande partie la syntaxe de Java sur laquelle il s'appuie, mais la simplifie pour un apprentissage plus aisé. La plateforme JavaScool est accompagnée d'un ensemble d'activités diverses de découverte de la programmation. [En savoir plus]
Python est un langage de programmation impératif inventé à la fin des années 1980. Il permet une programmation orientée objet et admet une syntaxe concise et claire qui en font un langage très bien adapté aux débutants. Étant un langage interprété, il n'est cependant pas aussi performant que d'autres langages. [En savoir plus]
Erreurs de compilation

L'oubli du second paramètre de Array.make induit logiquement une erreur. Supposons ainsi qu'on souhaite créer un tableau d'entiers de taille 25, mais qu'on oublie la valeur du contenu initial à mettre dans les cases :

let tab = Array.make 25 in
print_int tab.(2);
File "test.ml", line 2, characters 10-13:
This expression has type 'a -> 'a array but is here used with type 'b array

Pour des raisons qu'on comprendra bien plus tard, il n'y a pas d'erreur au moment de la déclaration du tableau. L'erreur ne se situe que lors de son utilisation. Ainsi le nom tab ligne 2 pose un problème. Ce nom devrait être de type 'b array ce qui veut dire "tableau d'un type quelconque". Pourtant le type de tab est 'a -> 'a array : le fait d'avoir oublié un paramètre à la fonction Array.make fait que tab a été associé à une fonction ! C'est assez déroutant comme idée pour l'instant, mais cela ne nous empêche pas de repérer le problème. Vu que l'erreur est sur tab et que la ligne 2 semble correcte, c'est qu'il faut aller chercher une erreur sur la définition de tab. On peut alors s'apercevoir d'un oubli du second paramètre de Array.make.

Erreurs d'exécution

Qu'est-ce que c'est qu'un tableau de taille zéro ? Serait-ce une aberration ? Non, c'est simplement un tableau qui ne contient aucun élément. Quel est l'intérêt d'avoir un tableau vide ? Ca peut très bien arriver dans des cas pratique. Supposons par exemple que l'on utilise un tableau pour stocker les coordonnées des contacts de son carnet d'adresse. Tout au début, il n'y a encore aucun nom dans le carnet. Le tableau associé à ce carnet tout neuf est donc un tableau de taille zéro. Remarque : pour déclarer un tableau vide, on fait par exemple let t = [||] in...

Que se passe-t-il alors si l'on essaie de fabriquer un tableau de taille négative ? Essayons avec Array.make de créer un tableau de taille -3, rempli de la chaîne "test".

let t = Array.make (-3) "test" in
print_string t.(0);

On n'obtient pas d'erreur de compilation, l'erreur ne sera détectée qu'au moment de l'exécution :

Fatal error: exception Invalid_argument("Array.make")
  • Une "exception" signifie qu'une erreur s'est produite lors d'un appel de fonction.
  • "Fatal error", traduire "Erreur fatale", veut dire que le programme a été obligé de s'arrêter brutalement au moment où l'erreur est apparue, car il ne pouvait pas aller plus loin. En effet, il s'est trouvé dans l'incapacité de créer un tableau de taille -3 (cela n'aurait pas de sens).
  • "Invalid_argument", traduire "Argument invalide" signifie que c'est un des paramètres fournis lors de l'appel à la fonction qui a été à l'origine du problème.
  • "Array.make" donne précisément le nom de la fonction qui est à l'origine de l'erreur.

Il est important de remarquer qu'aucune indication sur la ligne du programme où se situe l'erreur ne vous est donnée. Cela est dû au fait que les numéros de lignes ne sont donnés que pour les erreurs de compilation. Pour savoir à quelle ligne est apparue une erreur d'exécution, il faut utiliser un outil spécialisé supplémentaire, appelé "déboggeur".

Le recours à cet outil n'est nécessaire que pour des grands projets de plusieurs milliers de lignes, lorsque le code n'a pas été assez soigné lors de l'écriture. Pour des petits programmes, il est facile de localiser une erreur à l'aide d'un simple coup d'œil au code. Pour les programmes de taille moyenne, de quelques centaines de lignes, nous donnerons à la fin du cours une technique rapide et efficace pour localiser l'erreur.

Pourquoi le compilateur n'est-il pas capable de détecter que le paramètre -3 va provoquer une erreur ? Simplement parce que dans la plupart des cas il n'est pas possible de prévoir. Que penser du code suivant ?

let taille = read_int() in
let tableau = Array.make taille "test" in
print_string "c'est fini";

C'est un programme qui terminera correctement que si l'utilisateur fourni un entier positif ou nul. Dans les autres cas une erreur se produira avant la fin.

Voyons maintenant ce qui se passe si on déclare un tableau let tab = [| 3; 5; -7|] in ... et qu'on essaie d'accéder à tab.(-2) ou tab.(3), c'est-à-dire à des cases du tableau qui n'existent pas.

let tab = [| 3; 5; -7|] in
print_int tab.(-2);
Fatal error: exception Invalid_argument("Array.get")

Ce message nous dit qu'il y a eu une erreur fatale à cause d'une exception de type "Invalid_argument", c'est-à-dire d'une erreur générée par un argument invalide dans un appel à une fonction nommée "Array.get", traduire "Tableau.récupère". Quel peut bien être cette fonction Array.get qu'on n'a même pas utilisé mais qui provoque pourtant une erreur ?

L'explication est très simple. La notation tab.(i)tab est un tableau et i est un indice n'est qu'un raccourci pour l'expression : " Array.get tab i ". Cet appel de fonction permet exactement de récupérer dans le tableau tab l'élément à l'indice i. On peut l'utiliser dans son code, c'est juste beaucoup plus lourd que d'écrire simplement tab.(i). Ainsi, les deux lignes suivantes sont totalement équivalentes :

print_int (Array.get tab 2);
print_int tab.(2);

Le même principe s'applique pour la modification d'une valeur à un indice invalide :

let tab = [| 3; 5; -7|] in
tab.(4) <- 12;

Sauf que cette fois l'erreur est sur une fonction nommée "Array.set" :

Fatal error: exception Invalid_argument("Array.set")

La fonction "Array.set", traduire "Tableau.modifier", permet de changer le contenu d'une case d'un tableau donné à un indice donné, en précisant la nouvelle valeur lors de l'appel. Ainsi les deux expressions suivantes sont équivalentes :

Array.set tab i valeur;
tab.(i) <- valeur;
Longueur

"Array.length", traduire "Tableau.taille" est une fonction permettant de récupérer la taille du tableau qu'on lui donne en argument. Pour obtenir la taille d'un tableau nommée tab, on fait donc simplement "Array.length tab". Un exemple qui affiche la taille, égale à 3, du tableau :

let tab = [| 3; 5; -7|] in
print_int (Array.length tab);

Remarque : comme la taille d'un tableau est toujours positive ou nulle, le résultat d'un appel à Array.length n'est jamais négatif.

Maintenant que l'on sait récupérer la taille d'un tableau, on va pouvoir réaliser des traitements sur l'ensemble des éléments d'un tableau.

Essayons d'abord d'afficher tous les éléments d'un tableau d'entiers, dans l'ordre et séparés par des espaces. On a déjà vu comment faire :

let tab = [| 4; 9; 8; -5 |] in
print_int tab.(0);
print_string " ";
print_int tab.(1);
print_string " ";
print_int tab.(2);
print_string " ";
print_int tab.(3);
print_string " ";

Bien évidement, un tel code est inacceptable : il faut utiliser une boucle for. Ainsi le code se condense en :

let tab = [| 4; 9; 8; -5 |] in
for indice = 0 to 3 do
  print_int tab.(indice);
  print_string " ";
done;

Remarquez que le tableau est de taille 4, et que la boucle for commence à 0, le premier indice, et se termine à 3, le dernier indice.

Pensez à vous inscrire pour valider les cours et résoudre les exercices.