Ниже приведен пример применения модификатора 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;
переменная p1 будет указывать на девятый элемент ее соотносимого типа по отноше нию к элементу, на который она указывает в настоящий момент.
Если складывать указатели нельзя, то разрешается вычитать один указатель из дру гого, при условии, что оба указателя имеют один и тот же соотносимый тип. Резуль татом такой операции окажется количество элементов соотносимого типа, которые разделяют оба указателя.
Кроме сложения и вычитания целого числа из указателя, а также вычитания двух указателей, другие арифметические операции над указателями не разрешаются. В част ности, к указателям нельзя добавлять или вычитать из них значения типа float или double. Не допускаются также арифметические операции над указателями типа void*.
Для того чтобы проверить на практике результаты арифметических операций над указателями, выполните приведенную ниже короткую программу, где выводятся фи зические адреса, на которые указывает целочисленный указатель (ip) и указатель с пла вающей точкой одинарной точности (fp). Понаблюдайте за изменениями каждого из этих указателей по отношению к их соотносимым типам на каждом шаге цикла. // Продемонстрировать результаты арифметических операций над указателями. using System; class PtrArithDemo { unsafe static void Main { int x; int i; double d; int* ip = &i double* fp = &d Console.WriteLine("int double\n"); for(x=0; x < 10; x++) { Console.WriteLine((uint) (ip) + " " + (uint) (fp)); ip++; fp++; } } }