İşaretçiler ve Referanslar
Coddy'nin C++ Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 13 / 104.
Artık stack ve heap belleği anladığınıza göre, bellek konumlarıyla doğrudan çalışmanıza olanak tanıyan araçları keşfedelim: pointer'lar ve referanslar.
Bir pointer, başka bir değişkenin bellek adresini saklar. Onu * ile tanımlarsınız ve & kullanarak bir adres alırsınız.
int value = 42;
int* ptr = &value; // ptr, value değişkeninin adresini tutar
std::cout << ptr; // Bellek adresini yazdırır
std::cout << *ptr; // Dereference (Adresteki değere erişim): 42 yazdırırBir referans, mevcut bir değişken için bir takma addır. Bir kez bağlandığında, her zaman o değişkene atıfta bulunur. Onu & ile tanımlarsınız.
int value = 42;
int& ref = value; // ref, value için bir takma addır
ref = 100; // value değerini 100 olarak değiştirir
std::cout << value; // 100 yazdırırTemel farklar:
| Pointer'lar | Referanslar |
|---|---|
| Null olabilir | Başlatılması zorunludur |
| Yeniden atanabilir | Yeniden bağlanamaz |
Değere erişmek için * kullanılır | Değere doğrudan erişilir |
| Hiçbir şeyi işaret etmeyebilir | Her zaman geçerlidir |
Her ikisi de nesneleri kopyalamadan fonksiyonlara verimli bir şekilde aktarmak ve yığın (heap) üzerinde ayrılmış bellek ile çalışmak için gereklidir. Referanslar daha güvenli ve daha basittir; işaretçiler (pointers) ise yeniden atama yapmanız veya null kontrolü yapmanız gerektiğinde daha fazla esneklik sunar.
Görev
KolayVerileri değiştirirken işaretçilerin (pointers) ve referansların (references) nasıl farklı çalıştığını gösteren basit bir değer işleme sistemi oluşturalım.
Kodunuzu düzenlemek için iki dosya oluşturacaksınız:
ValueOps.h: Tam sayı değerlerini farklı şekillerde değiştiren üç fonksiyon tanımlayın:doubleByPointer(int* ptr)— bir işaretçi alır ve işaret ettiği değeri iki katına çıkarırtripleByReference(int& ref)— bir referans alır ve değeri üç katına çıkarırswapValues(int* a, int* b)— iki işaretçi alır ve işaret ettikleri değerleri birbirleriyle değiştirir
main.cpp: Girişten iki tam sayı okuyun, ardından hem işaretçileri hem de referansları gösterin:- Orijinal değerleri yazdırın:
"Original: <first> <second>" - İlk değer üzerinde
doubleByPointerkullanın, ardından yazdırın:"After double: <first>" - İkinci değer üzerinde
tripleByReferencekullanın, ardından yazdırın:"After triple: <second>" - Her iki değeri değiştirmek için
swapValueskullanın, ardından yazdırın:"After swap: <first> <second>"
- Orijinal değerleri yazdırın:
İşaretçilerle fonksiyon çağırırken, değişkenin adresini geçirmek için adres operatörünü (&) kullanmayı unutmayın. Referanslar daha doğal çalışır — değişkeni doğrudan geçirmeniz yeterlidir.
Başlık dosyanızı main.cpp içine #include "ValueOps.h" kullanarak dahil edin.
Kopya kağıdı
Bir pointer (işaretçi), başka bir değişkenin bellek adresini saklar. Onu * ile tanımlayın ve & kullanarak bir adres alın:
int value = 42;
int* ptr = &value; // ptr, value değişkeninin adresini tutar
std::cout << ptr; // Bellek adresini yazdırır
std::cout << *ptr; // Dereference (Adresten değere erişim): 42 yazdırırBir reference (referans), mevcut bir değişken için bir takma addır. Onu & ile tanımlayın:
int value = 42;
int& ref = value; // ref, value için bir takma addır
ref = 100; // value değerini 100 olarak değiştirir
std::cout << value; // 100 yazdırırTemel farklar:
| Pointer'lar | Referanslar |
|---|---|
| Null (boş) olabilir | Başlatılması (initialize) zorunludur |
| Yeniden atanabilir | Başka bir değişkene bağlanamaz |
Değere erişmek için * kullanılır | Değere doğrudan erişilir |
| Hiçbir şeyi işaret etmeyebilir | Her zaman geçerlidir |
Fonksiyonları pointer'lar ile çağırırken, değişkenin adresini geçirmek için adres operatörünü (&) kullanın. Referanslar doğrudan çalışır — sadece değişkeni geçirin.
Kendin dene
#include <iostream>
#include "ValueOps.h"
using namespace std;
int main() {
// Girdiden iki tam sayı oku
int first, second;
cin >> first;
cin >> second;
// Orijinal değerleri yazdır
cout << "Original: " << first << " " << second << endl;
// TODO: İlk değer üzerinde doubleByPointer kullan (& kullanarak adresi geçir)
// TODO: İkiye katladıktan sonra yazdır
// TODO: İkinci değer üzerinde tripleByReference kullan (değişkeni doğrudan geçir)
// TODO: Üç katına çıkardıktan sonra yazdır
// TODO: Her iki değeri takas etmek için swapValues kullan (& kullanarak adresleri geçir)
// TODO: Takas işleminden sonra yazdır
return 0;
}
Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.
Nesne Yönelimli Programlama bölümündeki tüm dersler
1OOP Temelleri
Harici DosyalarC++ Build ve DerlemeBaşlık Dosyaları ve Kaynak DosyalarıAd Alanları ve KapsamC++'ta OOP'ye GirişSınıflar ve Nesneler'this' İşaretçisiMetotlar (Üye Fonksiyonlar)Öznitelikler (Veri Üyeleri)Ctor ve Dtor TemelleriÖzet - Basit Hesap Makinesi4Sınıf Özellikleri
Örnek ve Statik ÜyelerGetter ve Setter MetotlarıConst Üye FonksiyonlarMutable Anahtar KelimesiStatik Metotlar ve DeğişkenlerFriend Fonksiyonlar ve SınıflarÖzet - Banka Hesabı Yöneticisi7Kalıtım
Temel KalıtımKalıtım Erişim SeviyeleriCtor ve Dtor Çağrılma SırasıMetot Geçersiz KılmaSanal Fonksiyonlar ve VTableÇoklu KalıtımSanal KalıtımÖzet - Çalışan Hiyerarşisi10STL Genel Bakış
STL Genel Bakış ve FelsefesiSTL KonteynerleriİteratörlerSTL AlgoritmalarıFunctor'lar ve Lambda İfadeleriÖzet - Kelime Frekansı13Tasarım Kalıpları 1. Bölüm
Tasarım Kalıplarına GirişSingleton KalıbıFactory ve Abstract FactoryBuilder KalıbıObserver KalıbıStrategy Kalıbı2Bellek Yönetimi
Stack ve Heap Bellekİşaretçiler ve ReferanslarDinamik Bellek (new/delete)C++'ta Akıllı İşaretçilerC++'ta RAIIÖzet - Dinamik Dizi Yöneticisi5Kapsülleme
C++'da Erişim BelirleyicilerDerinlemesine Erişim BelirleyicilerBilgi GizlemeStruct vs Classİç İçe ve Dahili SınıflarÖzet - Öğrenci Kayıt Sistemi8Çok Biçimlilik
Derleme ve Çalışma Zamanı Çok BiçimliliğiFonksiyon Aşırı YüklemeSanal Fonksiyonlara Yeniden BakışSaf Sanal FonksiyonlarSoyut SınıflarC++'ta Arayüz TasarımıDynamic Casting ve RTTIÖzet - Şekil Hesaplayıcı3Yapıcılar ve Yıkıcılar
Varsayılan YapıcıParametreli YapıcıKopya YapıcıTaşıma YapıcısıYapıcı İlklendirme ListeleriTemsilci YapıcılarYıkıcılara Derinlemesine BakışÜç / Beş / Sıfır KuralıÖzet - String Sınıfı6Operatör Aşırı Yükleme
Operatör Aşırı Yüklemeye GirişAritmetik Operatör Aşırı YüklemeKarşılaştırma Operatörü Aşırı YüklemeStream OperatörleriAtama Operatörü Aşırı Yükleme[] ve () Operatör Aşırı YüklemeTip Dönüşüm OperatörleriÖzet - Matris Sınıfı9Şablonlar
Fonksiyon ŞablonlarıSınıf ŞablonlarıŞablon ÖzelleştirmeVariadic ŞablonlarSFINAE ve Type Traits TemelleriÖzet - Generic Konteyner