Добавить в цитаты Настройки чтения

Страница 329 из 502

<b>MyStruct* p; // объявить указатель</b>

<b>p = &amp;o;</b>

<b>p-&gt;a = 10; // использовать оператор -&gt;</b>

<b>p-&gt;b = 20; // использовать оператор -&gt;</b>

<b>Console.WriteLine(&quot;Сумма равна &quot; + p-&gt;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 = &amp;i;</b>

<b>    double* fp = &amp;d;</b>

<b>    Console.WriteLine(&quot;int doublen&quot;);</b>

<b>    for(x=0; x &lt; 10; x++) {</b>

<b>      Console.WriteLine((uint) (ip) + &quot; &quot; + (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 байтов, и поэтому их адреса изменяются с приращением именно на эти величины.

Указатели можно сравнивать с помощью таких операторов отношения, как ==, &lt; и &gt;. Но для того чтобы результат сравнения указателей оказался содержательным, оба указателя должны быть каким-то образом связаны друг с другом. Так, если переменные p1 и р2 являются указателями на две разные и не связанные вместе переменные, то любое их сравнение, как правило, не имеет никакого смысла. Но если переменные p1 и р2 указывают на связанные вместе переменные, например на элементы одного массива, то их сравнение может иметь определенный смысл.