Publicité
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. Vous avez peut-être vécu NullPointerException à un moment donné. En tant que programmeur, le code que vous écrivez utilisera très 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. fonctionnement des tableaux et des listes Fonctionnement des tableaux et des listes en PythonLes tableaux et les listes sont parmi les structures de données les plus utiles dans la programmation - bien que peu de gens les utilisent à leur plein potentiel. Lire la suite pour une amorce de programmation. Cet article sera plus basé sur la théorie que d'habitude, mais respectez-le, 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é - vous le savez peut-être déjà. Cette section contiendra des déclarations assez générales - des choses qui s’appliquent
majorité des langues, mais pas nécessairement toutes.Reprenons les choses au début. Chaque ordinateur utilise le binaire Qu'est-ce que le binaire? [La technologie expliquée]Étant donné que le binaire est si fondamental pour l'existence des ordinateurs, il semble étrange que nous n'ayons jamais abordé le sujet auparavant - alors aujourd'hui, je pensais que je donnerais un bref aperçu de ce que le binaire ... Lire la suite , une série de uns et de zéros qui composent 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 confus), car ce sont les instructions brutes nécessaires à votre unité centrale de traitement ou CPU pour fonctionner Qu'est-ce qu'un CPU et que fait-il?Les acronymes informatiques prêtent à confusion. Qu'est-ce qu'un CPU de toute façon? Et ai-je besoin d'un processeur quadruple ou double cœur? Qu'en est-il d'AMD ou d'Intel? Nous sommes là pour vous expliquer la différence! Lire la suite . Ceci est connu comme Langage machine.
L'étape suivante du code machine est Assemblée. Il s'agit d'un format quelque peu lisible par l'homme. Bien que la programmation soit encore complexe, elle est possible. L'assemblage est composé d'une série de commandes simples pour exécuter des tâches et est appelé niveau faible langage de programmation. Il est possible d’écrire des programmes complexes, mais il est difficile d’exprimer des concepts abstraits et nécessite beaucoup de considération.
De nombreux jeux vidéo et applications hautes performances ont une partie de la logique écrite en assembleur, car certaines augmentations de vitesse réelles peuvent être trouvées si vous savez ce que vous faites. Cependant, pour la grande majorité des projets de programmation, vous n'avez pas besoin de connaître d'assemblage.
Donc, si le code machine est trop difficile à écrire et que l'assemblage est trop difficile à programmer, avec quoi écrivez-vous le code? Voici où haut niveau les langues entrent. Les langages de haut niveau rendent les programmes faciles à écrire. Vous pouvez programmer quelque chose qui ressemble à votre langue maternelle et il est facile d'exprimer des algorithmes complexes. Vous avez peut-être entendu parler de nombreuses langues de haut niveau (et vous aurez certainement utilisé un programme écrit en elles):
- DE BASE
- C ++
- Zézayer
Ces langues sont maintenant très anciennes et beaucoup ont été développées au début des années 50! Presque tous les langages de programmation modernes sont des langages de haut niveau, y compris PHP et Python. De plus en plus de langues sont inventées chaque jour (bien qu'il y en ait probablement assez maintenant), mais comment fonctionne exactement votre code si les ordinateurs nécessitent un code machine?
Voici où la compilation entre en jeu. Un compilateur est un programme qui convertit votre code de haut niveau en un formulaire qui peut être exécuté. Cela pourrait être un autre langage de haut niveau, mais c'est généralement l'assemblage. Certains langages (tels que Python ou Java) convertissent votre code en une étape intermédiaire appelée bytecode. Cela devra être compilé à nouveau à une date ultérieure, ce qui se fait généralement à la demande, par exemple lors de l'exécution du programme. Ceci est connu comme juste à temps compilation, et c'est assez populaire.
Gestion de la mémoire
Maintenant que vous savez comment fonctionnent les langages de programmation, regardons la gestion de la mémoire dans les langages de haut niveau. Pour ces exemples, j'utiliserai pseudo code - code écrit pas dans un langage spécifique, mais utilisé pour montrer des concepts plutôt que la syntaxe exacte. Aujourd'hui, cela ressemblera surtout au C ++ car c'est le meilleur langage de haut niveau (à mon avis).
Pour cette section, il vous sera utile si vous comprenez comment fonctionne la RAM Un guide rapide et sale sur la RAM: ce que vous devez savoirLa RAM est un élément crucial de chaque ordinateur, mais cela peut prêter à confusion. Nous le décomposons en termes faciles à comprendre, vous comprendrez. Lire la suite .
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 typés dynamiquement 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éroet lui donne un type de données entier. Une fois compilée, l'ordinateur interprète cette commande comme:
"Trouvez de la mémoire vide et réservez un espace assez 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:
monNombre = 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.
Maintenant, tout va bien, mais comment les emplacements de mémoire peuvent-ils être 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 nombreuses langues implémentent un Éboueur, utilisé pour détruire les variables (et donc libérer les emplacements de mémoire réservés) qui ont disparu hors champ.
Vous vous demandez peut-être quelle est la portée et pourquoi elle est si importante. Scope 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 que le garbage collector intervient). Voici un exemple:
fonction maths () {int firstNumber = 1; } int secondNumber = 2; print (firstNumber + secondNumber); // ne fonctionnera pas
Cet exemple ne se compilera pas. La variable firstNumber 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é. Ceci est un concept de programmation importantet comprendre qu'il est essentiel de travailler avec des pointeurs.
Cette façon de gérer la mémoire est appelée empiler. C’est ainsi que fonctionne 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 la récupération de place, 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 gourmandes en données?
Entrez: 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» sur la pile, mais croyez-moi, il y a une énorme différence. Les pointeurs sont stockés sur le tas. C'est l'opposé de la pile - elle est moins organisée, mais elle est beaucoup plus rapide.
Voyons comment les variables sont affectées sur la pile:
int numberOne = 1; int numberTwo = numberOne;
Il s'agit d'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 et est un élément essentiel de votre boîte à outils de pointeur.
int numberOne = 1; int numberTwo = & numberOne;
Maintenant le numéro deux variable points vers un emplacement de mémoire, plutôt que de copier le numéro un vers son propre nouvel emplacement de mémoire. Si vous deviez sortir cette variable, ce ne serait pas le numéro un (même si cela est stocké dans l'emplacement mémoire). Il afficherait son emplacement mémoire (probablement quelque chose comme 2167, bien qu'il varie en fonction du système et de la mémoire 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 vous déréférencer un pointeur:
int numberTwo = * numberOne;
le opérateur de déréférence est un astérisque (*).
Cela peut être un concept difficile à comprendre, alors revenons-y:
- le adresse de L'opérateur (&) stocke l'adresse mémoire.
- le opérateur de déréférence (*) accède à la valeur.
La syntaxe change légèrement lors de la déclaration des pointeurs:
int * myPointer;
Le type de données de int se réfère ici 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 séquentiellement. Vous pouvez considérer la RAM comme des trous de pigeon. Beaucoup de trous pour ranger quelque chose, un seul peut être utilisé à la fois. La différence ici est que ces trous de pigeon sont tous numérotés. Lors de l'attribution de 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.
Lorsque vous travaillez avec des pointeurs, si vous avez affecté un tableau, vous pouvez facilement naviguer vers l'élément suivant en incrémentant simplement votre pointeur.
Voici où cela 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 grandes variables, votre programme les stocke maintenant deux fois. Lorsque votre fonction est terminée, vous devrez peut-être 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?
Si vous passez un pointeur sur votre fonction, seule l'adresse mémoire est copiée (ce qui est minuscule). Cela économise beaucoup de travail à votre CPU! Peut-être que votre pointeur pointe vers un immense tableau d'images - non seulement votre fonction peut-elle fonctionner exactement de la même manière données stockées dans le même emplacement de mémoire, mais une fois cela fait, il n'est pas nécessaire de retourner n'importe quoi. Soigné!
Vous devez cependant être très prudent. Les pointeurs peuvent toujours être hors de portée et collectés par le ramasse-miettes. Cependant, les valeurs stockées en mémoire 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 il utilise toujours de la mémoire. C'est une raison courante pour laquelle de nombreux programmes se bloquent, et cela peut échouer de façon 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), mais ce n'est pas souhaitable.
Les pointeurs de débogage peuvent être un cauchemar, surtout si vous travaillez avec de grandes quantités de données ou si vous travaillez en boucle. Leurs inconvénients et leur difficulté à comprendre valent vraiment les compromis que vous gagnez en performances. N'oubliez pas qu'ils ne sont pas toujours 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 c'était un peu complexe, jetez un œil à notre guide des langages de programmation les plus simples 6 langages de programmation les plus faciles à apprendre pour les débutantsApprendre à programmer, c'est tout autant trouver le bon langage que le processus d'édification. Voici les six premiers langages de programmation les plus simples pour les débutants. Lire la suite .
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!
Joe est diplômé en informatique de l'Université de Lincoln, au Royaume-Uni. C'est un développeur de logiciels professionnel, et lorsqu'il ne pilote pas de drones ou n'écrit pas de musique, il peut souvent être trouvé en train de prendre des photos ou de produire des vidéos.