Adloun

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) <- 5

Corrigé

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.

Exercices semblables

Le cours du chapitre · Tous les exercices du chapitre