Доступ до змінної по вказівнику
Припустімо, що ми не знаємо змінної, але знаємо її адресу. Чи можемо ми дістати доступ до значення цієї змінної?
Існує спеціальний запис, призначений для доступу до значення змінної, використовуючи її адресу замість імені. В приведеній далі програмі показано, як це можна зробити.
#include<iostream>
using namespace std;
int main()
{ int var1=11;
int var2=22;
cout<<&var1<<endl
<<&var2<<endl;
int* ptr; //вказівник на ціле число
ptr=&var1;
cout<<*ptr<<endl;
ptr=&var2;
cout<<*ptr<<endl;
return 0;
}
Ця програма схожа на попередню за винятком того, що замість виведення на екран адрес, що зберігаються в змінній ptr, ми виводимо значення, які зберігаються за цією адресою. Вираз *ptr дозволяє нам одержати значення змінних var1 і var2.
Зірочка, яка стоїть перед іменем змінної, як у виразі *ptr, називається операцією розіменуванняю Цей запис означає таку дію: взяти значення змінної, на яку вказує вказівник. Таким чином, вираз *ptr являє собою значення змінної, на яку вказує вказівник ptr.
Вказівники можна використовувати не лише для одержання значень змінної, на яку він вказує, але й для виконання дій з цими змінними. Далі приведена програма використовує вказівник для присвоєння значень одній змінній, а потім іншій:
#include<iostream>
using namespace std;
int main()
{ int var1,var2;
int* ptr;
ptr=&var1;
*ptr=37;
var2=*ptr;
cout<<var2<<endl;
return 0;
}
Варто також запам’ятати, що зірочка, використовувана в операції розіменування – це не те саме, що зірочка, використовувана при оголошенні вказівника. Операція розіменування попереджає ім’я змінної і означає значення, що знаходиться в змінній, на яку вказує вказівник. Натомість зірочка в оголошенні вказівника означає вказівник на.
int* ptr; //оголошення вказівника на int
*ptr=37; //розіменування значення змінної
Доступ до значення змінної, яка зберігається за адресою, з використанням операції розіменування називається непрямим доступом або розіменованим доступом.
Розглянемо невеличкий приклад
int v; //оголошення змінної типу int
int* p;//визначаємо змінну типу вказівник на int
p=&v; //присвоюємо змінній p значення адреси змінної v
v=3; //присвоюємо v значення 3
*p=3; //робимо те саме, але через вказівник
Поки що ми не виявили перваг доступу через вказівники порівняно з прямим, але важливсість вказівників стає очевидною тоді, коли ми не маємо прямого доступу до змінної.
Вказівник на void
Відмітимо одну особливість роботи з вказівниками. Адреса, яка поміщається у вказівник, повинна бути одного з ним типу. Ми не можемо присовїти вказівнику на int адресу змінної типу float.
float flovar=99.6;
int* ptrint=&flovar; //заборонений вираз
Але є виняток – існує тип вказівника, який може вказувати на довільний тип даних. Він називається вказівником на void і визначається наступним чином:
void* ptr;
Такі вказівники призначені для використання в певних випадках, наприклад, при передачі вказівників у функції, які працюють незалежно від типу даних, на які вказує вказівник.
Розглянемо приклад використання вказівника на void.
#include<iostream>
using namespace std;
int main()
{int intvar;
float flovar;
int* ptrint;
float* ptrflo;
void* ptrvoid;
ptrint=&intvar; //так можна int*=int*
//ptrint=&flovar; //заборонено – вказівники різного типу
//ptrflo=&intvar; //заборонено – вказівники різного типу
ptrflo=&flovar; //float*=float*
ptrvoid=&intvar; **так можна void*=int*
ptrvoid=&flovar; //так можна void*=float*
return 0;
}
Якщо нам з певних причин необхідно прсвоїти одному типу вказівника інший тип, то з цією метою можна використати функцію reinterpret_cast:
ptrint=reinterpret_cast<int*>(&flovar);
ptrflo= reinterpret_cast<float*>(&intvar);
