C++

Comment utiliser les pointeurs C++

Comment utiliser les pointeurs C++
La mémoire d'un ordinateur est une longue série de cellules. La taille de chaque cellule est appelée un octet. Un octet est un espace occupé par un caractère anglais de l'alphabet. Un objet au sens ordinaire du terme est un ensemble consécutif d'octets en mémoire. Chaque cellule a une adresse, qui est un nombre entier, généralement écrit sous forme hexadécimale. Il existe trois manières d'accéder à un objet en mémoire. Un objet est accessible à l'aide de ce qu'on appelle un pointeur. Il est accessible en utilisant ce qu'on appelle une référence. Il est toujours accessible à l'aide d'un identifiant. Cet article se concentre sur l'utilisation de pointeurs et de références. En C++, il y a l'objet pointé et l'objet pointeur. L'objet pointé a l'objet d'intérêt. L'objet pointeur a l'adresse de l'objet pointé.

Vous devez avoir des connaissances de base en C++, y compris ses identifiants, fonctions et tableaux ; pour comprendre cet article.

L'objet pointeur et l'objet pointé, chacun a son identifiant.

L'adresse de l'opérateur, &

C'est un opérateur unaire. Lorsqu'il est suivi d'un identifiant, il renvoie l'adresse de l'objet de l'identifiant. Considérez la déclaration suivante :

int ptdInt;

Ci-dessous le code, l'expression suivante, renverra l'adresse identifiée par ptdInt :

&ptdEntier

Vous n'avez pas besoin de connaître l'adresse exacte (numéro) lorsque vous codez.

L'opérateur d'indirection, *

Il s'agit d'un opérateur unaire dans le contexte des pointeurs. Il est généralement tapé devant un identifiant. S'il est utilisé dans une déclaration de l'identifiant, alors l'identifiant est l'objet pointeur qui ne contient que l'adresse de l'objet pointé. S'il est utilisé devant l'identifiant de l'objet pointeur, pour retourner quelque chose, alors la chose retournée est la valeur de l'objet pointé.

Création d'un pointeur

Jetez un œil au segment de code suivant :

flotteur ptdFloat;
float *ptrFloat;
ptrFoat = &ptdFloat;

Le segment commence par la déclaration de l'objet pointé, ptdFloat. ptdFloat est un identifiant, qui identifie juste un objet flottant. Un objet réel (valeur) aurait pu lui être affecté, mais dans ce cas, rien ne lui a été affecté. Ensuite dans le segment, il y a la déclaration de l'objet pointeur. L'opérateur d'indirection devant cet identifiant signifie qu'il doit contenir l'adresse d'un objet pointé. Le type d'objet, float au début de l'instruction, signifie que l'objet pointé est un float. L'objet pointeur est toujours du même type que l'objet pointé. ptrFoat est un identifiant, qui identifie simplement un objet pointeur.

Dans la dernière instruction du code, l'adresse de l'objet pointé est affectée à l'objet pointeur. Notez l'utilisation de l'opérateur address-of, &.

La dernière déclaration (ligne) ci-dessus montre qu'après avoir déclaré l'objet pointeur sans initialisation, vous n'avez pas besoin de l'opérateur d'indirection, lorsque vous devez l'initialiser. En fait, c'est une erreur de syntaxe d'utiliser l'opérateur d'indirection dans la troisième (dernière) ligne.

L'objet pointeur peut être déclaré et initialisé par l'objet pointé dans une instruction, comme suit :

flotteur ptdFloat;
float *ptrFoat = &ptdFloat;

La première ligne du segment de code précédent et celui-ci, sont les mêmes. Les deuxième et troisième lignes du segment de code précédent ont été combinées en une seule instruction ici.

Notez dans le code ci-dessus que lors de la déclaration et de l'initialisation de l'objet pointeur, l'opérateur d'indirection doit être utilisé. Cependant, il n'est pas utilisé si l'initialisation doit être effectuée par la suite. L'objet pointeur est initialisé avec l'adresse de l'objet pointé.

Dans le segment de code suivant, l'opérateur d'indirection est utilisé pour renvoyer le contenu de l'objet pointé.

int ptdInt = 5;
entier *ptrInt = &ptdInt;
cout << *ptrInt << '\n';

La sortie est de 5.

Dans la dernière instruction ici, l'opérateur d'indirection a été utilisé pour renvoyer la valeur pointée, par l'identifiant du pointeur. Ainsi, lorsqu'il est utilisé dans une déclaration, l'identifiant de l'opérateur d'indirection contiendrait l'adresse de l'objet pointé. Lorsqu'il est utilisé dans une expression de retour, en combinaison avec l'identifiant du pointeur, l'opérateur d'indirection renvoie la valeur de l'objet pointé.

Attribution de zéro à un pointeur

L'objet pointeur doit toujours avoir le type de l'objet pointé. Lors de la déclaration de l'objet pointeur, le type de données de l'objet pointé doit être utilisé. Cependant, la valeur du zéro décimal peut être affectée au pointeur comme dans le segment de code suivant :

int ptdInt = 5;
int *ptrInt;
ptrInt = 0 ;
ou dans le segment,
int ptdInt = 5;
entier *ptrInt = 0;

Dans les deux cas, le pointeur (identifiant) est appelé pointeur nul ; sens, il ne pointe nulle part. C'est-à-dire qu'il n'a l'adresse d'aucun objet pointé. Ici, 0 est un zéro décimal et non un zéro hexadécimal. Le zéro hexadécimal pointerait vers la première adresse de la mémoire de l'ordinateur.

N'essayez pas d'obtenir la valeur pointée par un pointeur nul. Si vous essayez cela, le programme peut compiler, mais peut ne pas s'exécuter.

Nom du tableau en tant que pointeur constant

Considérez le tableau suivant :

int arr[] = 000, 100, 200, 300, 400 ;

Le nom du tableau, arr est en fait l'identifiant qui a l'adresse du premier élément du tableau. L'expression suivante renvoie la première valeur du tableau :

*arr

Avec le tableau, l'opérateur d'incrémentation, ++ se comporte différemment. Au lieu d'ajouter 1, il remplace l'adresse du pointeur par l'adresse de l'élément suivant dans le tableau. Cependant, le nom du tableau est un pointeur constant ; ce qui signifie que son contenu (adresse) ne peut pas être modifié ou incrémenté. Ainsi, pour incrémenter, l'adresse de début du tableau doit être affectée à un pointeur non constant comme suit :

entier *ptr = arr;

Maintenant, ptr peut être incrémenté pour pointer vers l'élément suivant du tableau. ptr a été déclaré ici en tant qu'objet pointeur. Sans * ici, ce ne serait pas un pointeur ; ce serait un identifiant pour contenir un objet int et non pour contenir une adresse mémoire.

Le segment de code suivant pointe enfin vers le quatrième élément :

++ptr;
++ptr;
++ptr;

Le code suivant renvoie la quatrième valeur du tableau :

int arr[] = 000, 100, 200, 300, 400 ;
entier *ptr = arr;
++ptr;
++ptr;
++ptr;
cout << *ptr << '\n';

La sortie est de 300.

Nom de la fonction comme identifiant

Le nom d'une fonction est l'identifiant de la fonction. Considérez la définition de fonction suivante :

entier fn()

cout << "seen" << '\n';
retour 4 ;

fn est l'identifiant de la fonction. L'expression,

&fn

renvoie l'adresse de la fonction en mémoire. fn est comme l'objet pointu. La déclaration suivante déclare un pointeur vers une fonction :

int (*func)();

L'identifiant de l'objet pointé et l'identifiant de l'objet pointeur sont différents. func est un pointeur vers une fonction. fn est l'identifiant d'une fonction. Et donc, func peut être fait pour pointer vers fn comme suit :

fonction = &fn;

La valeur (contenu) de func est l'adresse de fn. Les deux identifiants auraient pu être liés à une instruction d'initialisation comme suit :

entier (*func)() = &fn;

Notez les différences et les similitudes dans la gestion des pointeurs de fonction et des pointeurs scalaires. func est un pointeur vers une fonction ; c'est l'objet pointu ; il est déclaré différemment d'un pointeur scalaire.

La fonction peut être appelée avec,

fn()
ou alors
fonction()

Il ne peut pas être appelé avec *func().

Lorsque la fonction a des paramètres, les deuxièmes parenthèses ont les types des paramètres et n'ont pas besoin d'avoir les identifiants des paramètres. Le programme suivant illustre cela :

#inclure
en utilisant l'espace de noms std ;
float fn(float fl, int in)

retour fl;

int main()

float (*func)(float, int) = &fn;
float val = func(2.5, 6);
cout << val << '\n';
renvoie 0 ;

La sortie est 2.5.

Référence C++

Le référencement en C++ n'est qu'un moyen de produire un synonyme (un autre nom) pour un identifiant. Il utilise l'opérateur &, mais pas de la même manière que & est utilisé pour les pointeurs. Considérez le segment de code suivant :

int monInt = 8;
entier &votreInt = monInt;
cout << myInt << '\n';
cout << yourInt << '\n';

La sortie est :

8
8

La première instruction initialise l'identifiant myInt ; je.e. myInt est déclaré et fait pour contenir la valeur, 8. La deuxième instruction crée un nouvel identifiant, yourInt un synonyme de myInt. Pour ce faire, l'opérateur & est placé entre le type de données et le nouvel identifiant dans la déclaration. Les instructions cout montrent que les deux identifiants sont synonymes. Pour renvoyer la valeur dans ce cas, vous n'avez pas besoin de la faire précéder de * . Utilisez simplement l'identifiant.

myInt et yourInt ici, ne sont pas deux objets différents. Ce sont deux identifiants différents référençant (identifiant) le même emplacement en mémoire ayant la valeur, 8. Si la valeur de myInt est modifiée, la valeur de yourInt changera également automatiquement. Si la valeur de yourInt est modifiée, la valeur de myInt changera également automatiquement.

Les références sont du même type.

Référence à une fonction

Tout comme vous pouvez avoir une référence à un scalaire, vous pouvez également avoir une référence à une fonction. Cependant, coder une référence à une fonction est différent de coder une référence à un scalaire. Le programme suivant illustre cela :

#inclure
en utilisant l'espace de noms std ;
float fn(float fl, int in)

retour fl;

int main()

float (&func)(float, int) = fn;
float val = func(2.5, 6);
cout << val << '\n';
renvoie 0 ;

La sortie est 2.5.

Notez la première instruction dans la fonction principale, qui fait de func un synonyme de fn. Les deux font référence à la même fonction. Notez l'usage unique et la position de &. Donc & est l'opérateur de référence ici et non l'opérateur d'adresse de. Pour appeler la fonction, utilisez simplement l'un des noms.

Un identifiant de référence n'est pas la même chose qu'un identifiant de pointeur.

Fonction retournant un pointeur

Dans le programme suivant, la fonction renvoie un pointeur, qui est l'adresse de l'objet pointé :

#inclure
en utilisant l'espace de noms std ;
float *fn(float fl, int in)

flotteur *fll = &fl;
retour fll;

int main()

float *val = fn(2.5, 6);
cout << *val << '\n';
renvoie 0 ;

La sortie est 2.5

La première instruction de la fonction, fn() est juste là pour créer un objet pointeur. Notez l'usage unique et la position de * dans la signature de la fonction. Notez également comment le pointeur (adresse) a été reçu dans la fonction main() par un autre objet pointeur.

Fonction retournant une référence

Dans le programme suivant, la fonction renvoie une référence :

#inclure
en utilisant l'espace de noms std ;
float &fn(float fl, int in)

flotteur &frr = fl;
retour frr;

int main()

float &val = fn(2.5, 6);
cout << val << '\n';
renvoie 0 ;

La sortie est 2.5.

La première instruction de la fonction, fn() est là juste pour créer une référence. Notez l'usage unique et la position de & dans la signature de la fonction. Notez également comment la référence a été reçue dans la fonction main() par une autre référence.

Passer un pointeur vers une fonction

Dans le programme suivant, un pointeur, qui est en fait l'adresse d'un objet pointé flottant, est envoyé en argument à la fonction :

#inclure
en utilisant l'espace de noms std ;
float fn(float * fl, int in)

retour *fl;

int main()

flotteur v = 2.5 ;
float val = fn(&v, 6);
cout << val << '\n';
renvoie 0 ;

La sortie est 2.5

Notez l'utilisation et la position de * pour le paramètre float dans la signature de la fonction. Dès que l'évaluation de la fonction fn() démarre, l'instruction suivante est faite :

flottant *fl = &v;

fl et &v pointent tous les deux vers le même objet pointu qui contient 2.5. *fl à l'instruction return n'est pas une déclaration ; cela signifie, la valeur de l'objet pointé pointé par l'objet pointeur.

Passer une référence à une fonction

Dans le programme suivant, une référence est envoyée en argument à la fonction :

#inclure
en utilisant l'espace de noms std ;
float fn(float &fl, int in)

retour fl;

int main()

flotteur v = 2.5 ;
float val = fn(v, 6);
cout << val << '\n';
renvoie 0 ;

La sortie est 2.5

Notez l'utilisation et la position de & pour le paramètre float dans la signature de la fonction. Dès que l'évaluation de la fonction fn() démarre, l'instruction suivante est faite :

flottant &fl = v;

Passer un tableau à une fonction

Le programme suivant montre comment passer un tableau à une fonction :

#inclure
en utilisant l'espace de noms std ;
int fn(int arra[])

retour arra[2];

int main()

int arr[] = 000, 100, 200, 300, 400 ;
int val = fn(arr);
cout << val << '\n';
renvoie 0 ;

La sortie est de 200.

Dans ce programme, c'est le tableau qui est passé. Notez que le paramètre de la signature de fonction a une déclaration de tableau vide. L'argument dans l'appel de fonction n'est que le nom d'un tableau créé.

Une fonction C++ peut-elle renvoyer un tableau?

Une fonction en C++ peut renvoyer la valeur d'un tableau, mais ne peut pas renvoyer le tableau. La compilation du programme suivant génère un message d'erreur :

#inclure
en utilisant l'espace de noms std ;
int fn(int arra[])

retour arra;

int main()

int arr[] = 000, 100, 200, 300, 400 ;
int val = fn(arr);
renvoie 0 ;

Pointeur d'un pointeur

Un pointeur peut pointer vers un autre pointeur. C'est-à-dire qu'un objet pointeur peut avoir l'adresse d'un autre objet pointeur. Ils doivent toujours être du même type. Le segment de code suivant illustre cela :

int ptdInt = 5;
entier *ptrInt = &ptdInt;
entier **ptrptrInt = &ptrInt;
cout << **ptrptrInt << '\n';

La sortie est de 5.

Dans la déclaration de pointeur à pointeur, le double * est utilisé. Pour renvoyer la valeur de l'objet pointé final, le double * est toujours utilisé.

Tableau de pointeurs

Le programme suivant montre comment coder un tableau de pointeurs :

#inclure
en utilisant l'espace de noms std ;
int main()

entier num0=000, num1=100, num2=200, num3=300, num4=400;
entier *no0=&num0, *no1=&num1, *no2=&num2, *no3=&num3, *no4=&num4;
int *arr[] = no0, no1, no2, no3, no4 ;
cout << *arr[4] << '\n';
renvoie 0 ;

La sortie est :

400

Notez l'utilisation et la position de * dans la déclaration du tableau. Notez l'utilisation de * lors du retour d'une valeur dans le tableau. Avec des pointeurs de pointeurs, deux * sont impliqués. Dans le cas d'un tableau de pointeurs, un * a déjà été pris en compte, car l'identifiant du tableau est un pointeur.

Tableau de chaînes de longueur variable

Un littéral de chaîne est une constante qui renvoie un pointeur. Un tableau de chaînes de longueur variable est un tableau de pointeurs. Chaque valeur du tableau est un pointeur. Les pointeurs sont des adresses vers des emplacements de mémoire et sont de la même taille. Les chaînes de longueurs différentes sont ailleurs en mémoire, pas dans le tableau. Le programme suivant illustre l'utilisation :

#inclure
en utilisant l'espace de noms std ;
int main()

const char *arr[] = "femme", "garçon", "fille", "adulte";
cout << arr[2] << '\n';
renvoie 0 ;

La sortie est "fille".

La déclaration du tableau commence par le mot réservé, « const » pour constante ; suivi de « char » pour le caractère, puis de l'astérisque, * pour indiquer que chaque élément est un pointeur. Pour renvoyer une chaîne du tableau, * n'est pas utilisé, à cause de la nature implicite du pointeur de chaque chaîne. Si * est utilisé, alors le premier élément de la chaîne sera retourné.

Pointeur vers une fonction renvoyant un pointeur

Le programme suivant illustre le codage d'un pointeur vers une fonction renvoyant un pointeur :

#inclure
en utilisant l'espace de noms std ;
entier *fn()

nombre entier = 4 ;
entier *inter = #
retour inter;

int main()

entier *(*func)() = &fn;
int val = *func();
cout << val << '\n';
renvoie 0 ;

La sortie est de 4.

La déclaration d'un pointeur vers une fonction renvoyant un pointeur est similaire à la déclaration d'un pointeur vers une fonction ordinaire mais précédée d'un astérisque. La première instruction de la fonction main() illustre cela. Pour appeler la fonction à l'aide du pointeur, faites-la précéder de *.

Conclusion

Pour créer un pointeur vers un scalaire, faites quelque chose comme,

flotteur pointu;
float *pointeur = &pointed;

* a deux significations : dans une déclaration, il indique un pointeur ; pour retourner quelque chose, c'est pour la valeur de l'objet pointé.

Le nom du tableau est un pointeur constant vers le premier élément du tableau.

Pour créer un pointeur vers une fonction, vous pouvez faire,

entier (*func)() = &fn;

où fn() est une fonction définie ailleurs et func est le pointeur.

& a deux significations : dans une déclaration, il indique une référence (synonyme) au même objet qu'un autre identifiant ; lors du retour de quelque chose, cela signifie l'adresse de.

Pour créer une référence à une fonction, vous pouvez faire,

float (&refFunc)(float, int) = fn;

où fn() est une fonction définie ailleurs et refFunc est la référence.

Lorsqu'une fonction renvoie un pointeur, la valeur renvoyée doit être reçue par un pointeur. Lorsqu'une fonction renvoie une référence, la valeur renvoyée doit être reçue par une référence.

Lors du passage d'un pointeur vers une fonction, le paramètre est une déclaration, tandis que l'argument est l'adresse d'un objet pointé. Lors du passage d'une référence à une fonction, le paramètre est une déclaration, tandis que l'argument est la référence.

Lors du passage d'un tableau à une fonction, le paramètre est une déclaration tandis que l'argument est le nom du tableau sans []. La fonction C++ ne renvoie pas de tableau.

Un pointeur à pointeur a besoin de deux * au lieu d'un, le cas échéant.

Chrys

Le bouton de clic gauche de la souris ne fonctionne pas sous Windows 10
Si vous utilisez une souris dédiée avec votre ordinateur portable ou de bureau mais que le le clic gauche de la souris ne fonctionne pas sur Windows 1...
Le curseur saute ou se déplace de manière aléatoire lors de la saisie dans Windows 10
Si vous constatez que le curseur de votre souris saute ou se déplace tout seul, automatiquement, au hasard lors de la saisie sur un ordinateur portabl...
Comment inverser le sens de défilement de la souris et des pavés tactiles dans Windows 10
Souris et Pavé tactiles rendent non seulement l'informatique facile, mais plus efficace et moins chronophage. Nous ne pouvons pas imaginer une vie san...