Шрифт:
Оператор * можно использовать также в левой части оператора присваивания. В этом случае он задает значение, на которое указывает соответствующий указатель, как в приведенном ниже примере. *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 могут быть объявлены списком через запятую.
Ниже приведен пример применения модификатора fixed. // Продемонстрировать применение оператора fixed. using System; class Test { public int num; public Test(int i) { num = i; } } class FixedCode { // Пометить метод Main как небезопасный. unsafe static void Main { Test о = new Test(19); fixed (int* p = &o.num) { // использовать модификатор fixed для размещения // адреса переменной экземпляр о.num в переменной р Console.WriteLine("Исходное значение переменной о.num: " + *р); *р = 10; // присвоить значение 10 переменной count, // на которую указывает переменная р Console.WriteLine("Новое значение переменной о.num: " + *р); } } }
Вот к какому результату приводит выполнение этой программы. Исходное значение переменной о.num: 19 Новое значение переменной о.num: 10
В данном примере модификатор fixed препятствует удалению объекта о. А по скольку переменная р указывает на переменную экземпляра о.num, то она будет ука зывать на недостоверную область памяти, если удалить объект о. Доступ к членам структуры с помощью указателя
Указатель может указывать на объект типа структуры при условии, что структура не содержит ссылочные типы данных. Для доступа к члену структуры с помощью ука зателя следует использовать оператор-стрелку (->), а не оператор-точку (.). Напри мер, доступ к членам структуры struct MyStruct { public int a; public int b; public int Sum { return a + b; } }
осуществляется следующим образом. MyStruct о = new MyStruct; MyStruct* p; // объявить указатель p = &o; p->a = 10; // использовать оператор -> p->b = 20; // использовать оператор -> Console.WriteLine("Сумма равна " + p->Sum); Арифметические операции над указателями
Над указателями можно выполнять только четыре арифметические операции: ++, --, + и -. Для того чтобы стало понятнее, что именно происходит в арифметических операциях над указателями, рассмотрим сначала простой пример. Допустим, что пе ременная p1 является указателем с текущим значением 2000, т.е. она содержит адрес
После выполнения выраженияp1++; переменная p1 будет содержать значение 2004, а не 2001! Дело в том, что после каждого инкрементирования переменная p1 указывает на следующее значение типа int. А по скольку тип int представлен в C# 4 байтами, то в результате инкрементирования зна чение переменной p1 увеличивается на 4. Справедливо и обратное: при каждом декре ментировании переменной p1 ее значение уменьшается на 4. Например выражениеp1--; приводит к тому, что значение переменной p1 становится равным 1996, если раньше оно было равно 2000!
Все сказанное выше можно обобщить: после каждого инкрементирования указа тель будет указывать на область памяти, где хранится следующий элемент его соот носимого типа, а после каждого декрементирования указатель будет указывать на об ласть памяти, где хранится предыдущий элемент его соотносимого типа. Арифметические операции над указателями не ограничиваются только инкремен тированием и декрементированием. К указателям можно добавлять и вычитать из них целые значения. Так, после вычисления следующего выражения: p1 = p1 + 9;