Страница 329 из 502
<b>MyStruct* p; // объявить указатель</b>
<b>p = &o;</b>
<b>p->a = 10; // использовать оператор -></b>
<b>p->b = 20; // использовать оператор -></b>
<b>Console.WriteLine("Сумма равна " + p->Sum());</b>
Над указателями можно выполнять только четыре арифметические операции: ++, --, + и -. Для того чтобы стало понятнее, что именно происходит в арифметических операциях над указателями, рассмотрим сначала простой пример. Допустим, что переменная p1 является указателем с текущим значением 2000, т.е. она содержит адрес 2000. После выполнения выражения
<b>p1++;</b>
переменная p1 будет содержать значение 2004, а не 2001! Дело в том, что после каждого инкрементирования переменная p1 указывает на следующее значение типа int. А поскольку тип int представлен в C# 4 байтами, то в результате инкрементирования значение переменной p1 увеличивается на 4. Справедливо и обратное: при каждом декрементировании переменной p1 ее значение уменьшается на 4. Например выражение
p1--;
приводит к тому, что значение переменной p1 становится равным 1996, если раньше оно было равно 2000!
Все сказанное выше можно обобщить: после каждого инкрементирования указатель будет указывать на область памяти, где хранится следующий элемент его соотносимого типа, а после каждого декрементирования указатель будет указывать на область памяти, где хранится предыдущий элемент его соотносимого типа.
Арифметические операции над указателями не ограничиваются только инкрементированием и декрементированием. К указателям можно добавлять и вычитать из них целые значения. Так, после вычисления следующего выражения:
<b>p1 = p1 + 9;</b>
переменная p1 будет указывать на девятый элемент ее соотносимого типа по отношению к элементу, на который она указывает в настоящий момент.
Если складывать указатели нельзя, то разрешается вычитать один указатель из другого, при условии, что оба указателя имеют один и тот же соотносимый тип. Результатом такой операции окажется количество элементов соотносимого типа, которые разделяют оба указателя.
Кроме сложения и вычитания целого числа из указателя, а также вычитания двух указателей, другие арифметические операции над указателями не разрешаются. В частности, к указателям нельзя добавлять или вычитать из них значения типа float или double. Не допускаются также арифметические операции над указателями типа void*.
Для того чтобы проверить на практике результаты арифметических операций над указателями, выполните приведенную ниже короткую программу, где выводятся физические адреса, на которые указывает целочисленный указатель (ip) и указатель с плавающей точкой одинарной точности (fp). Понаблюдайте за изменениями каждого из этих указателей по отношению к их соотносимым типам на каждом шаге цикла.
<b>// Продемонстрировать результаты арифметических операций над указателями.</b>
<b>using System;</b>
<b>class PtrArithDemo {</b>
<b> unsafe static void Main() {</b>
<b> int x;</b>
<b> int i;</b>
<b> double d;</b>
<b> int* ip = &i;</b>
<b> double* fp = &d;</b>
<b> Console.WriteLine("int doublen");</b>
<b> for(x=0; x < 10; x++) {</b>
<b> Console.WriteLine((uint) (ip) + " " + (uint) (fp));</b>
<b> ip++;</b>
<b> fp++;</b>
<b> }</b>
<b> }</b>
<b>}</b>
Ниже приведен примерный результат выполнения данной программы. У вас он может оказаться иным, хотя промежутки между выводимыми значения должны быть такими же самыми.
<b>int double</b>
<b>1243464 1243468</b>
<b>1243468 1243476</b>
<b>1243472 1243484</b>
<b>1243476 1243492</b>
<b>1243480 1243500</b>
<b>1243484 1243508</b>
<b>1243488 1243516</b>
<b>1243492 1243524</b>
<b>1243496 1243532</b>
<b>1243500 1243540</b>
Как следует из приведенного выше результата, арифметические операции выполняются над указателями относительно их соотносимого типа. Так, значения типа int занимают в памяти 4 байта, а значения типа double — 8 байтов, и поэтому их адреса изменяются с приращением именно на эти величины.
Указатели можно сравнивать с помощью таких операторов отношения, как ==, < и >. Но для того чтобы результат сравнения указателей оказался содержательным, оба указателя должны быть каким-то образом связаны друг с другом. Так, если переменные p1 и р2 являются указателями на две разные и не связанные вместе переменные, то любое их сравнение, как правило, не имеет никакого смысла. Но если переменные p1 и р2 указывают на связанные вместе переменные, например на элементы одного массива, то их сравнение может иметь определенный смысл.