# Указатели и памет. ## Указатели и референции. Работа с памет. Указателите, които вече добре познаваме, са променливи, които съхраняват адреса на обект в паметта. Указателите най - често са използвани за: * Да заделяме динамично памет в heap-а * Итерираме елементите на масив или друга структура от данни * Подаваме функции като аргументи на други функции и много други. Указателите са удобен и изключително гъвкав инструмент, с който често ще ни се налага да работим. Нека разгледаме следния сценарий. ```c++ int main() { int a = 10; int b = 12; int* ptr = &a; } ``` Искаме да напишем функция, която приема указател и променлива и кара указателя да сочи към адреса на тази променлива. Дали следния код ще свърши работа: ```c++ #include void redirect(int* ptr, int dest) { ptr = &dest; } int main() { int a = 10; int b = 12; int* ptr = &a; redirect(ptr, b); std::cout << *ptr; // *ptr връща стойността записана в този адрес } ``` Очевидно това не сработи, но защо? Във функцията *redirect* на *ptr* се прави **копие**. После това копие започва да сочи към *dest*, но на нас това не ни помага! Ние искаме да пренасочим **самия указател а не неговото копие**. Тук на помощ идват референциите (или псевдонимите). Ако пренапишем функцията по следния начин ```c++ void redirect(int*& ptr, int& dest) { ptr = &dest; } ``` то вече функцията върши желаната работа. Когато приемаме обект по референция **копие не се прави**. Това важи за всички типове - включително и за указателите. Можем да правим указатели към всякакви типове включително и към указатели. Типът **int\*\*** не е нищо повече от указател към указател. Тогава не можем ли просто да вземем указател към указателя и да го променим по този начин? ```c++ #include void redirect(int** ptr, int& dest) { *ptr = &dest; } int main() { int a = 10; int b = 12; int* ptr = &a; redirect(&ptr, b); // &ptr връща адреса на указателя, точно това което е int**, адрес на указател. std::cout << *ptr; } ``` Този код също върши работа. Тогава каква е разликата между указател и референция? Разликата е, че указателите са по - гъвкави. Не можем да пренасочим референция. Също така не можем да имаме референция която не сочи към обект. При указателите имаме специален тип наречен nullptr, който сочи към "нищото". Често референцията е представяна като указател, който не може да се пренасочва, вика \* вместо теб и винаги сочи към обект. ## const и указателите За *const* важи следното правило - *const* винаги модифицира това което е в негово ляво, освен когато няма нищо отляво, тогава модифицира това което е отдясно. * const int\* -> Указател, който сочи към константен *int*. Можем да пренасочваме, но не можем да променяме стойността. * int const\* -> Абсолютно същото. * int \* const -> Константен указател, не можем да го пренасочваме. * const int\* const -> Константен указател към константен *int*. Нито можем да пренасочваме нито да променяме стойността.