Арифметические операции

 

Из арифметических операций к указателям могут применяться только сложение и вычитание, которые имеют ряд особенностей и ограничений.

Пусть объявлен массив и указатель, в котором хранится адрес начала массива: const n=10; float a[n]; float * p=a, *q; unsigned short k=3;

В результате операции сложения адреса с целым числом(p+k) для целого положительного к получается адрес ячейки, которая находится на k*sizeof(тип) байт “правее” ячейки с адресом p, где тип — тип элементов массива (здесь float). Другими словами, при использовании указателей для работы с массивами используется другая, отличная от известной с детского сада арифметика. Значение переменной указателя увеличивается не на k, как для обычных переменных, а на k*sizeof(тип). То есть записанное нами выражение система корректирует. Например, пусть p содержит значение адреса, условно равное 5000. Тогда в результате операции p+3 получим не 5003, а 5000+3*4=5012, где 4 =sizeof(float)— количество байт, занимаемое одним вещественным числом типа float. Другими словами, если в p был адрес начала массива (p=a), то p+3 — это адрес элемента a[3] (обозначается &a[3]), a *(p+3) — элемент массива a[3]. Если это изменённое значение адреса присвоить другой переменной, то есть выполнить q=p+3, то, как и для обычных переменных, адрес в p не изменится, а в q будет адрес элемента a[3]. Если выполнить p+=3, то значение переменной p изменяется и в нейбудет &a[3], а доступ к a[3] можно осуществить с помощью операции разыменование. Поэтому cout<<(*p); выведет значение 3-го элемента массива (a[3]).

При к=1 получаем операцию инкремент для адреса(p++;), которая выполняется аналогично. В результате численное значение указателя увеличивается не на один байт, а на величину sizeof(тип) байт, где тип — тип элементов массива, а тип * — тип указателя. В нашем случае мы сместимся на 4 байта вправо к соседнему элементу массива с большим адресом . При организации цикла эта операция играет ту же роль, что и увеличесие индекса на единицу, например, i++;.

Определена и операция вычитание целого положительного числа из указателя, например,p-k. Числовое значение указателя уменьшается на величину k*sizeof(тип). Поэтому для нашего примера после выполнения p-=3; мы “сместимся” на 3 элемента влево, то есть адрес в переменной p уменьшится на 3*4 =12 байт. После операции декремент (p--;) указатель “перемещается” влево к соседнему элементу с меньшим адресом.

Операции p+k, p-k, p++, p-- теоретически разрешены не только для массивов. Изменяя значение указателя, можно перемещаться по участкам памяти и получать доступ к разным переменным. Но не следует надеяться, что они будут размещаться в памяти подряд в соответствии с размещением их описаний в тексте программы. Потому эти операции могут дать непредсказуемые результаты, если их использовать не для массива. Полную уверенность в последовательном размещении элементов можно получить, если используем массив.

Кроме вычитания целого числа из указателя можно вычитать один указатель из другого.Эта операция имеет смысл только тогда, когда оба указателя указывают на элементы одного и того же типа. Более того, эти элементы должны находиться в одном и том же массиве. В результате получаем количество элементов указанного типа (а не количество байт), находящихся между указателями. При этом может получиться как положительное, так и отрицательное значение. Пусть в p находится адрес начала массива (например, 5000), а в q — &a[3], то есть, 5012. Тогда cout<<(q-p); выведет не 12, а число 3 ((5012-5000)/4), а cout<<(p-q); выведет отрицательное число -3, так как p указывает на элемент с меньшим адресом.

В случае указателей на символы при работе со строками рассмотренные выше арифметические операции упрощаются, так как sizeof(char)=1, и мы имеем дело с обычной арифметикой. В этом случае, например, операция p+k “перемещает нас” на k байт, или на k символов вправо, если k>0, и влево, если k<0.

Другие арифметические операции к указателям неприменимы. Нельзя умножать, делить и складывать указатели, нельзя умножать и делить их не только на вещественное, но и на целое число. Нельзя применять битовый сдвиг и другие битавые операции к указателям, нельзя к указателю добавлять или вычитать из указателей вещественные значения.