« Structures de données/Pointeurs » : différence entre les versions

→‎Les pointeurs : intro, spécification, utilisation, exemple avec des entier
(retour sur la gestion des variables en mémoire, mémoire dynamique. schéma manquants)
 
(→‎Les pointeurs : intro, spécification, utilisation, exemple avec des entier)
Nous allons apprendre comment utiliser cette mémoire dynamique. Et ce, avec cet outil que sont les '''pointeurs'''.
 
== Les pointeursApproche ==
 
Le pointeur est un nouveau [[Algorithmique impérative/Types expressions opérateurs|type]] au même titres que les entiers, les caractères, chaînes de caractères, booléens et autres abordés en [[algorithmique impérative]].
 
Il convient cependant de distinguer les pointeurs typés des pointeurs non-typés (également appellés générique). Nous allons d'abord nous pencher sur les premiers et réserver les seconds pour plus tard.
 
Un pointeur typé indique le type de la donnée qu'il pointe. Il y a donc des pointeurs vers des entiers, des pointeurs vers des caractères, etc. Il convient d'affecter à des variables de types pointeur vers T uniquement des expressions de types pointeur vers T (tout comme on doit assigner à une variable de type entier une expression entière).
 
== Spécification des pointeurs typés ==
 
On déclare un pointeur vers T (T : un type) comme suit :
 
Lexique
identifiant_du_pointeur : ^T
 
On accède à la valeur pointée comme suit :
 
identifiant_du_pointeur^
 
Cette expression est donc du type pointé : T
 
<code>Ecrire(identifiant_du_pointeur)</code> afficherait l'adresse mémoire ou est stockée la donné pointée (souvent en sous la forme hexadécimale) : dans notre cours ce n'est d'aucune utilité.
 
== Utilisation des pointeurs typés ==
 
Pour stocker des données dans notre mémoire dynamique, il faut réserver l'espace nécessaire.
 
p est une variable de type pointeur (vers T, un type quelconque : entier...) :
 
Lexique
t : T (* une variable d'un type quelconque que l'on va stocker en mémoire dynamique *)
p : ^T (* un pointeur vers des données du type de t *)
 
On réserve l'espace nécessaire pour stocker une variable de type T en faisait appel à l'instruction :
 
new(p)
 
p contient alors l'adresse de l'espace qui nous pourront utilisé : on peut donc stocker le contenu de t en mémoire dynamique.
 
p^:=t
 
On peut libérer l'espace : c'est à dire indiquer au système d'exploitation que cette partie de la mémoire dynamique n'est plus utilisée et qu'il peut désormais en faire ce qu'il veut. Pour celà on utilise la procédure "réciproque" de <code>new</code> :
 
delete(p)
 
On remarquera qu'après un <code>delete</code> la donnée stockée reste en mémoire : seul le pointeur change de valeur (il se retrouve avec la valeur "pointeur vers vide"). La valeur de t restera en mémoire tant que le système d'exploitation n'aura pas décidé d'attribuer cet espace : cette valeur est néanmoins perdue, il n'y est plus possible d'y accéder puisque son adresse est perdue.
 
Remarque : l'utilité de ce qui est expliqué dans cette partie "utilisation" peut échappée au lecteur. En effet, cette partie sert seulement à donner les procédures <code>new</code> et <code>delete</code>. Stocker la valeur de t dans la mémoire dynamique n'a aucun interêt en soi puisque la valeur est déjà dans t. L'important est de comprendre comment (par <code>new</code> et <code>delete</code>) on peut stocker et lire des informations en mémoire dynamique.
 
=== Exemple avec des entiers ===
 
Remarque : encore une fois ce programme n'est d'aucune utilité. On pourrait en faire un équivalent sans utiliser de pointeurs. Le but est d'expliquer les mécanismes décrits précedemment.
 
Algorithme Exemple
Lexique
a : entier
b : entier
p1 : ^entier
p2 : ^entier
Début
a:=1
new(p1) (* on réserve de l'espace pour stocker un entier *)
p1^:=a (* stocke 1 dans la zone mémoire pointée par p1 *)
ecrire(p1^) (* affiche 1 *)
a:=2
ecrire(p1^) (* affiche 1 *)
p2:=p1 (* p2 va pointer la zone mémoire pointée par p1 *)
ecrire(p2^) (* affiche 1 *)
p2^:=3 (* on place 2 dans la zone mémoire pointée par p2 *)
ecrire(p1^) (* affiche 3 *)
delete(p1) (* on libère la zone pointée par p1 et donc la zone pointée par p2 *)
(* a se stade : plus aucune zone mémoire n'est réservée dans la mémoire dynamique *)
new(p1)
new(p2)
p1^:=4
p2^:=p1^+1
ecrire(p2^) (* affiche 5 *)
(* il est d'usage de libérer au maximum la mémoire dynamique : *)
delete(p1)
delete(p2)
Fin
 
== Spécification des pointeurs génériques ==