Содержимое ячейки памяти с адресом ptr (а там записано число 5 – ведь это адрес переменной i) будет присвоено переменной j, содержимое ячейки памяти с адресом ukaz – переменной y, содержимое ячейки памяти с адресом adr – переменной d.
Таким образом, два оператора присваивания:
ptr = &i;
выполняют то же самое, что и один оператор:
Значит, можно организовать не только прямую передачу данных от одной переменной к другой (j = i), но и косвенную – через адреса переменных, даже не упоминая их имен. Указатели позволяют обращаться к конкретным ячейкам памяти и изменять их содержимое, не интересуясь тем, значения каких именно переменных хранятся в этих ячейках:
*adr = ‘+’;
переменой по адресу adr присвоено значение символа ‘+’,
(*ptr)++;
значение переменной по адресу ptr увеличивается на единицу,
(*ptr) += 3;
значение переменной по адресу ptr увеличивается на 3,
j = (*ptr)++;
значение переменной по адресу ptr присваивается переменной j и после этого увеличивается на единицу.
Если это выражение записать без скобок:
j = *ptr++;
то сначала значение адреса ptr увеличивается на единицу (получаем адрес следующей ячейки памяти), а затем содержимое новой ячейки памяти присваивается переменной j : операции доступа по адресу * и инкремента ++ имеют одинаковый приоритет, но выполняются справа налево.
Помимо операций доступа по адресу * и получения адреса & , над указателями определены следующие операции:
- сложение с константой,
- вычитание,
- инкремент,
- декремент,
- операции отношений.
Операция доступа по адресу* предназначена для доступа к величине, адрес которой хранится в указателе. Эту операцию можно использовать как для получения, так и для изменения значения величины (если она не объявлена как константа):
char a; // a - переменная типа char
char *ptr; // выделение памяти под указатель ptr
*ptr = ‘@’; // по адресу ptr записано значение @
a = *ptr; // переменной а присвоено значение, // записанное по адресу ptr
Как видно из примера, конструкцию *указатель можно использовать в левой части оператора присваивания, так как она определяет адрес области памяти. Эту конструкцию можно считать именем переменной, на которую ссылается указатель. С ней допустимы все действия, определенные для величин соответствующего типа.
Арифметические операции с указателями (сложение с константой, вычитание, инкремент и декремент) автоматически учитывают размер типа величин, адресуемых указателями. Эти операции применимы только к указателям одного типа и имеют смысл в основном при работе со структурами данных, последовательно размещенными в памяти, например, с массивами.
Инкремент++ перемещает указатель к следующему элементу массива, декремент- к предыдущему. Если указатель на определенный тип увеличивается или уменьшается на константу, то его значение изменяется на величину этой константы, умноженной на размер объекта данного типа. Эта операция производится автоматически.
Разность двух указателей – это расстояние между двумя областями памяти, определяемое в единицах, кратных размеру (в байтах) объекта того типа, к которому отнесены эти указатели. Таким образом, разность указателей, адресующих два смежных объекта одинакового типа, по абсолютной величине всегда равна единице.
Внимание! Суммирование двух указателей недопустимо!
Указатели редко используются с простыми данными вроде отдельных переменных. Преимущества указателей наглядно проявляются при использовании их вместе с массивами, функциями и строками.