Mutatóval kapcsolatos operátorok – a változók címe, a dereferencia tárolási helyei és a memóriahelyek elérése
A mutató operátorai lehetővé teszik a változók címét (&
), a mutató elhalasztását (*
), a mutatóértékek összehasonlítását, valamint a mutatók és egész számok hozzáadását vagy kivonását.
A következő operátorokkal dolgozhat a mutatókkal:
- Unary
&
(address-of) operátor: egy változó címének lekéréséhez - Unary
*
(pointer indirection) operátor: a mutató által mutatott változó lekérése - A
->
(taghozzáférés) és[]
(elemhozzáférés) operátorok - Számtani operátorok
+
,-
,++
és--
- Összehasonlító operátorok
==
,!=
,<
,>
,<=
és>=
A mutatótípusokról további információt a Mutatótípusok című témakörben talál.
Feljegyzés
A mutatókkal végzett műveletekhez nem biztonságos környezet szükséges. A nem biztonságos blokkokat tartalmazó kódot az AllowUnsafeBlocks fordítóbeállítással kell lefordítani.
Operátor címe >
A unary &
operátor az operandus címét adja vissza:
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
Az operátor operandusának &
rögzített változónak kell lennie. A rögzített változók olyan változók, amelyek olyan tárolóhelyeken találhatók, amelyeket a szemétgyűjtő működése nem érint. Az előző példában a helyi változó number
rögzített változó, mert a veremen található. A szemétgyűjtő által érinthető (például áthelyezett) tárolóhelyeken található változókat mozgatható változóknak nevezzük. Az objektummezők és a tömbelemek ingó változókra mutatnak példákat. Egy ingó változó címét lekérheti, ha "kijavítja", vagy "kitűzi" egy fixed
utasítással. A kapott cím csak az utasításblokkon fixed
belül érvényes. Az alábbi példa egy utasítás és az &
operátor használatát fixed
mutatja be:
unsafe
{
byte[] bytes = { 1, 2, 3 };
fixed (byte* pointerToFirst = &bytes[0])
{
// The address stored in pointerToFirst
// is valid only inside this fixed statement block.
}
}
Állandó vagy érték címét nem lehet lekérni.
A rögzített és mozgatható változókkal kapcsolatos további információkért lásd a C# nyelvspecifikáció Rögzített és mozgatható változók szakaszát.
A bináris &
operátor kiszámítja a logikai és logikai operandusok és a bitenkénti logikai ÉS az integrál operandusok logikai ÉS logikai számításait.
Mutató indirekt operátora *
A nem mutató indirekt operátor *
beolvasja azt a változót, amelyre az operandusa rámutat. Dereference operátornak is nevezik. Az operátor operandusának *
mutató típusúnak kell lennie.
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
Az operátor nem alkalmazható *
típuskifejezésre void*
.
A bináris *
operátor kiszámítja a numerikus operandusok szorzatát .
Mutatótag-hozzáférési operátor –>
Az ->
operátor egyesíti a mutató indirekt ésa tagok hozzáférését. Vagyis ha x
egy mutató típusú T*
, és y
a típus T
akadálymentes tagja, akkor az űrlap kifejezése
x->y
egyenértékű a
(*x).y
Az alábbi példa az operátor használatát ->
mutatja be:
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)
}
}
Az operátor nem alkalmazható ->
típuskifejezésre void*
.
Mutatóelem-hozzáférési operátor []
Egy mutató típusú kifejezés p
esetében az űrlap p[n]
mutatóelem-hozzáférését a rendszer a következőképpen értékeli ki*(p + n)
, ahol n
implicit módon átalakíthatónak int
kell lennie , uint
long
vagy ulong
. A mutatókkal rendelkező operátor viselkedésével +
kapcsolatos információkért tekintse meg az integrálértékek összeadását vagy kivonását egy mutatószakaszba vagy abból.
Az alábbi példa bemutatja, hogyan érheti el a tömbelemeket egy mutatóval és az []
operátorral:
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
Az előző példában egy stackalloc
kifejezés lefoglal egy memóriablokkot a veremen.
Feljegyzés
A mutatóelem hozzáférési operátora nem ellenőrzi a határtalan hibákat.
Nem használható []
mutatóelem-hozzáféréshez típuskifejezéssel void*
.
Az operátort []
tömbelemhez vagy indexelőhöz is használhatja.
Mutató aritmetikai operátorai
A következő aritmetikai műveleteket hajthatja végre mutatókkal:
- Integrálérték hozzáadása vagy kivonása mutatóhoz vagy mutatóból
- Két mutató kivonása
- Mutató növelése vagy csökkentése
Ezeket a műveleteket nem lehet ilyen típusú void*
mutatókkal végrehajtani.
A numerikus típusokkal végzett támogatott aritmetikai műveletekről további információt az Aritmetikai operátorok című témakörben talál.
Egy integrálérték hozzáadása vagy kivonása egy mutatóhoz vagy abból
Egy típusmutató p
T*
és egy implicit módon átalakítható int
típus kifejezése n
esetén az uint
long
ulong
összeadás és kivonás az alábbiak szerint van definiálva:
- Mind a
n + p
kifejezések, mindp + n
a kifejezések olyan típusúT*
mutatót hoznak létre, amely a megadottp
címhez való hozzáadásbóln * sizeof(T)
ered. - A
p - n
kifejezés olyan típusúT*
mutatótn * sizeof(T)
hoz létre, amely a megadott címbőlp
való kivonásból ered.
Az sizeof
operátor bájtban szerzi be egy típus méretét.
Az alábbi példa egy mutatóval szemlélteti az +
operátor használatát:
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
Mutató kivonása
Két mutató p1
és p2
típus T*
esetén a kifejezés p1 - p2
a megadott és p2
a osztva sizeof(T)
megadott címek p1
közötti különbséget hozza létre. Az eredmény típusa: long
. Vagyis p1 - p2
a számítás a ((long)(p1) - (long)(p2)) / sizeof(T)
következőképpen történik: .
Az alábbi példa a mutató kivonását mutatja be:
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
}
Mutató növekménye és csökkentése
A ++
növekmény operátor 1-et ad hozzá a mutató operandusához. A --
decrement operátor kivon 1-et a mutató operandusából.
Mindkét operátor két formában támogatott: postfix (p++
és p--
) és előtag (++p
és --p
). A művelet eredménye p++
és p--
értékep
. A művelet eredménye ++p
és --p
értékep
.
Az alábbi példa a postfix és az előtag növekményes operátorainak viselkedését mutatja be:
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
Mutató-összehasonlító operátorok
A ==
, , !=
, <
<=
>
, és >=
operátorokkal bármilyen mutatótípusú operandusokat összehasonlíthat, beleértve a elemet is.void*
Ezek az operátorok úgy hasonlítják össze a két operandus által megadott címeket, mintha alá nem írt egész számok lennének.
Az operátorok más típusú operandusok viselkedéséről az Egyenlőség operátorok és az Összehasonlító operátorok című cikkekben olvashat bővebben.
Operátorok műveleti sorrendje
Az alábbi lista a mutatóval kapcsolatos operátorokat a legmagasabb prioritástól a legalacsonyabbig rendeli:
- A postfix növekményes
x++
és decrementx--
operátorai, valamint az és[]
az->
operátorok - Az előtag növekményes
++x
és decrement--x
operátorai, valamint az és*
az&
operátorok - Additív
+
és-
operátorok - Összehasonlítás
<
,>
,<=
és>=
operátorok - Egyenlőség
==
és!=
operátorok
Zárójelek ()
használatával módosíthatja az operátorok elsőbbsége által előírt kiértékelési sorrendet.
A C#-operátorok elsőbbségi szint szerint rendezett teljes listájáért tekintse meg a C# operátorok cikkének Operátorok elsőbbsége című szakaszát.
Operátorok túlterhelése
A felhasználó által definiált típus nem terhelheti túl a mutatóval kapcsolatos operátorokat &
, *
és ->
[]
.
C# nyelvspecifikáció
További információt a C# nyelvspecifikációjának alábbi szakaszaiban talál:
- Rögzített és áthelyezhető változók
- Az operátor címe
- Mutató indirekt
- Mutatótag-hozzáférés
- Mutatóelem-hozzáférés
- Mutató aritmetikai
- Mutató növekménye és csökkentése
- Mutató összehasonlítása
Lásd még
Visszajelzés
https://aka.ms/ContentUserFeedback.
Hamarosan elérhető: 2024-ben fokozatosan kivezetjük a GitHub-problémákat a tartalom visszajelzési mechanizmusaként, és lecseréljük egy új visszajelzési rendszerre. További információ:Visszajelzés küldése és megtekintése a következőhöz: