C#'ta Gösterici(Pointer) Kullanmak – II

C#'ta göstericilerin kullanýmýna yönelik ilk yazýda göstericilere giriþ yapmýþtýk, C#'ta göstericilerin kullanýmýný 3 yazýlýk bir seri halinde anlatmayý düþündüm. Bu yazýda gösterici aritmetiðini ve fixed anahtar sözcüðünün kullanýmýný öðreneceðiz.

Göstericilerin adres bilesenlerine sabit tamsayi degerleri ekleyebiliriz, ayni sekilde göstericilerin adres bileseninden sabit bir tamsayi degerini çikarabiliriz. Ancak göstericilere uygulanan bu toplama ve çikarma islemleri biraz farklidir. Göstericilere sabit degerlerin eklenmesi yada bir degerin göstericiden çikarilmasi göstericideki tür bileseni ile yakindan ilgilidir. Bir göstericinin degerini bir artirmak göstericinin adres bilesenini, göstericinin türünün içerdigi byte sayisi kadar artirmak demektir. Ayni kural çikarma islemi içinde geçerlidir. Örnegin int türünden bir gösterici ile 1 sayisini toplamak göstericinin adres bilesenini 4 artirmak anlamina gelir. Çünkü int türü 4 byte büyüklügündedir. Ayni sekilde int türden bir göstericiden 1 sayisini çikarmak göstericinin adres bilesenini 4 eksiltmek anlamina gelir. Göstericilerle yapilan bu tür aritmetik islemlerin tamamina gösterici aritmetigi denilmektedir.

Gösterici aritmetigini daha yakindan görmek için asagidaki programi yazin ve sonucunu inceleyin.

using System;

class Gosterici
{
   
unsafe static void Main()
   {
      
int* ptr1 = (int*)500;
      
char* ptr2 = (char*)500;
      
double* ptr3 = (double*)500;
      
byte* ptr4 = (byte*)500;

      ptr1 += 2;
      ptr2 += 5;
      ptr3 += 2;
      ptr4 += 6;

      Console.WriteLine((uint)ptr1);
      Console.WriteLine((
uint)ptr2);
      Console.WriteLine((
uint)ptr3);
      Console.WriteLine((
uint)ptr4);
   }
}

Programi /unsafe argümani ile derleyip çalistirdigimizda asagidaki ekran görüntüsünüz elde ederiz. Programda Main() metodunun unsafe olarak isaretlendigine dikkat edin.

508
510
516
506

Programin çiktisindan da görüldügü üzere int türden bir göstericiye 2 sayisini eklemek göstericinin adres bilesenini 2*4=8 kadar artirmistir. Ayni sekilde char türden bir göstericiye 5 degerini eklemek göstericinin adres bilesenini 5*2 =10 kadar artirmistir. Toplama yerine çikarma islemi yapilmis olsaydi bu sefer ayni oranda adres bileseni eksiltimis olacakti.

Göstericiler üzerinde sadece tamsayilarla aritmetik islemler yapilabilir. Göstericiler ile asagidaki aritmetik operatörleri kullanabiliriz.

+ , - , -- , ++ , -=, +=

void göstericilerde herhangi bir tür bilgisi olmadigi için bu tür göstericiler üzerinde aritmetik islemler yapilamaz. Çünkü void türünden bir göstericiye örnegin 1 eklemek istedigimizde göstericinin adres bileseninin kaç byte ötelenecegi belli degildir.

Göstericiler üzerinde yapilabilecek diger önemli islemde iki göstericinin birbirinden çikarilmasidir. Gösterici türleri ayni olmak sartiyla iki göstericiyi birbirinden çikarabiliriz. Ancak iki göstericinin çikarilmasi sonucunda üretilen deger bir gösterici türü degildir. Iki gösterici arasindaki fark, adres bilesenlerinin sayisal farkinin gösterici türlerinin büyüklügünden kaç adet byte miktari edecegidir. Diger bir deyisle adres bilesenlerinin sayisal farki alinip gösterici türünün byte miktarina göre bir deger belirlenir. Iki göstericinin farki long türden bir deger üretir. Iki göstericinin farkina örnek verecek olursak, int türden 5008 adres ile int türden 5000 adresinin farki (5008-5000) % sizeof(int) tir. Yani sonuç long türden 2 dir. Asagidaki programi yazarak sonucu görebilirsiniz.

using System;

class Gosterici
{
   unsafe static void Main()
   {
      int* ptr1 = (int*)500;
      int* ptr2 = (int*)508;

      long fark=ptr2 - ptr1;

      Console.WriteLine(fark);
   }
}

Diger bir ilginç nokta iki göstericinin adres bilesenlerinin farki gösterici türlerinin büyüklügünün tam kati olmadiginda görülür. Örnegin ptr2 göstericisini tanimlanmasini

int * ptr2 = (int*)507;

seklinde degistirdiginizde bu sefer ekrana 1 yazdigini görürsünüz. Burdan çikarmamiz gereken sonuç iki göstericinin farki adres bilesenlerinin sayisal farkinin olmamasidir.

Dikkat: Iki göstericinin farki long türden bir deger üretir. Bu yüzden iki göstericinin farki açikca bir tür dönüsümü yapilmadikça long türünden küçük türden olan degiskenlere atanamaz.

Göstericiler ile kullanilabilecek diger operatörler ise ==, < ve > gibi karsilastirma operatörleridir. Bu operatörler iki göstericinin adres bilesenini karsilastirip ture yada false degeri üretirler. Karsilastirma operatörleri göstericiler için çok istisnai durumlar disinda anlamli degildir. Bu istisna durumlardan biri göstericileri kullanarak dizi islemleri yaptigimizda görülür.