Que vous le réalisiez ou non, la grande majorité des programmes que vous avez utilisés utilisent des pointeurs d’une manière ou d’une autre. Peut-être avez-vous vécu une NullPointerException à un moment donné. En tant que programmeur, le code que vous écrivez utilisera plus que probablement des pointeurs, même si vous ne les avez pas implémentés vous-même.
Aujourd’hui, je vais vous montrer comment fonctionnent les pointeurs, vous voudrez donc peut-être vérifier comment fonctionnent les tableaux et les listes pour une amorce de programmation. Cet article sera plus théorique que d’habitude, mais restez-y, les pointeurs sont très complexes !
Code de compilation
Avant de creuser dans les pointeurs, vous devez comprendre comment le code est construit et exécuté — peut-être le savez-vous déjà. Cette section contiendra des déclarations assez générales – des choses qui s’appliquent à la majorité des langues, mais pas nécessairement toutes.

Reprenons les choses au début. Chaque ordinateur utilise du binaire, une série de uns et de zéros qui constituent la technologie moderne telle que nous la connaissons. Il est extrêmement difficile de coder quoi que ce soit en binaire (les fichiers seraient très déroutants), car ce sont les instructions brutes nécessaires à votre unité centrale de traitement ou CPUpour fonctionner. Ceci est connu comme Langage machine.
La prochaine étape du code machine est Assemblée. Il s’agit d’un format quelque peu lisible par l’homme. Bien qu’il soit encore complexe à programmer, c’est possible. L’assemblage est composé d’une série de commandes simples pour exécuter des tâches, et est connu comme un niveau faible langage de programmation. Il est possible d’écrire des programmes complexes, mais il est difficile d’exprimer des concepts abstraits et demande beaucoup de réflexion.
De nombreux jeux vidéo et applications hautes performances ont une partie de la logique écrite en assemblage, car de réelles augmentations de vitesse peuvent être trouvées si vous savez ce que vous faites. Cependant, pour la grande majorité des projets de programmation, vous n’avez besoin de connaître aucun assembly.

Donc, si le code machine est trop difficile à écrire et que l’assemblage est trop difficile à programmer, avec quoi écrivez-vous du code ? Voici où haut niveau les langages entrent en jeu. Les langages de haut niveau rendent les programmes faciles à écrire. Vous pouvez programmer dans quelque chose qui ressemble à votre langue maternelle, et il est facile d’exprimer des algorithmes complexes. Vous avez peut-être entendu parler de nombreux langages de haut niveau (et vous aurez certainement utilisé un programme écrit dans ces langages) :
- DE BASE
- C++
- Zézayer
Ces langages sont très anciens maintenant, et beaucoup ont été développés au début des années 1950 ! Presque tous les langages de programmation modernes sont des langages de haut niveau, y compris PHP et Python. De plus en plus de langages sont inventés chaque jour (bien qu’il y en ait probablement assez maintenant), mais comment exactement votre code fonctionne-t-il correctement si les ordinateurs nécessitent du code machine ?
C’est ici qu’intervient la compilation. Un compilateur est un programme qui convertit votre code de haut niveau en une forme qui peut être exécutée. Cela pourrait être un autre langage de haut niveau, mais il s’agit généralement d’assembly. Certains langages (comme Python ou Java) convertissent votre code en une étape intermédiaire appelée bytecode. Cela nécessitera une nouvelle compilation à une date ultérieure, ce qui est généralement fait à la demande, comme lors de l’exécution du programme. Ceci est connu comme juste à temps compilation, et c’est très populaire.
Gestion de la mémoire
Maintenant que vous savez comment fonctionnent les langages de programmation, intéressons-nous à la gestion de la mémoire dans les langages de haut niveau. Pour ces exemples, j’utiliserai du pseudo-code — du code écrit dans un langage spécifique, mais utilisé pour montrer des concepts plutôt que la syntaxe exacte. Aujourd’hui, cela ressemblera principalement à C++ car c’est le meilleur langage de haut niveau (à mon avis).
Pour cette section, cela vous aidera si vous comprenez le fonctionnement de la RAM.
La plupart des langues ont des variables — des conteneurs qui stockent des données. Vous devez définir explicitement le type de données. Certains langages à typage dynamique tels que Python ou PHP gèrent cela pour vous, mais ils doivent toujours le faire.
Disons que vous avez une variable :
int myNumber;
Ce code déclare une variable appelée mon numéro, et lui donne un type de données de entier. Une fois compilée, l’ordinateur interprète cette commande comme :
“Trouvez de la mémoire vide et réservez un espace suffisamment grand pour stocker un entier”
Une fois cette commande exécutée, ce bit de mémoire ne peut pas être utilisé par un autre programme. Il ne contient pas encore de données, mais il est réservé à votre variable myNumber.
Attribuez maintenant une valeur à votre variable :
myNumber = 10;
Pour terminer cette tâche, votre ordinateur accède à son emplacement de mémoire réservé et modifie la valeur qui y est stockée en cette nouvelle valeur.
C’est bien beau, mais comment les emplacements mémoire ne sont-ils pas réservés ? Si les programmes réservaient toute la mémoire qu’ils aiment, la RAM se remplirait immédiatement — cela ferait un très système lent.

Pour éviter ce problème potentiel, de nombreux langages implémentent un Éboueur, utilisé pour détruire les variables (et donc libérer les emplacements mémoire réservés) qui ont disparu hors de portée.
Vous vous demandez peut-être quelle est la portée et pourquoi elle est si importante. La portée définit les limites et la durée de vie des variables ou de toute mémoire utilisée par un programme. Une variable est “hors de portée” lorsqu’elle n’est plus accessible par aucun code (c’est à ce moment-là que le ramasse-miettes intervient). Voici un exemple :
function maths() { int firstNumber = 1;}int secondNumber = 2;print(firstNumber + secondNumber); // will not work
Cet exemple ne compilera pas. La variable premierNuméro est dans le mathématiques fonction, c’est donc sa portée. Il n’est pas accessible depuis l’extérieur de la fonction dans laquelle il a été déclaré. C’est un concept de programmation important, et comprendre qu’il est crucial de travailler avec des pointeurs.
Cette façon de gérer la mémoire est appelée empiler. C’est ainsi que fonctionnent la grande majorité des programmes. Vous n’avez pas besoin de comprendre les pointeurs pour l’utiliser, et c’est assez bien structuré. L’inconvénient de la pile est la vitesse. Comme l’ordinateur doit affecter de la mémoire, garder une trace des variables et exécuter le ramasse-miettes, il y a une petite surcharge. C’est bien pour les petits programmes, mais qu’en est-il des tâches hautes performances ou des applications lourdes en données ?
Entrer : pointeurs.
Pointeurs
En surface, les pointeurs semblent simples. Ils font référence (pointer vers) un emplacement en mémoire. Cela peut ne pas sembler différent des variables “normales” de la pile, mais croyez-moi, il y a une énorme différence. Les pointeurs sont stockés sur le tas. C’est le contraire de la pile — c’est moins organisé, mais c’est beaucoup plus rapide.
Regardons comment les variables sont affectées sur la pile :
int numberOne = 1;int numberTwo = numberOne;
C’est une syntaxe simple ; La variable numéro deux contient le numéro un. Sa valeur est copiée pendant l’affectation à partir du numéro un variable.
Si vous vouliez obtenir le adresse mémoire d’une variable, au lieu de sa valeur, vous devez utiliser le signe esperluette (&). C’est ce qu’on appelle le adresse de opérateur, et est une partie essentielle de votre boîte à outils de pointeur.
int numberOne = 1;int numberTwo = &numberOne;
Maintenant le numéro deux variable points vers un emplacement mémoire, plutôt que de faire copier le numéro un dans son propre nouvel emplacement mémoire. Si vous deviez sortir cette variable, ce ne serait pas le numéro un (même s’il est stocké dans l’emplacement mémoire). Il afficherait son emplacement mémoire (probablement quelque chose comme 2167, bien que cela varie en fonction du système et de la RAM disponible). Pour accéder à la valeur stockée dans un pointeur, au lieu de l’emplacement mémoire, vous devez déréférencement le pointeur. Cela accède directement à la valeur, qui serait le numéro un dans ce cas. Voici comment déréférencer un pointeur :
int numberTwo = *numberOne;
Les opérateur de déréférencement est un astérisque
.
- Cela peut être un concept difficile à comprendre, alors reprenons-le : Les adresse de
- l’opérateur (&) stocke l’adresse mémoire. Les opérateur de déréférencement
int * myPointer;
accède à la valeur. La syntaxe change légèrement lors de la déclaration des pointeurs : Le type de données de entier fait ici référence au type de données du pointeur
points à, et non le type du pointeur lui-même.Maintenant que vous savez ce que sont les pointeurs, vous pouvez faire des trucs vraiment sympas avec eux ! Lorsque la mémoire est utilisée, votre système d’exploitation démarre

. Vous pouvez considérer la RAM comme des casiers. De nombreux trous pour ranger quelque chose, un seul peut être utilisé à la fois. La différence ici est que ces casiers sont tous numérotés. Lors de l’attribution de la mémoire, votre système d’exploitation démarre au numéro le plus bas et fonctionne. Il ne sautera jamais entre des nombres aléatoires.
Pointeurs

C’est là que ça devient intéressant. Lorsque vous transmettez des valeurs à une fonction (à l’aide de variables stockées sur la pile), ces valeurs sont copiées dans votre fonction. S’il s’agit de grosses variables, votre programme les stocke maintenant deux fois. Lorsque votre fonction est terminée, vous aurez peut-être besoin d’un moyen de renvoyer ces valeurs. Les fonctions ne peuvent généralement renvoyer qu’une seule chose. Et si vous vouliez renvoyer deux, trois ou quatre choses ?
Pointeurs

Il faut quand même être très prudent. Les pointeurs peuvent toujours sortir de la portée et être collectés par le ramasse-miettes. Les valeurs stockées en mémoire, cependant, ne sont pas collectées. C’est ce qu’on appelle une fuite de mémoire. Vous ne pouvez plus accéder aux données (car les pointeurs ont été détruits), mais cela consomme toujours de la mémoire. C’est une raison courante pour laquelle de nombreux programmes se bloquent, et cela peut échouer de manière spectaculaire s’il y a une grande quantité de données. La plupart du temps, votre système d’exploitation tuera votre programme si vous avez une fuite importante (en utilisant plus de RAM que le système n’en a), mais ce n’est pas souhaitable.
Pointeurs
Le débogage des pointeurs peut être un cauchemar, surtout si vous travaillez avec de grandes quantités de données ou en boucle. Leurs inconvénients et leur difficulté à comprendre valent vraiment les compromis que vous gagnez en performance. Bien que rappelez-vous, ils peuvent ne pas toujours être nécessaires.
C’est tout pour aujourd’hui. J’espère que vous avez appris quelque chose d’utile sur un sujet complexe. Bien sûr, nous n’avons pas couvert tout ce qu’il y a à savoir — c’est un sujet très complexe. Si vous souhaitez en savoir plus, je recommande fortement C++ en 24 heures.
Si cela était un peu complexe, jetez un œil à notre guide des langages de programmation les plus simples.
Avez-vous appris comment fonctionnent les pointeurs aujourd’hui ? Avez-vous des trucs et astuces que vous souhaitez partager avec d’autres programmeurs ? Sautez dans les commentaires et partagez vos réflexions ci-dessous!