informatique (MP2I/MPI) · Chapitre 6 · Application directe du cours
Trois lignes, une matrice fausse
Types et structures de données abstraites · niveau 2
Énoncé
Que valent les deux matrices après ces lignes ? Expliquer, et donner la bonne écriture.
let m = Array.make 3 (Array.make 3 0)
let () = m.(0).(0) <- 5
let n = Array.make_matrix 3 3 0
let () = n.(0).(0) <- 5Corrigé
Mesuré :
m = [|5;0;0|] [|5;0;0|] [|5;0;0|] <-- les TROIS lignes ont change
n = [|5;0;0|] [|0;0;0|] [|0;0;0|] <-- correct
Pourquoi. Array.make 3 v range la même valeur v dans les trois cases. Ici v est un tableau, donc une valeur mutable : les trois cases désignent le même tableau de trois entiers. Écrire par l'une, c'est écrire par les trois. L'expression Array.make 3 0 n'a été évaluée qu'une fois — c'est un argument, pas une recette.
Les deux bonnes écritures :
let n = Array.make_matrix 3 3 0
let o = Array.init 3 (fun _ -> Array.make 3 0) (* la fonction est RAPPELEE *)
La seconde dit exactement où est la différence : Array.init reçoit une fonction et l'appelle une fois par ligne, donc alloue trois tableaux.
Le même piège, une seconde fois. Array.copy est une copie superficielle : elle duplique le tableau extérieur et recopie les cases telles quelles. Mesuré, sur une matrice correcte :
let c = Array.copy n in c.(1).(1) <- 8 => n vaut [|5;0;0|] [|0;8;0|] [|0;0;0|]
La copie et l'original partagent leurs lignes. Le programme mentionne explicitement ce point — « copy (y compris le caractère superficiel de cette copie) » —, et c'est le même fait que le premier : en OCaml, ce qui se copie, c'est le bloc, pas ce qu'il désigne.
Le test qui l'attrape à coup sûr, et qu'il faut prendre l'habitude d'écrire : après avoir construit une matrice , modifier m.(0).(0) et vérifier que m.(1).(0) n'a pas bougé. Trois lignes de test contre une classe entière de fautes.