Доступ к данным с использованием оператора обращения к значению (*)
Предположим, у вас есть указатель, содержащий вполне допустимый адрес. Как те перь обратиться к этой области, чтобы записать или прочитать содержащиеся в ней дан ные? Для этого используется оператор обращения к значению (de-referencing operator) (*). По существу, если есть допустимый указатель p D ata , использование оператора * p D ata позволяет получить доступ к значению, хранящемуся по адресу, содержащемуся в указа теле. Использование оператора (*) показано в листинге 8.4.
И СТИ Н Г 8.4 . Использование оператора обращения к значению
для доступа к целочисленному значению______________________
#include
using namespace std;
int main()
{
int Age = 30;
int DogsAge = 9;
8
|
cout
|
«
|
"Integer
|
Age = " «
|
Age
|
« endl;
|
9
|
cout
|
«
|
"Integer
|
DogsAge =
|
" «
|
DogsAge « endl;
|
10
|
|
|
|
|
|
|
int* plnteger = &Age;
cout « "plnteger points to Age" « endl;
// Отображение значения указателя
15
|
cout
|
«
|
"plnteger
|
=
|
Ox" «
|
hex
|
<< plnteger
|
«
|
endl;
|
16
|
// Отображение значения в указанной области
|
|
|
17
|
«
|
endl;
|
18
|
cout
|
«
|
"*plnteger
|
=
|
" «
|
dec «
|
*plnteger
|
19
|
|
|
|
|
|
|
|
|
|
plnteger = &DogsAge;
cout « "plnteger points to DogsAge now" « endl;
23
|
cout
|
«
|
"plnteger
|
=
|
Ox" «
|
hex
|
«
|
plnteger
|
<<
|
endl;
|
24
|
cout
|
«
|
"*plnteger
|
=
|
" «
|
dec
|
«
|
*plnteger
|
«
|
endl;
|
25
|
|
|
|
|
|
|
|
|
|
|
return 0;
}
Результат
Integer Age = 30
Integer DogsAge = 9
plnteger points to Age
plnteger = 0x0025F788
*plnteger = 30
plnteger points to DogsAge now
plnteger = 0x0025F77C
*plnteger = 9
Анализ
Кроме изменения адреса, хранимого в указателе, как в предыдущем примере (см. ли стинг 8.3), здесь используется также оператор обращения к значению (*) с тем же указателем p ln te g e r для отображения значения двух адресов. Обратите внимание на строки 18 и 24.
обеих этих строках осуществляется доступ к целочисленному значению, на которое указывает указатель p ln te g e r , с использованием оператора обращения к значению (*). По скольку адрес, содержавшийся в указателе p ln t e g e r , изменяется в строке 20, тот же ука затель после этого позволяет обратиться к переменной DogsAge и отобразить значение 9.
Когда выполняется оператор обращения к значению (*), приложение использует хра нящийся в указателе адрес как отправную точку для выборки из памяти 4 байтов, при надлежащих целому числу (поскольку это указатель на тип i n t и оператор s i z e o f ( i n t) дает 4). Таким образом, допустимость адреса, содержавш егося в указателе, является абсолютно необходимой. При инициализации указателя результатом оператора &Аде в строке 11 мы гарантировали, что указатель содержит допустимый адрес. Если не инициа лизировать указатель, он будет содержать случайное значение, которое сущ ествовало в области памяти при создании переменной указателя. Обращение к значению такого ука
зателя обычно приводит к ошибке с сообщением A c c e ss V i o l a t i o n (Нарушение прав доступа), свидетельствующем о попытке обращения к области памяти, доступ к которой вашему приложению не разрешен.
Оператор обращения к значению (*) называется также оператором косвенного доступа (indirection operator).
Указатель в приведенном выше примере использовался для чтения (получения) зна чения из области памяти, на которую указывает указатель. В листинге 8.5 показано, что происходит, когда оператор * p ln te g e r используется как 1-значение, т.е. для присвоения значения, а не для его чтения.
ЛИСТИНГ 8.5. Манипулирование данными при помощи указателя и оператора обращения к значению (*)_____
#include
using namespace std;
int main()
{
int DogsAge = 30;
6 cout « "Initialized DogsAge = " « DogsAge « endl;
7
int* pAge = &DogsAge;
cout << "pAge points to Dog'sAge" « endl;
10
11 cout « "Enter an age for your dog: ";
174 ЗАНЯТИЕ 8. Указатели и ссылки
1 2 :
// сохранить ввод в области памяти, на которую указывает рАде
cin » *рАде;
15:
// Отобразитьадрес, покоторому хранитсявозраст
17:
|
cout
|
«
|
"Input storedusing
|
pAge at
|
Ox" « hex
|
«
|
pAge « endl;
|
18:
|
cout
|
«
|
"Integer DogsAge =
|
" « dec
|
« DogsAge
|
«
|
endl;
|
19:
|
2 0 :
|
|
|
|
|
|
|
|
return 0;
22: }
Результат
Initialized DogsAge = 30
pAge points to DogsAge
Enter an age for your dog: 10
Input stored using pAge at 0x0025FA18
Integer DogsAge = 10
Анализ
Ключевой этап здесь в строке 14, где введенное пользователем целое число сохраняет ся в области, на которую указывает указатель pAge. Обратите внимание, несмотря на то, что введенное число было сохранено при помощи указателя pAge, строка 19 отображает это же значение при помощи переменной DogsAge. Это связано с тем, что указатель рАде указывает на переменную DogsAge, как было инициализировано в строке 8. Любое из менение в области памяти, где хранится значение переменной DogsAge, и на которую указывает указатель рАде, отражается на обоих.
Каков результат выполнения оператора sizeof () для указателя?
Вы уже знаете, что указатель — это только переменная, содержащая адрес области памяти. Следовательно, независимо от типа, на который он указывает, содержимое ука зателя — числовой адрес. Длина адреса — это количество байтов, необходимых для его хранения; она является постоянной для конкретной системы. Таким образом, результат выполнения оператора s i z e o f () для указателя зависит от компилятора и операционной системы, для которой программа была скомпилирована, и не зависит от характера данных, на которые он указывает, как демонстрирует листинг 8.6.
ЛИСТИНГ 8.6. Указатели на различные типы имеют одинаковый размер_________________
#include
using namespace std;
2 :
int main()
{
int Age = 30;
double Pi = 3.1416;
char SayYes = 'у ';
Динамическое распределение памяти
|
175
|
инициализация указателей адресами переменных int* pint = &Age;
double* pDouble = Π char* pChar = &SayYes;
cout
|
«
|
"sizeof fundamental
|
types
|
«
|
endl;
|
|
|
cout
|
«
|
"sizeof(int) =
|
" «
|
sizeof(int)
|
«
|
endl;
|
endl;
|
cout
|
«
|
"sizeof(double)
|
|
|
Do'stlaringiz bilan baham: |