| Name | Size | |
|---|---|---|
| .. | ||
| README.md | 4.7 KiB | log stats plain blame |
| Сложност.pdf | 212.3 KiB | log stats plain blame |
Указатели и памет.
Указатели и референции. Работа с памет.
Указателите, които вече добре познаваме, са променливи, които съхраняват адреса на обект в паметта. Указателите най - често са използвани за: * Да заделяме динамично памет в heap-а * Итерираме елементите на масив или друга структура от данни * Подаваме функции като аргументи на други функции
и много други.
Указателите са удобен и изключително гъвкав инструмент, с който често ще ни се налага да работим. Нека разгледаме следния сценарий.
int main() {
int a = 10;
int b = 12;
int* ptr = &a;
}
Искаме да напишем функция, която приема указател и променлива и кара указателя да сочи към адреса на тази променлива. Дали следния код ще свърши работа:
#include<iostream>
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, но на нас това не ни помага! Ние искаме да пренасочим самия указател а не неговото копие. Тук на помощ идват референциите (или псевдонимите). Ако пренапишем функцията по следния начин
void redirect(int*& ptr, int& dest) {
ptr = &dest;
}
то вече функцията върши желаната работа. Когато приемаме обект по референция копие не се прави. Това важи за всички типове - включително и за указателите. Можем да правим указатели към всякакви типове включително и към указатели. Типът int** не е нищо повече от указател към указател.
Тогава не можем ли просто да вземем указател към указателя и да го променим по този начин?
#include<iostream>
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. Нито можем да пренасочваме нито да променяме стойността.
