объявляется указатель р типа int и переменная q типа int. Это равнозначно двум следующим объявлениям. int* р; int q;
А в C# знак * является разделительным, и поэтому в объявлении int* р, q;
создаются две переменные-указателя. Это равнозначно двум следующим объявлениям. int* р; int* q;
Это главное отличие следует иметь в виду при переносе кода C/C++ на С#. Операторы * и & в указателях
В указателях применяются два оператора: * и &. Оператор & является унарным и возвращает адрес памяти своего операнда. (Напомним, что для унарного оператора требуется единственный операнд.) Например, в следующем фрагменте кода: int* ip; int num = 10; ip = #
в переменной ip сохраняется адрес памяти переменной num. Это адрес расположения переменной num в оперативной памяти компьютера. Он не имеет никакого отноше ния к значению переменной num. Поэтому в переменной ip содержится не значение 10, являющееся исходным для переменной num, а конкретный адрес, по которому эта переменная хранится в оперативной памяти. Операцию & можно рассматривать как возврат адреса той переменной, перед которой она указывается. Таким образом, при веденное выше присваивание словами можно описать так: "Переменная ip получает адрес переменной num.
Второй оператор, *, является дополнением оператора &. Этот унарный оператор на ходит значение переменной, расположенной по адресу, на который указывает его опе ранд. Следовательно, этот оператор обращается к значению переменной, на которую указывает соответствующий указатель. Так, если переменная ip содержит адрес памяти переменной num, как показано в предыдущем примере, то в следующей строке кода: int val = *ip;
в переменной val сохраняется значение 10 переменной num, на которую указывает переменная ip. Операцию * можно рассматривать как получение значения по адресу. Поэтому приведенный выше оператор присваивания описывается словами следую щим образом: "Переменная val получает значение по адресу, хранящемуся в пере менной ip."
Оператор * можно использовать также в левой части оператора присваивания. В этом случае он задает значение, на которое указывает соответствующий указатель, как в приведенном ниже примере. *ip = 100;
В данном примере значение 100 присваивается переменной, на которую указывает переменная ip, т.е. переменной num. Поэтому приведенный выше оператор присваи вания описывается словами следующим образом: "Разместить значение 100 по адресу, хранящемуся в переменной ip." Применение ключевого слова unsafe
Любой код, в котором используются указатели, должен быть помечен как небезо пасный с помощью специального ключевого слова unsafe. Подобным образом мож но пометить конкретные типы данных (например, классы и структуры), члены класса (в том числе методы и операторы) или отдельные кодовые блоки как небезопасные. В качестве примера ниже приведена программа, где указатели используются в методе Main, помеченном как небезопасный. // Продемонстрировать применение указателей и ключевого слова unsafe. using System; class UnsafeCode { // Пометить метод Main как небезопасный. unsafe static void Main { int count = 99; int* p; // создать указатель типа int p = &count // поместить адрес переменной count в переменной р Console.WriteLine("Исходное значение переменной count: " + *р); *р = 10; // присвоить значение 10 переменной count, // на которую указывает переменная р Console.WriteLine("Новое значение переменной count: " + *р); } }
Эта программа дает следующий результат. Исходное значение переменной count: 99 Новое значение переменной count: 10 Применение модификатора fixed
В работе с указателями нередко используется модификатор fixed, который препят ствует удалению управляемой переменной средствами "сборки мусора". Потребность в этом возникает, например, в том случае, если указатель обращается к полю в объекте определенного класса. А поскольку указателю ничего не известно о действиях системы "сборки мусора", то он будет указывать не на тот объект, если удалить нужный объект. Ниже приведена общая форма модификатора fixed: fixed (тип* р = &фиксированный_объект) ( // использовать фиксированный объект }
где р обозначает указатель, которому присваивается адрес объекта. Этот объект будет оставаться на своем текущем месте в памяти до конца выполнения кодового блока. В качестве адресата оператора fixed может быть также указано единственное выраже ние, а не целый кодовый блок. Модификатор fixed допускается использовать только в коде, помеченном как небезопасный. Кроме того, несколько указателей с модифика тором fixed могут быть объявлены списком через запятую.