Теперь можно обратиться к тому объекту, адрес которого содержит pint, используя операцию раскрытия указателя, называемую косвенной адресацией.

*pint = *pint+1; //увеличивает ival на 1, т.е. эквивалентно ival=ival+1;

В этом примере мало смысла. В реальности указатели используются чаще всего для манипуляций с динамически размещаемыми объектами.

Выделяют два основных различия между статическим и динамическим выделением памяти:

· Статические объекты обозначаются именованными переменными, и действия над этими объектами производятся напрямую, с использованием их имен. Динамические объекты не имеют собственных имен, и действия над ними производятся косвенно, с помощью указателей.

· Выделение и освобождение памяти под статические объекты производится компилятором автоматически. Выделение и освобождение памяти под динамические объекты целиком и полностью возлагается на программиста. Для манипуляции динамически выделяемой памятью служат операторы new и delete.

Простейшее объявление указателя на объект имеет вид: тип *имя; Тип может быть любым, причем тип к этому моменту может быть только объявлен, но не определен.

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

· Указатель на int, содержащий значение адреса 1000, указывает на область памяти 1000-1003 (в 32-битной системе);

· Указатель на double, содержащий значение адреса 1000, указывает на область памяти 1000-1007 (в 32-битной системе);

int *ip1, *ip2;

string *pstring;

double *dp;

long *lp, lp2; //lp – указатель на объект типа long, lp2 – переменная типа long/

Синтаксически правильны и эквивалентны следующие определения:

string *ps;

string* ps;

Рекомендуется использовать первый вариант определения. Если значение указателя равно нулю, значит он не содержит никакого адреса объекта. Указатель может быть константой, а также указывать на константу. Примеры:

Int i; //Целая переменная

const int ci=1; //Целая константа

const int *pci; //указатель на целую константу

int * const cp=&i; //указатель константа на целую переменную

const int *const cpc=&ci; //указатель-константа на целую константу

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

Величины типа указатель подчиняются общим правилам определения области действия, видимости и времени жизни.

Инициализация указателей

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

Существуют следующие способы инициализации указателя:

1. Присвоение указателю адреса существующего объекта:

· С помощью операции получения адреса:

int a=5;

int *p=&a; или int *p(&a);

§ С помощью значения другого инициализированного указателя: int *r=p;

2. Присвоение указателю адреса области памяти в явном виде:

char *cp = (char *)0xB8000000; //шестнадцатеричная константа 0xB8000000

//преобразуется к типу указатель на char

3. Присваивание пустого значения:

int *ip=NULL; //константа NULL – указатель равный 0

int *ip=0; //рекомендуется использовать 0

Пустой указатель можно использовать для проверки, ссылается указатель на конкретный объект или нет.

4. Выделение участка динамической памяти и присваивание ее адреса указателю:

int *ip=new int; //new выделяет участок динамической памяти, достаточный для

//размещения величины типа int и записывает адрес начала этого

//участка в переменную ip.

int *ip1=new int(10); //выделенная динамическая память инициализируется значением 10

int *ip3=new int[10]; //выделяется память под массив из 10 величин типа int и записывает

//адрес начала этого участка в переменную ip3.

Освобождение памяти должно выполняться с помощью операции delete: delete ip; delete ip1; delete []ip3;

Операции над указателями

& или операция адресации – унарная операция, возвращает адрес своего операнда.

int y=5;

int *ip=&y; //адрес переменной y присваивается укзателю ip

* или операция косвенной адресации или операция разыменования – возвращает значение, находящееся в области памяти, на которую указывает указатель (операнд операции *)

cout<<*ip; //выведет на экран 5

*ip=9 //9 присвоится переменной Y

cin>>*ip //осуществляет ввод значения переменной y

Пример.

int a=7;

int *aPtr=&a;

cout<<&*aPtr<<*&aPtr; //выведет 77, что показывает что операции * и & инверсны друг другу.

Когда мы применяем операцию & (взятия адреса) к объекту типа int, то получаем результат типа int *. Если ту же операцию применить объекту типа int* (указатель на int), то получаем результат типа int** (указатель на указатель на int). Объект типа int** - это адрес объекта, который содержит адрес объекта типа int.

int **aaPtr=&aPtr;

Чтобы получить само значение объекта a, необходимо операцию разыменования применить дважды:

cout<<**aaPtr;

Наши рекомендации