May 24, 2022

Merhaba,

Bunu şurda Ali hoca sayesinde öğrendim ve dilerseniz kitaptaki bu bölümden ayrıntısına girebilirsiniz. Ama önce şu örneklere göz atın:

  int[] dizi = new int[3];
  "@×".writeln(dizi.ptr);       // @×9ABCDEF00xxx

  dizi[1] = 1;
  assert(dizi == [ 0, 1, 0]);

Buraya kadar her şey bildiğiniz gibi basit. Önce 3 elemanlı dinamik bir dizi oluşturduk. Otomatik 0 ile init olduğundan 0 değere sahip üyelerden 2.'sine klasik bir biçimde 1 yazdık...

  int * birGösterge = &dizi[1];
  "@×".writeln(birGösterge);    // @×9ABCDEF00xxx+4

Artık değeri 1 olan ve dizi'nin 2. elemanı gösteren bir göstergemiz var. Bunu adreslerden anlayabilirsiniz. Hatta bunlar da basit, değil mi!😀

  birGösterge[1] = 2;
  assert(dizi == [ 0, 1, 2]);

  "@×".writeln(&birGösterge[1]);// @×9ABCDEF00xxx+8

Şimdi, janjanlı kısım başlıyor. Gösterge bir sonrakine erişebilmesi için adrese bir nevi +4 eklemişiz gibi köşeli parantez kullanabiliyoruz. Böylece typeof, sizeof gibi şeylerle uğraşmıyoruz!

  assert(dizi.capacity == 3);
  dizi ~= 3;
  assert(dizi.capacity == 7);

Ancak devam etmeden önce dinamik dizinin kapasitesine bir bakalım. İddia ediyorum ki 7'den küçük, program assert'lere takılmazsa yüksek ihtimalle yeni eleman eklendiğinde dizi başka yere taşınacak. Evet, ilk dikkatlerinizi çekeceğim kısıma geliyoruz:

  birGösterge[2] = 41; // Dikkat 1: etkisiz!
  assert(dizi == [ 0, 1, 2, 3]);

  "@×".writeln(dizi.ptr);       // @× ???
  writefln("%-(%s, %)", dizi);  // 0, 1, 2, 3

Dizinin kapasitesi 3'den fazla olsaydı, (örneğin 4) o zaman son eklenen ile değerleri 0, 1, 2, 41, 3 olacaktı.

  int * ortası = &dizi[3];
  dizi.length = 7;

  // Dikkat 2: doğru adresi gösterirler...
  ortası[1] = 2;
  ortası[2] = 1;


  writefln("%-(%s, %)", dizi); // 0, 1, 2, 3, 2, 1, 0

Ama dizinin ortasını gösteren yeni bir gösterge doğru adresleri gösterecek. Bunu denemek için dizinin uzunluğunu olası kapasite kadar yükseltip 5 ve 6. elemanları değiştiriyoruz.

İlginç değil mi?

May 25, 2022

On Tuesday, 24 May 2022 at 17:58:41 UTC, Salih Dincer wrote:

>

Ali hoca sayesinde öğrendim ve dilerseniz kitaptaki bu bölümden [...]

Şimdi konuyu vakti az olanlar için tamamlayalım. Bölümün girişinde Ali hocam şöyle yazmış:

>

D'de göstergelerin çok daha kolay öğrenileceğini düşünüyorum. Bunun nedeni, göstergelerin amaçlarından bazılarının D'nin başka olanakları tarafından zaten karşılanıyor olmasıdır. Bu yüzden, hem bir çok durumda gösterge kullanılması gerekmez hem de başka D olanaklarının zaten anlaşılmış olması göstergelerin anlaşılmalarını da kolaylaştırır.

O yüzden GBS (Gereksiz Bilgiler Serisi) ya! Yani çok zorunda kalmadıkça hiç gösterge kullanmayınız. Ancak işin mantığını bilmek ve D'nin sağladığı esnekliği görmek güzel. Devam edelim... 😀

Bölümün ortalarında ve Göstergeden dilim elde etmek başlığı altında şu örnek verilmiş:

    double[] kesirliler = [ 0.0, 1.1, 2.2, 3.3, 4.4 ];

    double * gösterge = &kesirliler[2];

    *gösterge = -100;          // gösterdiğine erişim
    gösterge[1] = -200;        // dizi gibi erişim

    writeln(kesirliler);
>

Çıktısı: 0 1.1 -100 -200 4.4

Ve açıklaması da şöyle:

>

Böyle bir kullanımda göstergenin göstermekte olduğu değişken sanki bir dilimin ilk elemanıymış gibi düşünülür ve [] işleci o hayali dilimin belirtilen elemanına erişim sağlar. Yukarıdaki programdaki gösterge, kesirliler dizisinin 2 indeksli elemanını göstermektedir. gösterge[1] kullanımı, sanki hayali bir dilim varmış gibi o dilimin 1 indeksli elemanına, yani asıl dizinin 3 indeksli elemanına erişim sağlar.

Aslında D'nin güçlü dilimleri varken kendimizi böyle bir olanak ile kısıtlamak mantıklı değil. Yine de 10 seneyi aşkın süre D'nin içinde olan biri olarak (meğer C'den aldığı bir mirasmış; yani köşeli parantez C pointer'larında da mı var?) böyle bir şey ile karşılaşmamayı bırakın öğrenmemiş olmak bile eksiklik. Neyse, Ali hocam üstüne düşeni yapmış ve konuyu kitabında değinmiş. Son olarak kitaptan ilgili konuyu şu örneklerle bitirmiş:

>

Karışık görünse de bu kullanımın temelinde çok basit bir dönüşüm yatar. Derleyici gösterge[indeks] gibi bir yazımı perde arkasında *(gösterge + indeks) ifadesine dönüştürür:

    gösterge[1] = -200;      // dizi gibi erişim
    *(gösterge + 1) = -200;  // üsttekiyle aynı elemana erişim
>

Yukarıda da belirttiğim gibi, bu kullanımın geçerli bir değişkeni gösterip göstermediği denetlenemez. Güvenli olabilmesi için bunun yerine dilim kullanılmalıdır:

    double[] dilim = kesirliler[2 .. 4];
    dilim[0] = -100;
    dilim[1] = -200;
>

O dilimin yalnızca iki elemanı bulunduğuna dikkat edin. Dilim, asıl dizinin 2 ve 3 indeksli elemanlarına erişim sağlamaktadır. İndeksi 4 olan eleman dilimin dışındadır.

Dilimler güvenlidir; eleman erişimi hataları çalışma zamanında yakalanır:

    dilim[2] = -300;   // HATA: dilimin dışına erişim
>

Dilimin 2 indeksli elemanı bulunmadığından bir hata atılır ve böylece programın yanlış sonuçlarla devam etmesi önlenmiş olur:

core.exception.RangeError@deneme(8391): Range violation

Başarı sizinle olsun, kalın sağlıcakla...