Thread overview
Statik Dizilerin Ters (reverse => column x row) Kurulması
Jun 11, 2022
Salih Dincer
Jun 11, 2022
Salih Dincer
Jun 11, 2022
Ali Çehreli
Jun 13, 2022
Salih Dincer
Jun 13, 2022
Ali Çehreli
June 11, 2022

On Saturday, 11 June 2022 at 15:01:05 UTC, Ali Çehreli wrote:

>

On 6/11/22 00:09, z wrote:

>

I rechecked and it should be X Y Z for static array, but Z Y X for
indexing/dynamic array creating with new

How so? I wrote the following program:

import std.stdio;

void main() {
  enum X = 2;
  enum Y = 3;
  enum Z = 4;

  int[X][Y][Z] s;
  int[X][Y][] d = new int[X][Y][Z];

  pragma(msg, typeof(s));
  pragma(msg, typeof(d));
}

It outputs the following for the static and the dynamic arrays:

int[2][3][4]
int[2][3][]

Consistent elements, except the static array has a compile-time known length.

Ali

Merhaba Hocam,

Şimdi ben İngilizce iyi ifade edememiş olabilirim ya da ne bileyim Z ismindeki belirsiz kişi farklı bir şeyi de kastetmiş olabilir. O yüzden Türkçe yazayım istedim...

Eğer aynı şeyleri bahsediyorsak ki ben "in reverse" dedim üçlü örneğimiz kısaca şöyle:

   enum { X = 2, Y = 3, Z = 4 }
   auto d = new bool[X][Y][Z];

   d[X][Y][Z] = true; /* array index 3 is out of bounds `d[2][0 .. 3]`
   hatasını alırı çünkü erişimde yer değiştiriyorlar */

Örnek Y ortada olduğu için, sadece X ile Z yer değiştirmiş oluyor ve X, Z'den küçük olduğu için erişilemeyen bir yeri true yapmaya çalışıyoruz...

June 11, 2022

Siz Türkçe şurda mealen şöyle dediniz:

>

Bunu geçmişte defalarca yazdım ama D'nin yolu benim için tutarlı. Bunun nedeni, her zaman C'nin sözdizimini bu konuda çok mantıksız bulduğum için olmalı. [...]

Ben de "öyle düşünüyorum, katılıyorum" demek istedim ve şöyle devam ettim:

Sayenizde --consistent--v sözcüğünü de öğrendim!

>

Bence D, duygularımızla çok tutarlı. Yani bellekteki düzen satırlar x sütunlar şeklindedir. Ama evet, statik olarak ayarladığınızda tersi (sütun x satır). İşaretçiler üzerinde çalışan bu örnek kod bir kanıt olabilir:

void main()
{
  enum
  {
    Row = 2,
    Column = 3
  }
  size_t cal = Row * Column * int.sizeof;
  auto alloc = new ubyte[cal];
  size_t m = Column * int.sizeof;

  int[][] aSlice;
  foreach (i; 0 .. Row)
  {
    size_t n = i * m;
    aSlice ~= cast(int[])alloc[n .. n + m];
  }
  auto row = 2;
  auto column = 3;
  aSlice[row-1][column-1] = 1; // last element

  assert(
    *( &aSlice[0][0] // first element pointer
     + (row * column - 1)
     )
  ); // no error...


  //If you want to see it with your eyes:
  import std.stdio;
  aSlice.writefln!"%-(%-(%s %)\n%)";
}

Tamam, epey karışık ama bu daha önce birlikte geliştirdiğimiz bir işlevdi...

Yukardaki örneğimde, bellekteki adresleri kesinlikle ardı ardına olacak şekilde çift boyutlu (tamam buna itirazınız var ama söylenmesi kolay) erşiyoruz. Kurarken 2 satır ve 3 sütun kuralına uyduk ve pointer hesabı yaparak en sondaki 1 (true) yapıyorum. Çıktısını son satırda gözlerimizle görüyoruz. Ama eğer aynı parametreleri yer değiştirmeden kursaydık indekslerin 0'dan başlamasını da dikkate alarak son elemana şöyle ulaşırdık:

  auto birDizi = new bool[Row][Column];
  birDizi[2][1] = true; // hata vermez

Evet hata vermez çünkü biz derleyicinin diziyi kurarken, parametreleri tersten okumasını dikkate aldık ve 2. satırın 3.'ü elemanına eriş demedik ama biz Excel'deki gibi ABC yani üç sütun(column) istiyorduk neden 2 oldu!

Neyse, bu kadar kelam yer değişikliğini anlatmak içindi. Sanırım C'de de böyle. Tek farkı köşeli parantezin değişken isminin yanında olması.

Sevgiler, saygılar...

June 11, 2022
On 6/11/22 09:16, Salih Dincer wrote:

> Ben de "öyle düşünüyorum, katılıyorum" demek istedim ve şöyle devam ettim:

Çoğu konuda anlaşıyoruz. :)

> derleyicinin diziyi kurarken, parametreleri
> tersten okumasını dikkate aldık

Ben o tersten okuma konusunu anlamıyorum. Bir sonraki toplantıda konuşalım.

Ali

June 13, 2022

Merhaba,

Bu konu ya öyle hızlıca kapanmayacak (çünkü benim az önce netleştirdiğim şeyler var) ya da neredeyse tüm olasılıklara bakarak zaten kapatmak üzereyiz. Çıkış noktamız new operatörü ile kurulma tekniklerini anlatan şu sayfa:

https://dlang.org/spec/expression#new_multidimensional

Ancak dikkat, burada çok boyutlu diziler (Multidimensional Arrays) olarak nitelendirilen diziler dizisi, aşağıdaki spec'te, dikdörtgen diziler (Rectangular Arrays) olarak başlıklanırken daha çok işaretçilerin böldüğü (array of pointers to array) nitelendirilmiş...

https://dlang.org/spec/arrays.html#rectangular-arrays

Konu FORTRAN'dan başlayıp tırtıklı (jagged) diyebileceğimiz türde dizilere (hoş, aşağıdaki örneklerde bunu yapabilirdik) kadar uzuyor:

https://wiki.dlang.org/Dense_multidimensional_arrays

Buradaki konu başlığı her ne kadar statik diziler olsa da şu örneklerin biri (B maddesindeki 2 örnek) dışında her şey dinamik. O dizi sonuna (statik ve [2] birimlik olmak kaydıyla) ekleme bile yapabiliyorsunuz:

void printArray(Multi)(ref Multi arr)
{
  arr.writefln!"%-(%-(%12s %)\n%)";
  foreach(ref row; arr) {
    foreach(ref column; row) {
      write(&column, " ");
    }
    writeln;
  }
}
/* KISALTMALAR:
  =============
  - tür: tüm testin yapıldığı değişken (type)
  - sat: ilk baytın yerleştiği kısım (row)
  - süt: kaç adet (kısım x n) olacak (column)

  Açıklama: Kısım, aslında dizi ve tür.sizeof'dan
  sonra gelen en küçük birim. Çok boyutlu dizi ise
  dizi dizisi, yani en büyük birim.
 */
void main()
{
  alias tür = ubyte;

// A- 2 sat, 3 süt parantezli kurulum:

  auto satSüt = new tür[][](2, 3);
       satSüt[0][] = tür(1); // ilk satır 1 x 3

       satSüt[0].length = 4; /* dikkat: İlk kısım
       genişletilebiliyor! */

       satSüt.printArray;

  typeid(satSüt).writeln; // ubyte[][]

// B- öncekinin tersi sıralanan kurulum:

  auto sütSat = new tür[2][3];

       sütSat ~= [4, 4]; /* dikkat: dikey genişler
       ve statik dizilerin dizisidir */

       sütSat.printArray;
  typeid(sütSat).writeln; // ubyte[2][]

// C- Bu da aslında A'nın eşdeğeri (küçük a):
  auto a = new tür[][2];
       foreach(ref b; a)
       {
         b = new tür[3];
       }
       a.printArray;
  typeid(a).writeln;

Örneklerde işaretçilerin adrelerini ve içeriğini görebiliyorsunuz. Bunu bize sağlayan printArray() ve her şeyi değiştirerek istediğiniz gibi emin olmanız mümkün. O yüzden ben çok şey yazıp uzatmayacağım. Ancak dikkat çeken özellikle 2. örnek yani kısmen statik daha çok statik dizilerin dizisi, yanılıyor olabilir miyim?

On Saturday, 11 June 2022 at 16:26:18 UTC, Ali Çehreli wrote:

>

Ben o tersten okuma konusunu anlamıyorum. Bir sonraki toplantıda konuşalım.

Yukarda verdiğim 2. adresin 3. notunda "opposite orders" yazıyor. Acaba konuştuğumuz şey bu mu?

Teşekkürler...

June 13, 2022
On 6/12/22 22:19, Salih Dincer wrote:

> ya da neredeyse tüm olasılıklara bakarak zaten kapatmak
> üzereyiz.

Peki şu olasılığa baktık mı? Dinamik dizi statik dizisi dinamik dizisi dinamik dizisi statik dizisi? Tabii ki şaka yapıyorum. :) Temel kuralları öğrenince her şey zaten açık. Ve zaten dizi dizisi dizisi vs. çok nadiren kullanılıyor. Bu düzeylerden birisinde mutlaka araya bir struct giriyor çünkü yanında başka bilgiler de yararlı oluyor. Veya bir takım değişmezlerin (invariant) vs. sağlanması gerekiyor.

Temeller aşağıdakiler olunca benim için her şey tamam:

 - Tür    : Tek nesne
 - Tür[n] : n adet nesne yan yana
 - Tür[]  : yan yana n nesneyi gösteren iki değişken (ptr ve length)

Artık istediğim karmaşıklığa erişebilirim.

> Çıkış noktamız new operatörü ile kurulma tekniklerini anlatan
> şu sayfa:
>
> https://dlang.org/spec/expression#new_multidimensional

Ben de merak ettiğim bir şey bakmak için kendim denemiştim:

  new tür[][](2, 3)

diye tanımlayınca umduğum gibi davranıyor ve elemanlar gereken bütün belleği tek parçada ayırıyor. Sonra bütün dizi elemanları bu tek belleğin uygun yerlerini gösteriyorlar. Aslında iki bellek ayrılıyor: Dıştaki dinamik dizi için yer ve onun gösterdiği bütün dinamik dizi elemanları için *tek* yer:

Dıştaki:  {ptr, length}{ptr, length}
            |            |
            |             \
            |              \___
            |                  \
            |                   |
            V                   V
İçtekiler: {tür, tür, tür,}...{tür, tür, tür}...

İçteki dilimleri belirli bir biçimde hizaladığı için her birisinin yeni elemanlar için (bazen) biraz da kapasitesi oluyor. (Boş yerleri ... olarak gösterdim.)

import std.stdio;
import std.algorithm;
import std.format;

string değerleri(T)(T dizi) {
  return format!"{ptr: %s, length: %s, capacity: %s}"(
    dizi.ptr, dizi.length, dizi.capacity);
}

void main() {
  auto arr = new int[][](10, 5);
  writefln!"Dıştaki dizi:\n  %s"(arr.değerleri);

  writefln!"İçteki diziler:\n%-(  %s\n%)"(arr.map!değerleri);
}

O program (yalnızca) iki farklı bellek bölgesi olduğuna inandırıyor:

Dıştaki dizi:
  {ptr: 7F6FDF917000, length: 10, capacity: 10}
İçteki diziler:
  {ptr: 7F6FDF918000, length: 5, capacity: 7}
  {ptr: 7F6FDF918020, length: 5, capacity: 7}
  {ptr: 7F6FDF918040, length: 5, capacity: 7}
  {ptr: 7F6FDF918060, length: 5, capacity: 7}
  {ptr: 7F6FDF918080, length: 5, capacity: 7}
  {ptr: 7F6FDF9180A0, length: 5, capacity: 7}
  {ptr: 7F6FDF9180C0, length: 5, capacity: 7}
  {ptr: 7F6FDF9180E0, length: 5, capacity: 7}
  {ptr: 7F6FDF918100, length: 5, capacity: 7}
  {ptr: 7F6FDF918120, length: 5, capacity: 7}

İçteki her dizi birbirinden 0x20 uzakta durduğundan kapasitelerinin (0x20 / int.sizeof == 8) olmasını beklerdim. Anlaşılan, aralarda tek int'lik yeri kullanmıyor. (?) (int yerine başka uzunlukta türler vs. kullanınca farklı sonuçlar alınıyor.)

>    auto sütSat = new tür[2][3];
>
>         sütSat ~= [4, 4]; /* dikkat: dikey genişler
>         ve statik dizilerin dizisidir */

Evet, elemanları statik dizidir. Ne yazık ki oradaki [3] yazımı yanıltıcıdır çünkü bu new ifadesinde dıştaki dizi her zaman için dinamik dizidir.

Ali