CodeS-SourceS
Rechercher un code, un tuto, une réponse

Les pointeurs en delphi

Juin 2017



  = = Les Pointeurs ==

Delphi

Bonjour, et bienvenue dans ce tutoriel concernant les pointeurs. Ce tutoriel vous permettra, je l'espère, de mieux comprendre les pointeurs et la façon dont le système Windows gère la mémoire. Nous commencerons par une introduction sur les pointeurs, leur définition, puis nous attaquerons les chapitres pas-à-pas avec des exemples pour bien comprendre le fonctionnement des pointeurs et leur gestion avec Delphi.

  • Introduction


=== Dans le sens informatique du terme, un pointeur est un nombre entier sur 32 bits (4 octets) qui représente une adresse mémoire. Une variable est une certaine portion de mémoire qui contient des informations. == =


=== Premier danger à l'horizon, il ne faut pas confondre mémoire locale et mémoire globale. La mémoire locale est une certaine quantité de mémoire qui est dédiée à un processus unique. La mémoire globale représente toute la mémoire du système, qui est composée de certains blocs de mémoire locale, et de certains blocs non utilisés. Cependant, un grand avantage des pointeurs est qu'ils peuvent accéder à la mémoire globale, alors que les variables objet (TBitmap, Integer, ...) sont stockées automatiquement dans la mémoire locale du processus. Néanmoins, il faut avoir l'autorisation d'accéder à un endroit de la mémoire avant de même songer à y toucher (c'est là l'origine des violations d'accès, entre autres ...). == =

Ce texte sera le fil conducteur de tout le tutoriel :



Représentons la mémoire comme une ville, avec des maisons de taille différente, qui représentent des portions de mémoire, des variables. Les quartiers de la ville sont les processus, imaginons qu'on ne puisse pas changer de quartier sans avoir une autorisation de la mairie de notre quartier. Je suis un nouvel habitant, j'ai acheté une maison de taille 2 octets sur 2 octets. J'ai donc une portion de mémoire de 4 octets, et j'ai une adresse sur ma boîte aux lettres. Supposons que mon adresse soit 123. Je n'ai pas le droit de changer cette adresse, mais j'ai le droit de changer la décoration de ma maison. Je représente la décoration de ma maison par un nombre de 4 octets (de la taille de ma maison en fait). En arrivant, j'ai envie de mettre la déco à la valeur 736. Puis, en me promenant dans la rue, je change d'avis. Vite, j'arrive devant ma maison, je vois mon adresse, et j'ouvre la porte. C'est le principe du déréférencement (c'est-à-dire accéder à une variable à partir de son adresse). Je change ma déco à la valeur 12. Puis, je décide d'aller voir mon ami qui se trouve dans le quartier voisin. Une fois arrivé à la séparation des deux quartiers, on me dit que je suis un étranger et que les étrangers sont interdits. Vexé, je contacte mon ami par téléphone (ils seront symbolisés par les messages Windows). Il me dit par téléphone les détails de sa décoration, en m'indiquant bien qu'il a une plus grande maison que la mienne (16 octets). Je lui réponds que je n'ai pas le droit d'aller chez lui, et lui n'a pas le droit d'aller chez moi, et je lui fais part d'une idée pour pouvoir se transmettre des informations facilement. Parce que le téléphone, ça n'est pas sans risque : nos conversations peuvent être écoutées ... Si je bâtissais, dans un coin reculé de la ville, une petite cabane de 4 octets, sous aucune autorité, où mon ami et moi pourront échanger nos codes de décoration. J'irai dans la cabane, je déposerai une décoration dedans, j'appellerai mon ami pour lui dire d'aller voir ma nouvelle décoration dans la cabane, comme ça il pourra changer la sienne lui-même. Évidemment, nous aurons tous deux une clé pour rentrer dans la cabane, comme ça nous seuls pourrons rentrer dans la cabane. (La clé représente l'adresse de la cabane, ici).



Autant de thèmes que nous allons aborder dans ce tutoriel :

  • Création et libération de pointeurs
  • Variables et pointeurs
  • Accès à la mémoire d'un autre processus (mémoire partagée)
  • Création et libération de pointeurs
  • Notion de pointeur dans Delphi


=== Dans Delphi, un pointeur est d'abord de type pointer . Mais ce pointer tel qu'il est ne sert pas à grand-chose, car il ne pointe sur aucun type précis. Il faut donc préciser le type du pointeur. Il existe quelques types de pointeur prédéfinis, comme le pointeur qui pointe sur un byte (PByte), un mot, ou word (PWord), un double mot, ou dword (PDWord). Notez que par convention, on rajoute (ou on remplace le T par) un P pour indiquer qu'il s'agit d'un pointeur. Vous pouvez créer vos propres types de pointeur, suivant ce modèle : == =

=== type
 TMonType = record
  Titre: String[255 = ==
  • ;

  Numero: Integer;
 end ;
 { Imaginons un enregistrement quelconque ... }

 PMonType = ^TMonType;
 { L'accent circonflexe devant le nom du type déclare un type de pointeur qui pointera sur ce type }

= == Vocabulaire : un pointeur qui ne pointe sur aucun type est appelé un pointeur non typé , en Delphi. == =
  • Utilisation du pointeur dans Delphi


=== Tout pointeur que vous créerez sera simplement une adresse 32 bits (4 octets). Vous pouvez choisir de laisser Delphi choisir un emplacement de mémoire libre pour le pointeur, ou vous pouvez choisir vous-même l'adresse du pointeur (attention, vous devrez vous assurer que vous avez le droit d'accéder à cette adresse). Soit le code suivant : == =

=== var
 Pointeur: PByte; { PByte est un pointeur qui pointe vers un emplacement mémoire 1 octet } == =

begin
 New(Pointeur); { On laisse Delphi choisir un emplacement de mémoire libre }
 Pointeur^ : = 45; { L'emplacement de mémoire contient à présent la valeur 45 }
 { On utilise ^ pour indiquer qu'on manipule l'emplacement pointé par le pointeur et non pas le pointeur }
 Dispose(Pointeur); { On libère le pointeur et la mémoire sur lequel il pointait }

 Pointeur := Ptr(6434); { On fait pointer notre pointeur vers l'emplacement 6434 de la mémoire }
 { Vous n'aurez probablement pas le droit d'accéder à cet emplacement }
 Pointeur^ := 22; { On change la valeur, mais il est très probable que ça ne fonctionne pas ... }
 Dispose(Pointeur); { Dans ces circonstances, il ne faut pas appeler Dispose, car cela libérerait l'emplacement 6434, qui contient peut-être des données très importantes (dans ce cas, Delphi lèvera une exception vous indiquant que vous n'avez pas le droit d'accéder à ces données) }
end ;

== = Comme vous l'aurez constaté, il y a plus de précautions à prendre lorsque l'on choisit soit-même son adresse. En fait, on ne la choisit même pas. En général, on fait pointer un pointeur sur une variable qui existe déjà en mémoire. On laissera généralement Delphi créer et libérer la mémoire pour nous, sauf dans de rares exceptions très particulières. ===

=== Vocabulaire : quand on affecte une adresse à un pointeur, on dit qu'on l' initialise . On peut initialiser en utilisant New, ou en faisant pointer le pointeur sur une variable existante. == =
  • Déréférencement


=== Ce mot barbare porte bien son nom, car il a pour effet d'accéder à une variable plutôt qu'à sa référence (le pointeur qui pointe dessus). On parle donc de déréférencement quand on veut accéder aux données sur lesquelles pointe notre pointeur. Il est très simple de déréférencer le pointeur en Delphi, puisqu'il suffit d'ajouter un accent circonflexe après le pointeur, comme ceci : == =

=== var
 Pointeur: PByte;
begin
 New(Pointeur); { On crée notre pointeur et la variable sur laquelle il pointe } == =

 Pointeur^ := 63; { On déréférence le pointeur pour que les données sur lesquelles il pointe prennent la valeur 63 }
 Dispose(Pointeur); { On libère le tout }
end ;

== = Une fois le pointeur déréférencé, traitez-le comme s'il s'agissait d'une variable du type sur lequel le pointeur pointe . == =

Attention : déréférencer un pointeur de type pointer n'a pas de sens car il ne pointe sur aucun type, autrement dit, le compilateur ne sait pas ce qu'il faut stocker à l'adresse du pointeur. Delphi déclenchera éventuellement une erreur de compilation si vous tentez de déréférencer un pointeur non typé. Déréférencer un pointeur avant de l'initialiser ne provoque pas d'erreur de compilation (peut-être un avertissement) mais causera une erreur à l'exécution. De même, tenter de déréférencer un pointeur qui pointe sur une variable inexistante ou interdite d'accès provoquera aussi une erreur d'exécution, ou, dans le meilleur des cas, stocker (ou lire) une valeur nulle dans la variable.

  • Résumé


=== Dans ce chapitre, vous aurez appris comment créer et libérer un pointeur , vous aurez acquis la notion de pointeur et de type de pointeur, et vous saurez comment déréférencer votre pointeur.
Dans le chapitre suivant, nous approfondirons le lien qui existe entre variable et pointeur. == =
  • Variables et pointeurs
  • La variable

Nous avons vu dans le précédent chapitre les bases sur les pointeurs en Delphi. Nous allons maintenant approfondir la relation qui unit la variable et le pointeur, après avoir défini le terme de variable .
Une variable est une portion de mémoire dans la mémoire globale. Elle est définie par un début, une taille, et peut être associée à un ou plusieurs pointeurs, qui représentent le début de la variable, et qui peuvent spécifier implicitement la taille de la variable s'ils sont typés (un pointeur non typé n'est associé à aucun type de variable précis, il ne véhicule donc pas d'information sur la taille de la variable sur laquelle il pointe). Voici un schéma pour mieux comprendre :


 


Adresse d'origine

A voir également

Publié par Bacterius.
Ce document intitulé «  Les pointeurs en delphi  » issu de CodeS-SourceS (codes-sources.commentcamarche.net) est mis à disposition sous les termes de la licence Creative Commons. Vous pouvez copier, modifier des copies de cette page, dans les conditions fixées par la licence, tant que cette note apparaît clairement.
Les fibers : des threads non preemptables
Envoyer des chaînes unicode sur le réseau