Opérateurs liés aux pointeurs : permettent de prendre l’adresse des variables, de déréférencer des emplacements de stockage et d’accéder à des emplacements de la mémoire.
Les opérateurs liés aux pointeurs vous permettent de prendre l’adresse d’une variable (&
), de déréférencer un pointeur (*
), de comparer les valeurs des pointeurs, et d’ajouter ou de soustraire des pointeurs et des entiers.
Vous utilisez les opérateurs suivants avec les pointeurs :
- Opérateur unaire
&
(address-of) : pour obtenir l’adresse d’une variable - Opérateur unaire
*
(indirection du pointeur) : pour obtenir la variable pointée par un pointeur - Opérateurs
->
(accès aux membres) et[]
(accès aux éléments) - Opérateurs arithmétiques
+
,-
,++
et--
- Opérateurs de comparaison
==
,!=
,<
,>
,<=
et>=
Pour plus d’informations sur les types de pointeurs, consultez Types pointeur.
Notes
Toutes les opérations impliquant des pointeurs nécessitent un contexte unsafe. Le code qui contient des blocs unsafe doit être compilé avec l’option de compilateur AllowUnsafeBlocks.
Opérateur adresse de &
L’opérateur unaire &
retourne l’adresse de son opérande :
unsafe
{
int number = 27;
int* pointerToNumber = &number;
Console.WriteLine($"Value of the variable: {number}");
Console.WriteLine($"Address of the variable: {(long)pointerToNumber:X}");
}
// Output is similar to:
// Value of the variable: 27
// Address of the variable: 6C1457DBD4
L’opérande de l’opérateur &
doit être une variable fixe. Les variables fixes se trouvent dans des emplacements de stockage qui ne sont pas affectés par le récupérateur de mémoire. Dans l’exemple précédent, la variable locale number
est une variable fixe, car elle se trouve dans la pile. Les variables qui se trouvent dans des emplacements de stockage pouvant être affectés par le récupérateur de mémoire (par exemple, en étant déplacés) sont appelées variables déplaçables. Les champs d’objet et les éléments de tableau sont des exemples de variables déplaçables. Vous pouvez obtenir l’adresse d’une variable déplaçable en la fixant (ou en l’épinglant) à l’aide d’une instruction fixed
. L’adresse obtenue est uniquement valide à l’intérieur du bloc d’une instruction fixed
. L’exemple suivant montre comment utiliser une instruction fixed
et l’opérateur &
:
unsafe
{
byte[] bytes = { 1, 2, 3 };
fixed (byte* pointerToFirst = &bytes[0])
{
// The address stored in pointerToFirst
// is valid only inside this fixed statement block.
}
}
Vous ne pouvez pas obtenir l’adresse d’une constante ou d’une valeur.
Pour plus d’informations sur les variables fixes et déplaçables, consultez la section Variables fixes et déplaçables de la spécification du langage C#.
L’opérateur binaire &
calcule la logique AND de ses opérandes booléens, ou la logique AND au niveau du bit de ses opérandes de type intégral.
Opérateur d’indirection de pointeur *
L’opérateur unaire d’indirection de pointeur *
permet d’obtenir la variable vers laquelle pointe son opérande. Il est également appelé « opérateur de déréférence ». L’opérande de l’opérateur *
doit être un type de pointeur.
unsafe
{
char letter = 'A';
char* pointerToLetter = &letter;
Console.WriteLine($"Value of the `letter` variable: {letter}");
Console.WriteLine($"Address of the `letter` variable: {(long)pointerToLetter:X}");
*pointerToLetter = 'Z';
Console.WriteLine($"Value of the `letter` variable after update: {letter}");
}
// Output is similar to:
// Value of the `letter` variable: A
// Address of the `letter` variable: DCB977DDF4
// Value of the `letter` variable after update: Z
Vous ne pouvez pas appliquer l’opérateur *
à une expression de type void*
.
L’opérateur binaire *
calcule le produit de ses opérandes numériques.
Opérateur d’accès aux membres de pointeur ->
L’opérateur ->
associe l’indirection de pointeur à l’accès aux membres. C’est-à-dire que si x
est un pointeur de type T*
et que y
est un membre accessible de T
, une expression au format
x->y
équivaut à :
(*x).y
L’exemple suivant illustre l’utilisation de l’opérateur ->
:
public struct Coords
{
public int X;
public int Y;
public override string ToString() => $"({X}, {Y})";
}
public class PointerMemberAccessExample
{
public static unsafe void Main()
{
Coords coords;
Coords* p = &coords;
p->X = 3;
p->Y = 4;
Console.WriteLine(p->ToString()); // output: (3, 4)
}
}
Vous ne pouvez pas appliquer l’opérateur ->
à une expression de type void*
.
Opérateur d’accès aux éléments de pointeur []
Pour une expression p
d’un type pointeur, l’accès à un élément de pointeur au format p[n]
est évalué comme *(p + n)
, où n
doit être d’un type implicitement convertible en int
, uint
, long
ou ulong
. Pour plus d’informations sur le comportement de l’opérateur +
avec les pointeurs, consultez la section Addition ou soustraction d’une valeur intégrale dans un pointeur.
L’exemple suivant montre comment accéder à des éléments tableau avec un pointeur et l’opérateur []
:
unsafe
{
char* pointerToChars = stackalloc char[123];
for (int i = 65; i < 123; i++)
{
pointerToChars[i] = (char)i;
}
Console.Write("Uppercase letters: ");
for (int i = 65; i < 91; i++)
{
Console.Write(pointerToChars[i]);
}
}
// Output:
// Uppercase letters: ABCDEFGHIJKLMNOPQRSTUVWXYZ
Dans l’exemple précédent, une expression stackalloc
alloue un bloc de mémoire sur la pile.
Notes
L’opérateur d’accès aux éléments de pointeur ne recherche pas les erreurs de dépassement des limites.
Vous ne pouvez pas utiliser []
pour l’accès aux éléments de pointeur avec une expression de type void*
.
Vous pouvez également utiliser l’opérateur []
pour l’accès aux éléments de tableau ou à l’indexeur.
Opérateurs arithmétiques de pointeur
Vous pouvez effectuer les opérations arithmétiques suivantes avec des pointeurs :
- Ajouter ou soustraire une valeur intégrale dans un pointeur
- Soustraire deux pointeurs
- Incrémenter ou décrémenter un pointeur
Vous ne pouvez pas effectuer ces opérations avec des pointeurs de type void*
.
Pour plus d’informations sur les opérations arithmétiques prises en charge avec les types numériques, consultez Opérateurs arithmétiques.
Ajout ou soustraction d’une valeur intégrale dans un pointeur
Pour un pointeur p
de type T*
et une expression n
d’un type implicitement convertible en int
, uint
, long
ou ulong
, l’addition et la soustraction sont définies de la façon suivante :
- Les expressions
p + n
etn + p
produisent un pointeur de typeT*
qui est obtenu en ajoutantn * sizeof(T)
à l’adresse fournie parp
. - L’expression
p - n
produit un pointeur de typeT*
qui est obtenu en soustrayantn * sizeof(T)
de l’adresse fournie parp
.
L’opérateur sizeof
permet d’obtenir la taille d’un type en octets.
L’exemple suivant illustre l’utilisation de l’opérateur +
avec un pointeur :
unsafe
{
const int Count = 3;
int[] numbers = new int[Count] { 10, 20, 30 };
fixed (int* pointerToFirst = &numbers[0])
{
int* pointerToLast = pointerToFirst + (Count - 1);
Console.WriteLine($"Value {*pointerToFirst} at address {(long)pointerToFirst}");
Console.WriteLine($"Value {*pointerToLast} at address {(long)pointerToLast}");
}
}
// Output is similar to:
// Value 10 at address 1818345918136
// Value 30 at address 1818345918144
Soustraction de pointeur
Pour deux pointeurs p1
et p2
de type T*
, l’expression p1 - p2
produit la différence entre les adresses fournies par p1
et p2
, divisée par sizeof(T)
. Le type du résultat est long
. C’est -à-dire que p1 - p2
est calculé en tant que ((long)(p1) - (long)(p2)) / sizeof(T)
.
L’exemple suivant montre la soustraction d’un pointeur :
unsafe
{
int* numbers = stackalloc int[] { 0, 1, 2, 3, 4, 5 };
int* p1 = &numbers[1];
int* p2 = &numbers[5];
Console.WriteLine(p2 - p1); // output: 4
}
Incrémenter et décrémenter des pointeurs
L’opérateur d’incrémentation ++
ajoute 1 à son opérande de pointeur. L’opérateur de décrémentation --
soustrait 1 de son opérande de pointeur.
Les deux opérateurs sont pris en charge sous deux formes : suffixée (p++
et p--
) et préfixée (++p
et --p
). Le résultat de p++
et p--
est la valeur de p
avant l’opération. Le résultat de ++p
et --p
est la valeur de p
après l’opération.
L’exemple suivant montre le comportement des opérateurs d’incrémentation suffixés et préfixés :
unsafe
{
int* numbers = stackalloc int[] { 0, 1, 2 };
int* p1 = &numbers[0];
int* p2 = p1;
Console.WriteLine($"Before operation: p1 - {(long)p1}, p2 - {(long)p2}");
Console.WriteLine($"Postfix increment of p1: {(long)(p1++)}");
Console.WriteLine($"Prefix increment of p2: {(long)(++p2)}");
Console.WriteLine($"After operation: p1 - {(long)p1}, p2 - {(long)p2}");
}
// Output is similar to
// Before operation: p1 - 816489946512, p2 - 816489946512
// Postfix increment of p1: 816489946512
// Prefix increment of p2: 816489946516
// After operation: p1 - 816489946516, p2 - 816489946516
Opérateurs de comparaison de pointeur
Vous pouvez utiliser les opérateurs ==
, !=
, <
, >
, <=
et >=
pour comparer des opérandes de tout type de pointeur, y compris void*
. Ces opérateurs comparent les adresses fournies par les deux opérandes comme s’il s’agissait d’entiers non signés.
Pour plus d’informations sur le comportement de ces opérateurs pour les opérandes d’autres types, consultez les articles Opérateurs d’égalité et Opérateurs de comparaison.
Priorité des opérateurs
La liste suivante présente les opérateurs relatifs aux pointeurs par ordre de précédence, de la plus élevée à la plus basse :
- Opérateurs suffixés d’incrémentation
x++
et de décrémentationx--
, ainsi que les opérateurs->
et[]
- Opérateurs préfixés d’incrémentation
++x
et de décrémentation--x
, ainsi que les opérateurs&
et*
- Opérateurs additifs
+
et-
- Opérateurs de comparaison
<
,>
,<=
et>=
- Opérateurs d’égalité
==
et!=
Utilisez des parenthèses (()
) pour modifier l’ordre d’évaluation imposé par la précédence des opérateurs.
Pour obtenir la liste complète des opérateurs C# classés par niveau de priorité, consultez la section Priorité des opérateurs de l’article Opérateurs C#.
Capacité de surcharge de l’opérateur
Un type défini par l’utilisateur ne peut pas surcharger les opérateurs liés aux pointeurs &
, *
, ->
et []
.
spécification du langage C#
Pour plus d’informations, consultez les sections suivantes de la spécification du langage C# :
- Variables fixes et déplaçables
- address-of, opérateur
- Indirection de pointeur
- Accès aux membres de pointeur
- Accès aux éléments de pointeur
- Arithmétique des pointeurs
- Incrémentation et décrémentation des pointeurs
- Comparaison de pointeurs