Bases du pointeur du débutant

Présentation


Aujourd'hui, en raison de l'amélioration et de la réduction des coûts de la technologie, la quantité de mémoire et de puissance de traitement augmente régulièrement.

Selon la loi de Moore:
Le nombre de transistors placés sur une puce de circuit intégré double tous les 24 mois.
Il est à noter que deux paramètres sont modifiés:

  • Nombre de transistors
  • Dimensions du module

Les mêmes principes sont projetés sur la quantité de RAM (DRAM).

Maintenant, le problème de la mémoire n'est pas aigu, car la quantité de mémoire au cours des 10 dernières années a augmenté de 16 fois par dé.

La plupart des langages de programmation de haut niveau (PL) sont déjà «prêts à l'emploi» masquant le travail avec la mémoire du programmeur. Et, puisque cette question dormait, une nouvelle caste de programmeurs apparaît qui ne comprend pas ou ne veut pas comprendre comment fonctionne le travail avec la mémoire.

Dans cette rubrique, nous considérerons les principaux points de l'utilisation de la mémoire en utilisant l'exemple du langage C ++, car il s'agit de l'un des rares langages impératifs qui prend en charge le travail direct avec la mémoire et prend en charge la POO.

À quoi sert l'informatique?


Il convient de mentionner ici, cet article est conçu pour les personnes qui commencent tout juste leur chemin en C ++ ou veulent simplement avoir une idée de la mémoire dynamique.

Au moment de l'exécution, tout programme se réserve un morceau de mémoire dans la DRAM. Tous les autres espaces libres DRAM sont appelés «tas» («tas» en anglais). L'allocation de mémoire pendant l'exécution pour les besoins du programme se produit précisément à partir du tas et s'appelle l'allocation de mémoire dynamique.

Tout le problème est que si vous ne vous occupez pas de nettoyer la mémoire allouée lorsqu'elle n'est plus nécessaire, une soi-disant fuite de mémoire peut se produire, dans laquelle votre système (programme) se bloque simplement. Semblable à une voiture qui a calé au milieu de la route parce que quelqu'un a oublié de faire le plein à temps.

Ce que vous devez déjà savoir
La plupart des PL modernes sont équipés de collecteurs d'ordures et se vident d'eux-mêmes.
Cependant, C ++ s'est imposé comme l'une des API les plus performantes, en partie parce que tout le travail avec de la mémoire se fait manuellement.


nouveau et supprimer


L'allocation de mémoire peut être statique et dynamique. L'allocation statique de mémoire est appelée une allocation unique de mémoire lors de la compilation du programme, et la quantité de mémoire statique ne change pas au moment de l'exécution. Un exemple classique est la déclaration d'une variable entière ou d'un tableau. Mais que faire si le programmeur ne sait pas à l'avance combien d'éléments sont nécessaires dans le conteneur?
L'utilisation de la mémoire dynamique est conseillée lorsqu'il est nécessaire d'organiser l'allocation de mémoire pour les besoins du programme selon les besoins.
Le nouvel opérateur est responsable de l'allocation de mémoire dynamique en C ++, et delete est responsable de son effacement.
Le nouvel opérateur renvoie le résultat de son opération un pointeur sur une nouvelle instance de la classe.
La syntaxe est la suivante:

| pointeur de type de données (T1) | * | nom du pointeur | = nouveau | type T1 |;

Après le nouvel opérateur, vous pouvez utiliser le constructeur, par exemple, pour initialiser les champs de la classe.
Il convient de noter que la même fuite de mémoire se produit exactement lorsque le programmeur perd le contrôle de son allocation.
Il est important de se rappeler:
Si vous avez oublié de vider la mémoire dynamique des éléments inutiles «dépensés», tôt ou tard, un moment critique viendra où il ne sera plus possible de retirer la mémoire.

Un exemple d'allocation de mémoire et de son nettoyage:
int main{ // ,       new int *ptr = new int(); //   cout<<*ptr<<endl; // ,     delete ptr; //  delete     ,         return 0; } 


Cet article ne traitera pas des pointeurs dits «intelligents», car le sujet est très étendu, mais, en bref: «Les pointeurs intelligents automatisent partiellement le processus d'effacement de la mémoire pour le programmeur».

Pointeurs


Les pointeurs sont chargés de travailler avec la mémoire dynamique en C ++. C'est un sujet à partir duquel l'appétit gâte les débutants.

Vous pouvez déclarer un pointeur à l'aide de l'opérateur * . Par défaut, il pointera vers une région aléatoire de la mémoire. Afin que nous puissions accéder à la zone de mémoire dont nous avons besoin, nous devons passer un lien (opérateur & ) à la variable souhaitée.

Le pointeur lui-même est simplement l'adresse d'une cellule mémoire, et pour accéder aux données stockées dans cette cellule, il faut le déréférencer.

Retraite importante


Si vous essayez d'afficher le pointeur sans déréférencer, alors au lieu de la valeur de la zone mémoire vers laquelle il pointe, l'adresse de cette zone mémoire est affichée.
Pour déréférencer un pointeur, placez simplement l'opérateur * devant son nom.


 int main() { // ,          int* pNum= new int(1) ; cout<<*pNum<<endl; //    ,        ,       (   int   ) pNum++; cout<<*pNum<<endl; // ,         return 0; } 



En regardant de tels exemples, je voudrais demander: "Pourquoi est-ce même nécessaire si vous pouvez dériver immédiatement une variable?"

Un autre exemple:

Nous avons une classe de programmeurs qui décrit les membres d'une équipe de programmeurs qui ne connaissent pas les pointeurs.

  class Programmers{ public: Programmers(){} Programmers(int iWeight, int iAge){ this->weight = iWeight; this->age = iAge; } int weight; int age; }; int main() { //     Programmers int size = 9; Programmers *prog [size]; //  Programmers Programmers *ptr = nullptr; //     Programmers       //          for (int i =0;i<size;i++) { ptr=new Programmers(i+100,i); prog[i]=ptr; } return 0; } 

De cette façon, la mémoire peut être manipulée à notre guise. Et c'est pourquoi, lorsque vous travaillez avec la mémoire, vous pouvez "vous tirer une balle dans le pied". Il convient de noter que travailler avec le pointeur est beaucoup plus rapide, car la valeur elle-même n'est pas copiée, mais seul un lien vers une adresse spécifique lui est attribué.

Soit dit en passant, un tel mot - clé populaire fournit un pointeur vers l'objet de classe actuel. Ces pointeurs sont partout.

Un exemple de pointeur au quotidien:

Imaginez une situation lorsque vous commandez un plat dans un restaurant. Pour passer une commande, il vous suffit de pointer le plat dans le menu et vous serez prêt. De la même manière, les autres visiteurs du restaurant indiquent l'élément souhaité dans le menu. Ainsi, chaque ligne du menu est un pointeur sur la fonction de cuisson d'un plat, et ce pointeur a été créé au stade de la conception de ce menu lui-même.

Exemple de pointeur de fonction
 //      void Chicken(){ cout<<"Wait 5 min...Chicken is cooking"<<endl; } void JustWater(){ cout<<"Take your water"<<endl; } int main() { //    void   void (*ptr)(); ptr = Chicken; ptr(); ptr=JustWater; ptr(); return 0; } 



Retour à nos programmeurs. Supposons maintenant que nous ayons besoin de prendre les champs de la classe dans la section privée , comme il sied au principe d'encapsulation de la POO, puis nous devons obtenir pour obtenir un accès en lecture à ces champs. Mais imaginez que nous n'avons pas 2 champs, mais 100, et pour cela nous devons écrire notre propre accesseur pour chacun?

Spoiler
Bien sûr que non, je ne comprends même pas pourquoi vous avez ouvert ce becquet.

Pour ce faire, nous allons faire un «accesseur» de type void et lui passer des arguments par référence. Le passage d'un argument par référence signifie que la valeur de l'argument n'est pas copiée, mais seule l'adresse de l'argument réel est transmise. Ainsi, lors de la modification de la valeur d'un tel argument, les données de la cellule mémoire de l'argument actuel changeront également.
Cela affecte également les performances globales, car le passage d'un argument par référence est plus rapide que le passage par la valeur. Et cela sans parler des grandes collections d'éléments.

Par exemple, la méthode getParams à l' intérieur changera les arguments entrants et ils changeront leurs valeurs, y compris dans la portée, d'où elles ont été appelées.
Un pointeur nous aidera à naviguer dans le tableau. De la théorie des structures de données, nous savons qu'un tableau est une région continue de mémoire dont les éléments sont disposés les uns après les autres.
Cela signifie que si vous modifiez la valeur du pointeur en nombre d'octets que l'élément occupe dans le tableau, vous pouvez atteindre chaque élément jusqu'à ce que le pointeur dépasse les limites du tableau.
Créez un autre pointeur qui pointera vers le premier élément du tableau des programmeurs .

 class Programmers{ public: Programmers(){} Programmers(int iWeight, int iAge){ this->weight = iWeight; this->age = iAge; } //    ,   main     void getParams(int &w, int &a){ w=weight; a=age; } private: int weight; int age; }; int main() { int size = 9; Programmers *prog [size]; Programmers *ptr=nullptr; for (int i =0;i<size;i++) { ptr=new Programmers(i+100,i); prog[i]=ptr; } int w,a; int count = 9; //    //        Programmers **iter = prog; for (int i=0;i<count;i++) { ptr = *iter++; ptr->getParams(w,a); if(*(iter-1) != nullptr){ delete *(iter-1); ptr = nullptr; } cout<<w<<"\t"<<a<<endl; } return 0; } 



Dans cet exemple, je veux vous transmettre l'essence du fait que lorsque vous modifiez la valeur de l'adresse du pointeur, vous pouvez accéder à une autre zone de mémoire.

Structures de données telles que listes, vecteurs, etc. basé sur des pointeurs, et donc appelé structures de données dynamiques. Et pour les parcourir, il est plus correct d'utiliser des itérateurs. Un itérateur est un pointeur sur un élément de la structure de données et donne accès à l'élément du conteneur.

En conclusion


Ayant compris le sujet des pointeurs, travailler avec la mémoire devient une partie agréable de la programmation et, dans l'ensemble, une compréhension détaillée du fonctionnement de la machine avec la mémoire et de sa gestion apparaît. Dans un sens, il y a une philosophie derrière le concept même de «travailler avec la mémoire». Au bout de vos doigts, vous modifiez la charge sur les plaques de même très petits condensateurs.

Source: https://habr.com/ru/post/fr456318/


All Articles