Указатель - это переменная, содержащая адрес другой переменной.
При описании указателя надо задать тип объектов, адреса которых будут содержаться в нем. Перед именем указателя при описании ставится звездочка, чтобы отличить его от обычной переменной. Примеры описаний указателей:
int *a, *b, c, d;
char *e;
void *f;
В первой строке описаны указатели a и b на тип int и простые переменные c и d типа int (c и d - не указатели!).
С указателями возможны следующие два действия:
1. присвоить указателю адрес некоторой переменной. Для этого используется операция взятия адреса, которая обозначается амперсандом &. Например, строка
a = &c;
присваивает указателю a значение адреса переменной c;
2. получить значение переменной, адрес которой содержится в указателе; для этого используется операция звездочка '*'(называемая операцией разадресации), которая записывается перед указателем. (Заметим, что звездочкой обозначается также операция умножения.) Например, строка
d = *a;
присваивает переменной d значение целочисленной переменной, адрес которой содержится в a. Так как ранее указателю a был присвоен адрес переменной c, то в результате переменной d присваивается значение c, т.е. данная строка эквивалентна следующей:
d = c;
Указатели могут входить в выражения. Например, если a указывает на целое c, то *a может появляться в любом контексте, где может встретиться c. Так оператор
d = *a + 1
присваивает d значение, на 1 большее значения c;
cout<< *a;
печатает текущее значение c.
Зачем нужна вся эта мышиная возня? Для ускорения работы компьютера, который будет искать переменную только один раз - при задании указателя, - а потом будет уже обращаться к ней напрямую по адресу в памяти.
Арифметика указателей
Поскольку указатели - это адреса, а адреса - это всегда целые числа, то и к указателям можно прибавлять (или отнимать от них) только целые числа. При этом, эти числа означают количество байтов, соответствующих типу указателя. Например:
int *a, *b;
a = b + 2;
Здесь значение указателя а увеличивается на 8, так как b содержит адрес переменной типа int, которая занимает в памяти 4 байта, и в этой операции к b прибавляется ещё 2 таких же 4-байтовых отрезка. Этот процесс называется масштабированием.
Масштабирование очень подходит для работы с массивами, так как элементы массива располагаются в памяти один за другим, и увеличивая (уменьшая) указатель массива на единицу, мы переходим к адресу следующего (предыдущего) элемента массива.
Кроме смещения указателя на какое-либо число можно вычитать из большего указателя меньший (в случае, когда эти указатели одного типа). Разность их - это разность значений двух адресов, деленная на размер одного элемента данного типа.
Складывать указатели нельзя, ибо больший указатель уже содержит в себе меньший. Мало того, прибавляемый указатель может не быть кратным количеству байтов, соответствующих типу этого указателя.