Değer ve Referans Tipleri

Herkese Merhaba! Bugün değer ve referans tipleri hakkında bir yazı yazmak istedim. Bu konuyu bir yazılım mühendisinin kesinlikle bilmesi gerektiğini düşünüyorum. Değer ve referans tipleri tüm dillerde aynı mantıkta çalışıyor. Bugün anlatımımda C# üzerinden örnek veriyorum fakat Java, C++, Js vs.. gibi tüm dillerde aynı mantıkta çalışıyor. Daha fazla uzatmadan başlayalım 🙂

Öncelikle Tip ne demek hatırlayalım. Çoğu dilden bildiğimiz float, char, integer, boolean vs.. ifadeleri değişkenlerimizin tiplerini ifade ediyor. Bu tipler Değer ve Referans tipleri olarak 2 ye ayrılıyor.

Değer ve Referans Tip Tablosu
Değer ve Referans Tip Tablosu

Tabloyu mümkün oldukça anlaşılır şekilde oluşturdum fakat bazı yerleri tekrardan açıklamam gerekiyor. Veri tiplerini değer ve referans tipleri olarak ikiye ayrılır.

Değer Tipleri

Değer tipleri değişkenin değerini direkt bellek bölgesinden alırlar. Yani “int sayi1 = 5″ diye bir atama işlemi yaptığımızda sayi1 değişkeni stack bölgesinde oluşturuluyor. İsterseniz bir sonraki yazımda verilerin saklandığı bölgeleri (static bölge, sabit bölge, register bölgesi..) konusuna bakabiliriz. Değer tipleri ile ilgili bir c# örneği yaparak konuyu pekiştirelim. Sizde java, python gibi dillere uyarlayabilirsiniz.

int sayi = 5;
Console.WriteLine("Sayi ilk hali: "+sayi);  //System.out.println("Sayi ilk hali: "+sayi);
sayi = 10;
Console.WriteLine("Sayi ikinci hali: " + sayi);   //System.out.println("Sayi ikinci hali: "+sayi);

Sizce buradaki çıktı ne olacak? Bu soruyu cevaplamamız için değer tiplerin mantığını tam anlamış olmalıyız. Yukarıda belirttiğimiz gibi değer tipleri direkt bellek üzerinde tutuluyor. Yani burada bulunan ilk ifade “int sayi = 5;” bellekte sayi isimli değişkene 5 değerini atamış oluyor. Ardından yaptığımız “sayi = 10;” işlemi direkt bellek üzerinde bulunan sayi değişkenine uygulanacaktır. Sonuç olarak çıktımız aşağıdaki gibi olacaktır.

programCiktisi1

Farklı bir örnekle değer tipini bitirelim. Bu örneğimizde bir değer tipli değişkende yapılan değişiklik buna eşit olan başka bir değer tipli değişkende etkisine şahit olacağız. Tamam, kabul ediyorum böyle deyince oldukça karışık geldi örnekte hemen inceleyelim 🙂

int sayi = 5;
int sayi2 = sayi;
Console.WriteLine("Sayi2 ilk hali: "+sayi2);
sayi = sayi + 5;
Console.WriteLine("Sayi2 ikinci hali: " + sayi2);

Hemen çıktımızı da görelim üzerine konuşalım 🙂

programciktisi2

Satır satır ilerleyip kafa karışıklığını önlemek istiyorum. Öncelikle sayi isimli integer tipinde değişkene 5 değerini atadık. Ardından sayi2 isimli integer tipli değişkenimizi, sayi değişkenine eşitledik. Ve yazdırma fonksiyonunu kullanıp sayi2 değişkenini yazdırdık. Daha sonra sayi değişkenimizin değerine +5 ekledik. Ve şimdi sayi2 değişkenini bir daha yazdırıyoruz ki değişim olmuş mu görelim. Gördüğünüz üzere sayi2 değişkenin değeri değişmedi.

Peki bu işlemin aynısını referans tiplerinde yaparsak. Örneğin referans tiplerinden dizileri kullanarak nasıl çıktı alırdık ?

Referans Tipleri
            //ilkRakamDizisi isimli dizimizi boyutu 4 olucak şekilde tanımlıyoruz
            int[] ilkRakamDizisi = new int[4];

            //ikinciRakamDizisi isimli dizimizi ilkRakamDizisi'ne eşitliyoruz
            int[] ikinciRakamDizisi = ilkRakamDizisi;

            //ilkRakamDizimizin elemanlarını atıyoruz.
            ilkRakamDizisi[0] = 0;
            ilkRakamDizisi[1] = 1;
            ilkRakamDizisi[2] = 2;
            ilkRakamDizisi[3] = 3;

            //ilkrakamdizisi elamlarını yazdırıyoruz
            Console.WriteLine("-------ilkRakamDizisi isimli dizimizin ilk hali--------");
            foreach (var sayi in ilkRakamDizisi)
            {
                Console.WriteLine((sayi+1)+".nci elemanı: "+sayi);
            }

            // Burada eşitlediğimiz ve hiç eleman eklemediğimiz ikinci rakam dizisinin 3. indisindeki elemanı 9 yapıyoruz.
            ikinciRakamDizisi[3] = 9;

            //ilkrakamdizisi elamlarını tekrar yazdırıyoruz
            Console.WriteLine("-------ilkRakamDizisi isimli dizimizin ikinci hali--------");
            foreach (var sayi in ilkRakamDizisi)
            {
                Console.WriteLine((sayi + 1) + ".nci elemanı: " + sayi);
            }

Kodumuzu incelemeye başlamadan önce çıktımıza da bir göz atın. Ve mutlaka çalıştığınız dile bu kodu uyarlayıp konuyu sindirin!

programCiktisi3
Programımızın çıktısı

Kodumuza geçmeden size minik bir soru sormak istiyorum. Çıktıda ikinci kısımdaki yazdırma işlemi sırasında neden 4. indis yerine 10. indis şeklinde yazdı Mail olarak ilk dönüş yapan kişiye bir ödülüm olacak 🙂 ❤

Akılda kalıcılığı arttırmak adına buradaki örnekte kodumuzu biraz uzattım. Yine satır satır giderek kodumuzu inceleyelim. Öncelikle int tipinde ilkRakamDizisi isimli dizimizi boyutu 4 olacak şekilde tanımladık. Ardından ikinciRakamDizisi isimli dizi oluşturup ilkRakamDizisi dizimize eşitledik. Aslında bunlar referans tipli olduğu için yani dizi oldukları için değerlerini değil adreslerini eşitledik. İşte tüm fark bu! Eğer burayı anladıysak bundan sonrası yalnızca kod kısmı. Yani bizim buradaki ilkRakamDizisinde 3. indise atadığımız 3 sayısını değiştirmememize rağmen ikinci yazdırmamızda 9 olarak değişti. Bunun iki adet sebebi var. Birincisi en başta ikinciRakamDizisi’nin adresini ilkRakamDizisi’ne eşitlediğimiz için ve diziler referans tipli olduklarından adresleri eşit oldu. Bu yüzden ikinci neden olarak da ikinciRakamDizisinde 3. indisi 9 olarak değiştirdiğimizde ilkRakamDizisini de etkilemiş oldu.

Buradan anladığımız üzere Referans tiplerinde eğer eşitleme işlemi yaparsak Heap bölgesinde bulunan adreslerini eşitlemiş oluruz. Değer tiplerinde ise eşitleme durumunda yalnızca Stack bölgesinde bulunan değerleri eşitlenmiş olur.

Biraz karışık olsa da bu konuyu bitirmiş olduk. Anlamadığınız sormak istediğiniz bir yer olursa bana ulaşabilirsiniz. Bir sonraki yazıda görüşmek üzere. Herkese sağlıklı günler dilerim ❀