🚀 C# ile Programlamaya Giriş: Kodlamaya İlk Adımını At, Kendi Projelerini Geliştirmeye Başla!
00ANASAYFA 01YAZILAR 02EĞİTİM 03ELEKTRİK_ENERJİ 04OTOMOTİV_MÜHENDİSLİĞİ 05ARAÇLAR 06LAB 07SÖZLÜK 08ETİKETLER ♡OKUMA LİSTEM ⌕ARA
TRENG

İşaretçiler ve referanslar

Adres, işaretçi (pointer) ve referans kavramlarını örneklerle öğren; swap, const referans ve nullptr.

İşaretçiler, C++'ın "korkulan" konusudur ama aslında basit bir fikre dayanır: her değişkenin bellekte bir adresi vardır ve bu adresi tutan değişkenler yapabiliriz. Bu ders, hem işaretçilerin hem de daha güvenli kardeşleri olan referansların temelini atar.

Adres ve işaretçi

  • &x: x değişkeninin adresini verir.
  • int* p: "int'e işaret eden işaretçi" tanımlar.
  • *p: p'nin gösterdiği yerdeki değere ulaşır (dereference).
  • nullptr: "hiçbir yere işaret etmiyorum" anlamına gelen güvenli boş değer.

Referans

Referans, mevcut bir değişkenin takma adıdır. int& r = x; yazdıktan sonra r ile x aynı kutudur. Referans tanımlanırken bir değişkene bağlanmak zorundadır ve sonradan başka bir değişkene bağlanamaz; nullptr olamaz. Bu yüzden işaretçiden daha güvenlidir.

#include <iostream>
#include <vector>

void degistir(int& a, int& b) {          // referansla: orijinaller degisir
    int gecici = a;
    a = b;
    b = gecici;
}

double ortalama(const std::vector<double>& v) {   // kopyalamadan, degistirmeden oku
    double t = 0.0;
    for (double x : v) t += x;
    return t / v.size();
}

void sifirla(double* p) {                // isaretciyle: nullptr kontrolu sart
    if (p != nullptr) *p = 0.0;
}

int main() {
    int x = 10;
    int* p = &x;
    *p = 20;          // p'nin gosterdigi yere yaz -> x = 20
    int& r = x;
    r++;              // r, x'in takma adi -> x = 21
    std::cout << "x = " << x << '\n';

    int a = 3, b = 7;
    degistir(a, b);
    std::cout << "a=" << a << " b=" << b << '\n';

    std::vector<double> v = {2.0, 4.0, 6.0};
    std::cout << "ortalama = " << ortalama(v) << '\n';

    double yuk = 5.5;
    sifirla(&yuk);
    std::cout << "yuk = " << yuk << '\n';

    int dizi[3] = {10, 20, 30};
    int* q = dizi;                       // dizinin ilk elemanina isaret eder
    std::cout << *(q + 1) << ' ' << q[2] << '\n';
    return 0;
}
x = 21
a=7 b=3
ortalama = 4
yuk = 0
20 30

Kodda neler oldu?

Referansla geçirme

Önceki derste parametrelerin kopyalandığını söylemiştik. degistir(int& a, int& b) fonksiyonunda ise & sayesinde orijinal değişkenler değiştirilir; bu yüzden a ve b gerçekten yer değiştirdi. Değiştirmeyecek ama büyük bir nesneyi geçireceksen const referans kullan: kopyalama maliyeti olmaz, fonksiyon da değiştiremez. ortalama(const std::vector<double>& v) bunun örneğidir.

İşaretçiyle geçirme

sifirla(&yuk) çağrısında adresi veriyoruz. İşaretçi boş olabileceği için fonksiyon önce nullptr kontrolü yapıyor. Yeni yazdığın kodda mümkünse referans, "değer olmayabilir" durumlarında işaretçi tercih et.

Dizi ve işaretçi ilişkisi

Dizi adı, ilk elemanının adresine dönüşebilir. q + 1 bir sonraki int'e (4 bayt ileri) gider; *(q + 1) onun değerini verir ve q[1] ile aynıdır. Buna işaretçi aritmetiği denir.

Gömülü sistemlerde donanım yazmaçlarına (register) erişim işaretçilerle yapılır. Örneğin bir port yazmacı bellekte sabit bir adreste durur ve şöyle gösterilir: volatile std::uint32_t* const port = reinterpret_cast<volatile std::uint32_t*>(0x40020014);. volatile derleyiciye "bu değer donanım tarafından değişebilir, optimize etme" der. Bu, C++ ile donanıma yazmanın temelidir.

Tehlikeli durumlar: (1) Başlangıç değeri verilmemiş işaretçiyi kullanmak, (2) nullptr'ı dereference etmek, (3) artık yaşamayan bir yerel değişkenin adresini tutmak (dangling pointer), (4) dizi sınırı dışına çıkmak. Hepsi tanımsız davranıştır: program bazen çalışır, bazen çöker, bazen sessizce yanlış sonuç üretir.

İşaretçi mi, referans mı?

ÖzellikReferansİşaretçi
Boş olabilir mi?HayırEvet (nullptr)
Sonradan başka şeye bağlanır mı?HayırEvet
Kullanımr (doğrudan)*p ile

Kendin dene

  1. İki double değeri yer değiştiren swap fonksiyonu yaz.
  2. Bir vektörün bütün elemanlarını 2 ile çarpan fonksiyon yaz: parametresi std::vector<double>& olsun.
  3. Bir int dizisini işaretçi aritmetiğiyle (*(q + i)) yazdır.
  4. int* p = nullptr; tanımla ve dereference etmeden önce kontrol eden bir if yaz.

// Mini sınav

Bir seçeneğe tıkla; doğru mu yanlış mı, anında ve nedeniyle birlikte göreceksin.

1. int* p = &x; satırında &x neyi ifade eder?
2. Aşağıdakilerden hangisi referansın işaretçiden farkıdır?
3. Büyük bir vektörü okumak için fonksiyona geçirirken hangi yol en uygundur?

Bitirdiğinde işaretle: ilerlemen kaydolur, +20 XP kazanırsın.

İpucu: ← → tuşlarıyla dersler arasında gezinebilirsin.