Указатели

   Определение : Променлива , която съдържа адреса на друга променлива(или обект).
Всяка променлива (или друг обект) имат адрес в оперативната памет, където се съхраняват техните стойности, указателите извършват действия само с адресите на клетките от паметта.
1. Деклариране на променлива от тип указател
Когато декларираме указател е необходимо да се определи към какъв тип данни сочи.
Тип * Име на указател ;
    Int *p;
Тип - към какъв тип променлива ще сочи указателя (int,double, float и т.н.)
и в зависимост от това колко байта от паметта ще заеме.
Звездичката * ( в литературата я наричат оператор за дереференция) се
използва:
Веднъж, когато се декларира указател.Пише се пред името на указателя.
Int * p1;      int заема място от паметта 4 байта
float *p2;     float заема място от паметта 4 байт
char *ch;     char заема място от паметта - 1 байт,
променлива от тип double заема 8 байта памет
Операторът & връща адреса на променливата стояща след него.
Звездичката се използва втори път, когато извлича стойността съхранявана на адреса,
който следва,
   Пример
int *p; - декларираме указател p;
cout<< *p; - извеждаме на екрана стойността от указателя р;
Разликата е много голяма и трябва да се внимава!
   Пример 1 :
#include <iostream.h> // Microsoft Visual C++ 6.0
int main()
{
int a=5,*p;
p=&a;
cout<< p<< endl;
cout<< *p<< endl;
return 0;
}

Обяснение:
int a=5,*p; - декларираме променлива а=5 и указател сочещ към целочислена променлива;
p=&a; - това означава, че в указателя р се съдържа адреса на променливата а (нещо от рода 0х22ff14– в шестнадесетична бройна система 0х означава шестн. бр. система ).
cout<< p<< endl; - извежда на екрана адреса на променливата а ;
cout< <*p; - ще изведе на екрана 5 т.е. компютъра ше отиде на адреса, който се съдържа
в указателя р и от него ще извлече стойността ( на променливата а, която е 5).
   Същия пример, но променяме чрез указател стойността на
променливата а от 5 на 20. Примера е за компилатор на с++ "Code Blocks"

#include <iostream> // for Code Blocks
using namespace std;
int main()
{
int a=5,*p;
p=&a;
cout<< p<< endl;
cout<< *p<< endl;
*p=20; cout<< "a="<< a<< endl;
cout<< "*p="<< *p<< endl;
return 0;
}

Действия с указатели :
   - Указателите могат да се събират и изваждат само с целочислени стойности;
   - Указателите могат да се изваждат един от друг за да се разберат , колко
на брой са елементите между тях;
   - Указателите могат да се сравняват, ако сочат към един и същ обект;
   - Указателите могат да се индексират, само ако сочат към масив;
       индексиране- p[i];(ако р е указател, то i или стойността между
квадратните скоби е индекса);
  Ако на указател се присвои името на масив без индекс, то се присвоява указател
към началото на масива(или по-точно: адресът на първия байт от масива, защото
някой променливи заемат 8 или 12 байта памет за една променлива. Изпробвайте пример №3).

   Пример 2 : Когато чрез указател р променяме стойността на променливата а

#include <iostream> // for Code Blocks
using namespace std;
int main()
{
int a=5;
int *p1,*p2;
p1=&a;
cout<< p1<< endl; // Извежда адреса на а
cout<< *p1<< endl; // Извежда стойността от този адреса или 5
*p1=20; // а=20
p2=p1; // р2= адреса на а
cout<< a<< endl; // извежда 20
cout<< p1<< endl; // Извежда адреса на а
cout<< *p2<< endl; // Извежда 20
return 0;
}

   Пример 3 : Показва как можете да изведете адресите на указателите в десетичен вид,
извежда също колко памет заема даден базов тип данни и накрая присвоява указател на указател.

#include <iostream>// for Code Blocks
#include <stdlib.h>
#include <sstream>
using namespace std;
int main()
{
double a[5]; int b,e,d;
double *p;
p=a;*p=10;
stringstream s;
s << hex << p;
s>>b;
cout<<"a[0]="<< *p<< " adress in hex: "<< p<< ", adress in dec: "<< b<< endl;
p++;*p=20;
stringstream s1;
s1 << hex << p;
s1>>e;
cout<< "a[1]="<< *p<<" adress in hex: "<< p<< ", adress in dec: "<< e<< endl;
p=&a[2];*p=30;
stringstream s2;
s2<< hex << p;
s2>>d;
cout<< "a[2]="<< *p<< " adress in hex: "<< p<< ", adress in dec: "<< d<< endl;
cout<< " int ->"<< sizeof(int)<< " byte"<< endl;
cout<< " long int->"<< sizeof( long int)<< " byte "<< endl;
cout<< " long long int->"<< sizeof( long long int)<< " byte "<< endl;
cout<< " float->"<< sizeof(float)<< " byte"<< endl;
cout<< " double->"<< sizeof( double)<< " byte"<< endl;
cout<< " long double->"<< sizeof( long double)<< " byte"<< endl;
int r=5,*p1=&r,**p2;p2=&p1;
cout<< " r="<< *(*p2)<< endl;
return 0;
}

   Пример 4 : В последния пример имаме използване на указател, сочещ към указател ,
който сочи към данни.
#include <iostream>// for Code Blocks
using namespace std;
int main()
{
int a=5,*p=&a,**p2=&p,***p3=&p2;
cout<< "p="<< p<< "->"<< *p<< endl;
cout<< "p2="<< p2<< "->"<< "addres p="<< *p2<< endl;
cout<< "p="<< *p2<< "->"<< *(*p2)<< endl;
cout<< "p3="<< p3<< "->"<< ***p3<< endl;
return 0;
}

int a=5
адрес 0х22ff08
p=&a
адрес на p 0х22ff04
адрес ** р2=&р
0х22ff00
Можем да напишем и ***р3=&р2 и ако напишем cout<<***p3; Ще изведе 5.

Благодаря за вниманието Ви !