| Любой объект программы (переменная,
массив, функция и т. д.) имеет имя и занимает в памяти определенную область.
Местоположение объекта в памяти определяется его адресом. Обращение к
объекту можно осуществить по его имени или косвенно, через адрес. Обращение к
объекту через адрес осуществляется с помощью переменной-указателя,
связанного с объектом. Указатель хранит адрес объекта (или,
иначе, адрес ячейки памяти, с которой начинается объект). Для описания указателей используется
операция косвенной адресации *. Например, указатель целого типа uk описывается
так :  int *uk. Унарная операция &,
примененная к некоторой переменной, показывает, что нам нужен адрес этой
переменной, а не ее текущее значение. Если переменная uk объявлена как
указатель, то оператор присваивания  uk=&x означает: "взять адрес переменной x
и присвоить его значение переменной указателю uk". Теперь к переменной x
можно обратиться как *uk.     
В  одной  программе 
можно переопределять указатель, присваивая ему разные адреса. Тогда одна
и та же переменная будет использована для обращения к разным объектам. Такой
стиль обращений используется, однако, редко. Чаще, указатели используются при работе с
массивами, символьными строками, зарезервированными областями памяти и
объектами, память для которых выделяется динамически во время выполнения
программы (п. 2.3). Итак,
указатели предназначены для хранения адресов областей памяти. В C++ различают
три вида указателей – указатели на объект, на функцию и на void, отличающиеся свойствами и набором
допустимых операций. Указатель не является самостоятельным типом, он всегда
связан с каким-либо другим конкретным типом объекта. Указатель
на объект содержит адрес
области памяти, в которой хранятся данные определенного типа (основного или
составного). Объявление указателя на объект (в дальнейшем называемого просто
указателем) имеет вид: тип   *имя; где тип – тип объекта, на который
ссылается указатель. Он может быть любым, кроме ссылки и битового поля, причем
тип может быть к этому моменту только объявлен, но еще не определен
(следовательно, в структуре, например, может присутствовать указатель на
структуру того же типа). Символ "звездочка" сообщает компилятору, что
объявленная переменная является указателем. Независимо от типа объекта, для
указателя резервируется два или четыре байта в зависимости от используемой
модели памяти. Пример объявления указателей на
переменные целого типа: int  *pi, *pbi, *pci; Звездочка относится непосредственно к
имени. Поэтому для того, чтобы объявить несколько указателей, требуется ставить
ее перед именем каждого из них. Существует соглашение: имя указателя
начинать с буквы p. Это
облегчает чтение программы. При объявлении указателя надо стремиться
выполнить его инициализацию, то есть присвоение начального значения.
Непреднамеренное использование неинициализированных указателей –
распространенный источник ошибок в программах, который может привести к
аварийному событию. Инициализатор записывается после имени указателя либо в
круглых скобках, либо после знака равенства: тип  
*имя указателя = инициализирующее выражение; тип  
*имя указателя (инициализирующее выражение); Существуют
следующие способы инициализации указателя: 1.Присваивание
указателю адреса существующего объекта:   
– с помощью операции получения адреса: int a = 5; // целая
переменная int
*р = &а; //в указатель записывается адрес а int
*р (&а); // в указатель записывается адрес а другим способом    – с помощью значения другого
инициализированного указателя p: int a = 5; int *р = &а; int
*pr = р; //pr тоже указатель на a    – с помощью имени массива : int b[10]; // массив int
* pb = b; // присваивание адреса первого элемента
массива 2.
Присваивание указателю адреса области памяти в явном виде: char *pv = (char *)0xB8000000; Здесь
0xB8000000 –
шестнадцатеричная константа (начальный адрес видеопамяти ПЭВМ ), (char *) – обязательная операция приведения типа:
константа преобразуется к типу указателя ( char *). Таким образом, определяется, что в эту
ячейку памяти будет записан код переменной типа char. 3.
Присваивание пустого значения: int *psuxx = NULL; int
*prulez = 0; В
первой строке используется константа NULL, определенная в некоторых заголовочных файлах С как указатель, равный
нулю. Рекомендуется использовать просто 0, так как это значение типа int будет правильно преобразовано стандартными
способами в соответствии с контекстом. Поскольку гарантируется, что объектов с
нулевым адресом нет, пустой указатель можно использовать для проверки,
ссылается указатель на конкретный объект или нет. После определения указателя и его
инициализации адресом переменной или адресом области памяти, указатель можно
использовать для записи и чтения значения, находящегося по этому адресу. Для
этого применяется операция разыменования ' * ' ( получение значения
через указатель ). Пример: int a; // целая переменная int
*р = &а; //в указатель записывается адрес а *p = 5; //через операцию разыменования указателя переменной a присвоено значение 5 cout<< *p;
// вывод значения переменной a
через указатель но cout<< p;
// вывод адреса переменной a Выражение 
*p  обладает в данном случае правами имени
переменной  a 
и может использоваться везде, где допустимо использование имен объектов
того типа, к которому относиться указатель. С помощью указателя можно записать и
считать значение непосредственно из ячейки памяти с заданным адресом: char *pv = (char *)0xB8000000;//
присваивание указателю адреса области памяти в явном виде *pv = '+';    // запись в
ячейку с адресом 0xB8000000
символа  + char v = *pv;       // присваивание v значения из ячейки с адресом  0xB8000000, значение будет представлено в
символьном виде Можно определить неизменяемый
(константный) указатель. При инициализации ему присваивается значение
адреса, которое невозможно изменить. То есть константный указатель всегда
связан с конкретным фиксированным адресом участка основной памяти и является
как бы его именем. Определение константного указателя имеет следующий формат: тип 
*const  имя указателя 
инициализатор; Пример: char  *const key_byte =
(char*)1047; Значение указателя key_byte невозможно изменить, он всегда указывает на байт с адресом
1047. Содержимое участка памяти связанного с
константным указателем с помощью разыменования можно читать и изменять.   char  *const key_byte =
(char*)1047;     cout<<"\nbyte key:
"<< *key_byte; *key_byte = 'Ё';     cout<<"\nbyte key:
"<< *key_byte;   Попытку изменить значение самого
константного указателя, т.е. операцию вида key_byte = NULL; не допустит компилятор и выдаст сообщение
об ошибке. Можно определить указатель на
константу. Формат определения: тип 
const  *имя указателя  инициализатор; В этом случае значение переменной,
хранящейся по адресу связанному с указателем невозможно изменить через операцию
разыменования. Пример: const int zero = 0; //определение константы int const *pconst
= &zero;
//указатель на константу 0 Операторы вида  *pconst = 1; cin>>*pconst; недопустимы, так как каждый из них –
попытка изменить значение константы 0. Однако операторы pconst = &a; pconst = NULL; допустимы, так как разрывают связь
указателя pconst с
константой 0, но не меняют значение этой константы. Можно определить константный указатель
на константу. После инициализации такого указателя невозможно изменить ни
адреса, связанного с указателем, ни значения записанного по этому адресу с
помощью разыменования указателя. Например: const float pi = 3.141593; float const *const ppi = π Можно определить указатель на
указатель и т.д. сколько нужно раз. В следующей программе определены
такие указатели и с их помощью выполнен доступ к значению переменной:   int i = 77; int *pi = &i; int **ppi = π int ***pppi = &ppi; cout<<"i = "<< ***pppi;   Указатель
на тип void
применяется и тех случаях, когда конкретный тип объекта, адрес которого
требуется хранить, не определен (например, если в одной и той же переменной в
разные моменты времени требуется хранить адреса объектов различных типов). Указателю
на void можно присвоить
значение указателя любого типа, а также сравнивать его с любыми указателями, но
перед выполнением каких-либо действий с областью памяти, на которую он
ссылается, требуется преобразовать его к конкретному типу явным образом.
Возможности связывания указателя  void * с объектами разных типов показаны в следующей
программе:   void *pv; int i = 77; float f = 2.3456; cout<<RUS("\nНачальное значение pv = ")<< pv; pv = &i;     //работаем с переменной типа int cout<<"i
= "<< *(int
*)pv;     //перед разыменованием явное приведение
типа указателя к типу int pv = &f;     // работаем с переменной типа float cout<<"f
= "<< *(float
*)pv;  //перед разыменованием явное приведение типа
указателя к типу float |