Plazma sayı 8, sayfa 20

Bu sayfadaki yazılar

Sayfanın metni

Sayfa 20

Daha önce bir takım değişkenleri tanımlamaktan ve kullanmaktan bahsettik. Bu değişkenlerin hepsinin de bellekte durduğunu biliyoruz. İşte bir değişkenin bellekte durduğu yere o değişkenin “adresi” denir. Bu adres genelde platformun mimarisine bağlı büyüklükte bir sayıdır. Örneğin 32 bitlik bir sistemde bir değişkenin adresi de 32 bitlik bir sayıdır.

Bellek denilen şey art arda dizilmiş baytlardan oluşur. Bu baytlara istediğimiz bilgileri yazarız. Zaten siz bir değişken tanımladığınızda, o değişkenin tipine bağlı olarak bellekte bir grup bayt değişken için ayrılır. Örneğin çoğu 32 bitlik sistemde siz int tipinden bir değişken tanımladığınızda bellekte 4 baytlık bir alan ayrılır.

Bir değişkenin adresini almaya yarayan operatör & operatörüdür. Örneğin

in as 4 std::cout << da;

dediğiniz zaman sisteminizin a için ayırdığı baytlardan ilkinin adresini ekrana yazdırmış olursunuz.

bu tip değişken adresleri ile çeşitli işlemler yapabilmeniz için “işaretçileri” destekler. Bir işaretçi kendisi de bir değişkendir. İçerisinde başka bir değişkenin “adresini” taşır. Başka bir deyişle başka bir değişkene “işaret eder”. Bir nevi “şurada falanca tipte bir değişken var” der. Bunu biraz açalım.

İşaretçiler gösterdikleri değişkenin tipi ile bağlantılıdırlar örneğin

int a - 5;

int* pa &a;

Burada önce a adında tamsayı tipinde bir değişken tanımladık ve o değişkeni hemen 5 ile yükledik. Ardından “int tipinde bir değişkene bakan”, pa adında bir işaretçi tanımladık. Ve ona a değişkeninin adresini yükledik. İkinci satır bu demektir.

İşaretçiler aracılığıyla onların gösterdikleri değişkenlere erişebiliriz. Bunun için *operatörünü aşağıdaki gibi kullanırız std::cout<<*pa; bu komut a'daki değeri yani 5'i yazdırır. Aynı şekilde *pa=10;

Diyerek a değişkeninin değerini değiştirebiliriz.

İşaretçiler ile diziler arasında da akrabalık vardır diyebiliriz. Bir dizi tanımladığımız zaman dizinin adını aynı zamanda dizinin ilk elemanına bakan bir işaretçi gibi kullanabiliriz. Örneğin

int dizi(3) * (1, 2, 3); *dizi - 5; std: dizilÖl,;

dediğimizde 5 sonucu yazdırılır. Ancak dizilerin işaretçilerden farkı başka bir int değişkeninin adresini dizi'ye atayamamanızdır (oysa dizi bir dizi değil de işaretçi olsaydı atayabilirdiniz)

Değişkenlerin nerelerde ne amaçla kullanıldığını merak ediyor olabilirsiniz. Bu kullanımları yeri geldikçe birlikte göreceğiz.

Giriş

Bellek Yönetimine İşaretçilerin kullanıldığı yerlerden biri dinamik bellek yönetimidir. Şu ana kadar bütün gördüğümüz değişken tanımlamalarında, derleyici programın derlenişi esnasında ihtiyaç duyulan bellek miktarını bilebilir ve bu belleğin ayrılmasını dolaylı olarak sağlar.

Oysa bazen programcı, bellek tasarrufu için ya da başka sebeplerle çalıştığı sistemden bellek isteyecek şekilde programı yazmaya ihtiyaç duyar. Bu durumlarda programımıza bazı durumlarda sistemden bir miktar bellek isteyen komutlar yazarız.

İşte “bana biraz bellek ver” diye konuştuğumuz şahsiyete aslında “C++ runtime” deniyor. Bu programınıza eklenen bir kod bütünü. İşletim sistemi ile sizin programınız arasındaki bazı bağlantıları yaparak, programınızın çalışması için zemin hazırlıyor. Runtime'ın yaptığı işler arasında programınızın ihtiyacı olan belleğin bir kısmını siz istedikçe size sağlamak da var.

Aynı şekilde kullanıp artık ihtiyacınız kalmayan belleği de yine sisteme iade etmek gerekir. Siz bir bellek parçasını sisteme iade ettiğinizde o bellek sonraki isteklerde size verilebilecek bir kaynak olarak müsait hale gelir.

Eğer hep sistemden bellek alır ve hiç iade etmezseniz, eninde sonunda sistemde bellek kalmaz ve programınızın başına kötü şeyler gelir. Bu şekilde iade edilmesi gereken belleği iade etmeyi unutmak programlarda sık yapılan bir hata türüdür ve özel bir adı vardır: Bellek Sızdırma.

Şimdi sistemden nasıl bellek istediğimize bakalım: int* pa © new int();

Sistemden bellek isterken new komutunu kullanırız. Bu esnada o bellekte saklayacağımız şeyin tipini de söyleriz. Ve bu istek bize bir işaretçi döndürür. Bu işaretçi yeni oluşturulan değişkenin adresini taşımaktadır. Örneğin yukarıda bir tamsayı saklayacak kadar belleği sistemden istiyoruz. Eğer runtime istediğimiz belleği bulabilir ise (bellek bitmemişse bulur) uygun büyüklükte bir bellek parçasını ayırır ve o parçanın adresini döndürür.

Dönen şey bir adres olduğu için onu bir işaretçide saklamak zorundayız. İşte bu işaretçilerin en çok kullanıldığı yerlerden biridir. Bu tamsayı değişkenini hep işaretçi üstünden kullanırız.

Klavyeyle gezinmek için ← ve → tuşları.