Упрощённая модель памяти, но достаточно точная с точки зрения программиста:
Ø память компьютера представляет собой набор последовательно расположенных одинаковых ячеек, в которых хранятся данные. Ячейки называются байтами;
Ø все ячейки последовательно пронумерованы и каждая имеет свой уникальный номер, который называется адресом;
Ø одна переменная может занимать более одного байта. В этом случае адресом переменной является адрес её первого байта;
Ø доступ возможен только к тем ячейкам памяти, которые мы предварительно запросили у компьютера (т.н. выделение памяти). После того, как выделенные ячейки более не нужны, их можно вернуть компьютеру и в дальнейшем снова использовать (освобождение памяти);
Ø для обычных переменных выделение памяти происходит в момент объявления, а освобождение – в момент выхода из области действия;
Ø блоки памяти могут выделяться и освобождаться программой независимо от переменных в любой момент времени. Такие блоки не имеют имён, а только адрес.
1000 1004 1008 1012 1016 1020 1024 1028
int x, y;
| ▄▄▄▄
| ?
| ▄▄▄▄
| ▄▄▄▄
| ▄▄▄▄
| ?
| ▄▄▄▄
| …
|
| x
|
| y
|
|
x = 15;
| ▄▄▄▄
|
| ▄▄▄▄
| ▄▄▄▄
| ▄▄▄▄
| ?
| ▄▄▄▄
| …
|
К содержимому ячейки (= переменной) можно обращаться как посредством имени переменной, так и с помощью её адреса. Для реализации такой возможности во многих языках существуют команды адресации и разадресации. Первая позволяет по имени переменной получить её адрес, а вторая – по адресу получить значение, которое там содержится.
Существует также специальный тип, называемый указателями. Переменные данного типа предназначены для хранения адресов. В С++ существует три типа указателей:
ü указатель на переменную (содержит адрес первого байта переменной);
ü указатель на функцию (содержит адрес первой команды функции);
ü указатель на void (применяется в тех случаях, когда тип адресуемого объекта заранее не определён. Ему можно присвоить значение указателя любого типа и сравнить его с любым другим указателем).
Они отличаются свойствами и набором допустимых операций. Указатель – это не самостоятельный тип, он всегда связан с другим конкретным типом.
СИНТАКСИС ОБЪЯВЛЕНИЯ УКАЗАТЕЛЯ: тип * имя;
int *ip;
int *ip1, ip2, ip3; // ip1 – указатель, ip2 и ip3 – переменные
int* ip1, ip2, ip3; // ip1, ip2, ip3 – указатели
Величины типа указателя подчиняются общим правилам определения времени жизни, области действия и видимости. Указатель может быть константой, а также указывать на константу. Константный указатель не может менять своё значение.
Операции адресации и разадресации (&, *)
Для получения адреса какого – либо объекта используется операция адресации &.
int i;
int *ip = &i; //ip – адрес переменной i
Для доступа к величине по её адресу используется операция разадресации *.
int i = 5;
int *ip = &i;
cout << (*ip); //5
Конструкция *указатель является Lvalue.
1000 1004 1008 1012 1016 1020 1024 1028
int x, *p, *q
| ▄▄▄▄
| ?
| ▄▄▄▄
| ▄▄▄▄
| ?
| ?
| ▄▄▄▄
| …
|
| x
|
| p
| q
|
|
p = &x;
| ▄▄▄▄
| ?
| ▄▄▄▄
| ▄▄▄▄
|
| ?
| ▄▄▄▄
| …
|
|
*p = 125;
| ▄▄▄▄
|
| ▄▄▄▄
| ▄▄▄▄
|
| ?
| ▄▄▄▄
| …
|
|
q = p;
| ▄▄▄▄
|
| ▄▄▄▄
| ▄▄▄▄
|
|
| ▄▄▄▄
| …
|
|
(*q) += 10;
| ▄▄▄▄
|
| ▄▄▄▄
| ▄▄▄▄
|
|
| ▄▄▄▄
| …
|