Məzmuna keç
Educora
Orta20 dəq6 / 10

Göstəricilər, istinadlar və yaddaş

Yaddaş ünvanlarını, `&` və `*` operatorlarını, `nullptr`-i, dinamik yaddaşı (`new`/`delete`) və onu təhlükəsiz idarə edən `std::unique_ptr`-i öyrən.

Özünü yoxla
Bu dərsdə öyrənəcəksən
  • 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
  • new və delete ilə 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:

C++
#include <iostream>

int main() {
    int coins = 50;
    std::cout << "Value: " << coins << '\n';
    std::cout << "Address: " << &coins << '\n';
    return 0;
}
İkinci sətirdə 0x7ffc5a2b1c4c kimi bir ünvan görəcəksən — hər kompüterdə və hər işə salmada fərqli.
Tərif
Göstərici

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).

C++
#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;
}
Gözlənilən nəticə
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ı
&xx dəyişəninin ünvanı
int* pint-ə göstəricinin elanı
*pp ünvanındakı qiymət
nullptrheç 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.

C++
#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;
}
Gözlənilən nəticə
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:

C++
#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;
}
Gözlənilən nəticə
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.

C++
#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;
}
Gözlənilən nəticə
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.

C++
#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 automatically
Gözlənilən nəticə
Score: 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ə nullptr ola bilər.
  • new ilə ayrılan yaddaş delete (massiv üçün delete[]) ilə azad olunmalıdır — əks halda sızma yaranır.
  • RAII: std::vector, std::string və std::unique_ptr yaddaşı avtomatik azad edir — onlara üstünlük ver.

Özünü yoxla

10 sual. Hər düzgün cavab XP qazandırır.

1 / 10
&x ifadəsi nə verir?