- Göstəricinin nə olduğunu izah etmək,
&ilə ünvan almaq və*ilə qiymətə müraciət etmək - Göstəriciləri istinadlarla müqayisə etmək və
nullptr-i yoxlamaq newvədeleteilə dinamik yaddaşın necə ayrıldığını və təhlükələrini izah etmək- RAII prinsipini və
std::unique_ptr-i tətbiq etmək
Dostuna kitab vermək istəyirsən, amma kitab çox ağırdır. Onu daşımaq əvəzinə bir kağıza ünvanı yazırsan: «Nizami küçəsi, 12, 3-cü rəf». Dostun ünvanla kitabı özü tapa bilər. C++ dilində göstərici məhz belə kağızdır: o, qiymətin özünü yox, onun yaddaşdakı ünvanını saxlayır. Göstəricilər C++ dilinə sürət və çeviklik verir, amma diqqətsizlik bahalı başa gələ bilər.
Ünvanlar və göstəricilər
Kompüterin yaddaşı nömrələnmiş xanalardan ibarətdir və hər dəyişən müəyyən ünvanda yerləşir. & operatoru dəyişənin ünvanını qaytarır. Ünvan adətən onaltılıq say sistemində çap olunur və proqram hər dəfə işə düşəndə fərqli ola bilər:
#include <iostream>
int main() {
int coins = 50;
std::cout << "Value: " << coins << '\n';
std::cout << "Address: " << &coins << '\n';
return 0;
}0x7ffc5a2b1c4c kimi bir ünvan görəcəksən — hər kompüterdə və hər işə salmada fərqli.Başqa dəyişənin yaddaş ünvanını saxlayan dəyişən. int* p yazılışı «p — int tipli qiymətə göstəricidir» deməkdir. *p ifadəsi göstəricinin ünvanındakı qiymətə müraciətdir (ingiliscə dereference).
#include <iostream>
int main() {
int coins = 50;
int* ptr = &coins;
std::cout << "coins = " << coins << '\n';
std::cout << "*ptr = " << *ptr << '\n';
*ptr = 75;
std::cout << "coins = " << coins << '\n';
std::cout << std::boolalpha << (ptr == &coins) << '\n';
return 0;
}coins = 50 *ptr = 50 coins = 75 true
*ptr = 75 göstəricinin ünvanındakı qiyməti, yəni coins-in özünü dəyişir.| Yazılış | Mənası |
|---|---|
&x | x dəyişəninin ünvanı |
int* p | int-ə göstəricinin elanı |
*p | p ünvanındakı qiymət |
nullptr | heç yeri göstərməyən göstərici |
p->name | (*p).name-in qısa yazılışı |
İstinadlar və nullptr
Əvvəlki dərslərdə istinadlarla (int& ref = a;) tanış olmuşdun — istinad dəyişənin ikinci adıdır. Göstəricidən fərqli olaraq istinad elan olunanda mütləq bir dəyişənə bağlanır və sonra başqa dəyişənə keçirilə bilmir. Göstərici isə istənilən vaxt başqa ünvana yönəldilə bilər və heç yeri göstərməyə də bilər.
#include <iostream>
int main() {
int a = 10;
int b = 20;
int& ref = a;
int* ptr = &a;
ref += 5;
std::cout << "a = " << a << '\n';
ptr = &b;
*ptr += 5;
std::cout << "b = " << b << '\n';
std::cout << "a = " << a << '\n';
return 0;
}a = 15 b = 25 a = 15
Heç yeri göstərməyən göstəriciyə nullptr yazılır. nullptr-ə müraciət etmək (*p) qeyri-müəyyən davranışdır və adətən proqramı çökdürür. Ona görə göstərici boş ola bilərsə, istifadədən əvvəl onu yoxla:
#include <iostream>
void printValue(const int* p) {
if (p == nullptr) {
std::cout << "No value\n";
return;
}
std::cout << "Value: " << *p << '\n';
}
int main() {
int level = 3;
printValue(&level);
printValue(nullptr);
return 0;
}Value: 3 No value
Dinamik yaddaş: new və delete
Adi lokal dəyişənlər stekdə yaranır və funksiya bitəndə avtomatik silinir. Bəzən isə yaddaşı proqram işləyərkən, lazım olan ölçüdə ayırmaq lazımdır. new operatoru dinamik yaddaşda (heap) yer ayırır və onun ünvanını qaytarır. Bu yaddaş özü-özünə silinmir: onu delete ilə (massivi isə delete[] ilə) əl ilə azad etmək lazımdır.
#include <iostream>
int main() {
int* p = new int(42);
std::cout << *p << '\n';
delete p;
p = nullptr;
int size = 4;
int* squares = new int[size];
for (int i = 0; i < size; i++) {
squares[i] = i * i;
}
std::cout << squares[3] << '\n';
delete[] squares;
return 0;
}42 9
RAII və ağıllı göstəricilər
Müasir C++ bu problemləri RAII (Resource Acquisition Is Initialization) prinsipi ilə həll edir: resursu obyekt alır və obyekt məhv olanda resursu avtomatik qaytarır. std::vector və std::string məhz belə işləyir. Tək obyekt üçün <memory> faylındakı ağıllı göstərici std::unique_ptr var: o, yaddaşın yeganə sahibidir və görünmə sahəsindən çıxanda yaddaşı özü silir.
#include <iostream>
#include <memory>
#include <utility>
int main() {
std::unique_ptr<int> score = std::make_unique<int>(100);
*score += 50;
std::cout << "Score: " << *score << '\n';
std::unique_ptr<int> other = std::move(score);
std::cout << std::boolalpha << (score == nullptr) << '\n';
std::cout << "Other: " << *other << '\n';
return 0;
} // other deletes the memory automaticallyScore: 150 true Other: 150
unique_ptr-i köçürmək olmaz, yalnız std::move ilə sahibliyi ötürmək olar; köçürüləndən sonra score boş qalır.Əsas fikirlər
- Göstərici başqa dəyişənin ünvanını saxlayır:
int* p = &x;. &ünvanı verir,*isə ünvandakı qiymətə müraciət edir.- İstinad həmişə bir dəyişənə bağlıdır; göstərici yönünü dəyişə və
nullptrola bilər. newilə ayrılan yaddaşdelete(massiv üçündelete[]) ilə azad olunmalıdır — əks halda sızma yaranır.- RAII:
std::vector,std::stringvəstd::unique_ptryaddaşı avtomatik azad edir — onlara üstünlük ver.
Özünü yoxla
10 sual. Hər düzgün cavab XP qazandırır.
&x ifadəsi nə verir?