Ескертпе
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Жүйеге кіруді немесе каталогтарды өзгертуді байқап көруге болады.
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Каталогтарды өзгертуді байқап көруге болады.
Операторы указателя позволяют принимать адрес переменной (), разыменовывать указатель (&*), сравнивать значения указателя и добавлять или вычитать указатели и целые числа.
Справочные документы по языку C# описывают последнюю выпущенную версию языка C#. Она также содержит начальную документацию по функциям в общедоступных предварительных версиях для предстоящего языкового выпуска.
Документация определяет любую функцию, впервые представленную в последних трех версиях языка или в текущих общедоступных предварительных версиях.
Подсказка
Чтобы узнать, когда функция впервые появилась в C#, ознакомьтесь со статьей об истории версий языка C#.
Используйте следующие операторы для работы с указателями:
- Унарный оператор
&(address-of): для получения адреса переменной - Унарный
*(косвенный оператор указателя): чтобы получить переменную, на которую указывает указатель - Операторы
->(доступ к членам) и[](доступ к элементам) - Арифметические операторы
+,-,++и-- - Операторы сравнения
==,!=,<,>,<=и>=
Сведения о типах указателей см. в разделе Типы указателей.
Примечание.
Для всех операций с указателями требуется небезопасный контекст. Необходимо скомпилировать код, содержащий небезопасные блоки с параметром компилятора AllowUnsafeBlocks .
Оператор address-of >
Унарный оператор & возвращает адрес своего операнда:
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
Операнд оператора & должен быть фиксированной переменной.
Фиксированные переменные — это переменные, которые находятся в местах хранения сборщика мусора , не влияют. В предыдущем примере локальная переменная является фиксированной переменной number , так как она находится в стеке. Переменные, которые находятся в местах хранения сборщика мусора, могут повлиять (например, перемещение) называются перемещаемыми переменными. Поля объекта и элементы массива являются примерами перемещаемых переменных. Вы можете получить адрес перемещаемой переменной, если вы "исправите" или "закрепить", с помощью инструкцииfixed. Полученный адрес действителен только в пределах блока инструкции fixed. В следующем примере показано, как использовать инструкцию fixed и оператор &:
unsafe
{
byte[] bytes = { 1, 2, 3 };
fixed (byte* pointerToFirst = &bytes[0])
{
// The address stored in pointerToFirst
// is valid only inside this fixed statement block.
}
}
Получить адрес константы или значения нельзя.
Дополнительные сведения о фиксированных и перемещаемых переменных см. в разделе Фиксированные и перемещаемые переменные в спецификации языка C#.
Бинарный оператор & вычисляет логическое И своих логических операндов или побитовое логическое И своих целочисленных операндов.
Оператор косвенного обращения указателя *
Унарный оператор * косвенного указателя обращается к переменной, к которой обращаются его операнды. Он также называется оператором разыменования. Операнд оператора * должен иметь тип указателя.
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
Оператор нельзя применить * к выражению типа void*.
Бинарный оператор * вычисляет продукт своих числовых операндов.
Оператор доступа к элементу указателя ->
Оператор -> объединяет косвенное обращение к указателю и доступ к члену. Если x указатель типа и T* является доступным элементом типа yT, выражение формы
x->y
эквивалентно правилу
(*x).y
В следующем примере иллюстрируется использование оператора ->.
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)
}
}
Оператор нельзя использовать -> для выражения типа void*.
Оператор доступа к элементу указателя []
Для выражения p типа указателя доступ к элементу указателя формы p[n] оценивается как *(p + n). Значение n должно иметь тип, неявно преобразуемый в int, uintили longulong. Сведения о поведении оператора + с указателями см. в разделе Сложение целочисленного значения с указателем или его вычитание из указателя.
В следующем примере показано, как получить доступ к элементам массива с помощью указателя и [] оператора:
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
В предыдущем примере выражение stackalloc выделяет блок памяти в стеке.
Примечание.
Оператор доступа к элементу указателя не проверяет ошибки за пределами области.
Невозможно использовать [] для доступа к элементу указателя с выражением типа void*.
Можно также использовать оператор [] для доступа к элементу массива или индексатору.
Арифметические операторы указателя
Вы можете выполнить следующие арифметические операции с указателями:
- Сложение целочисленного значения с указателем или его вычитание из указателя
- Вычитание двух указателей
- Инкремент или декремент указателя
Эти операции нельзя выполнять с указателями типа void*.
Сведения о поддерживаемых арифметических операциях с помощью числовых типов см. в разделе арифметические операторы.
Сложение целочисленного значения с указателем или его вычитание из указателя
Для указателя p типа и выражения T* типа n неявно преобразуемого в int, uintlongили ulong, добавление и вычитание работают следующим образом:
- Оба
p + nиn + pдают указатель типаT*. Вы получите этот указатель, добавивn * sizeof(T)в адрес, на которыйpуказывает. - Выражение
p - nдает указатель типаT*. Этот указатель вычитаетсяn * sizeof(T)из адреса, на которыйpуказывает.
Оператор sizeof получает размер типа в байтах.
В следующем примере показано, как использовать + оператор с указателем:
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
Вычитание указателей
Для двух указателей p1 и p2 типов T*выражение p1 - p2 дает разницу между адресами, на которые p1 и p2 указывают, разделенные на sizeof(T). Результат имеет тип long. Другими словами, p1 - p2 вычисляется как ((long)(p1) - (long)(p2)) / sizeof(T).
В следующем примере показана вычитание указателя:
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
}
Инкремент и декремент указателя
Оператор инкремента ++добавляет 1 к своему операнду указателя. Оператор декремента --вычитает 1 из своего операнда указателя.
Оба оператора поддерживают две формы: постфикс (p++ и) и p--префикс (++p и --p). Результат p++ и p-- — это значение pперед операцией. Результат ++p и --p — это значение pпосле операции.
В следующем примере показано поведение постфиксных и префиксных операторов инкремента:
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
Операторы сравнения указателей
Вы можете использовать операторы ==, !=, <, >, <= и >= для сравнения операндов любого типа указателя, включая void*. Эти операторы сравнивают адреса, заданные двумя операндами, как если бы они не были назначены целыми числами.
Сведения о поведении этих операторов для операндов других типов см. в статьях Операторы равенства и Операторы сравнения.
Приоритет операторов
Следующие операторы списков указывают на связанные операторы в группах, начиная с самого высокого приоритета до наименьшего:
- (первичные) операторы: добавочные
x++и декрементныеx--операторы, а также->операторы и[]операторы. -
Унарные операторы: операторы добавочного
++xи уменьшения префикса,--xа также операторы адресного и косвенного&выражения*. - (Аддитивные) операторы: двоичные
+и-операторы. - (Реляционные и типо-тестирование) операторы: сравнение
<,>,<=и>=операторы. - Операторы равенства:
==и!=операторы.
Используйте скобки (), чтобы изменить порядок вычисления, накладываемый приоритетом операторов.
Полный список операторов C#, упорядоченный по уровню приоритета, можно найти в разделе Приоритет операторов статьи Операторы C#.
Возможность перегрузки оператора
Невозможно перегрузить операторы&, связанные с указателем, *->и [] в определяемом пользователем типе.
Спецификация языка C#
Дополнительные сведения см. в следующих разделах статьи Спецификация языка C#:
- Фиксированные и перемещаемые переменные
- Оператор address-of
- Косвенное обращение к указателю
- Доступ к членам указателей
- Доступ к элементам указателей
- Расчеты указателей
- Инкремент и декремент указателя
- Сравнение указателей