Jump to page: 1 2
Thread overview
Foreach döngüsü içindeki dizide oluşan hatalar
Oct 21, 2011
zafer
Oct 21, 2011
zafer
Oct 24, 2011
zafer
Oct 24, 2011
zafer
Oct 25, 2011
zafer
October 21, 2011

data.txt dosyası;

Alıntı:

>

Book:Defter
Table:Masa
Pencil:Kalem
Door:KapI
Blue:Mavİ
Dog:Köpek

import std.stdio;
import std.array;

void main()
{
	File dosya = File("data.txt", "rb");
	string[] listeForeach = ListeHazirla_ForeachKullan(dosya);

	writeln("ListeHazirla_ForeachKullan metodu ile elde edilen liste:");
	for (int j = 0; j < listeForeach.length; ++j)
	{
		writeln("Soru : ", listeForeach[j]);
	}


	File dosya2 = File("data.txt", "rb");
	string[] listeWhile = ListeHazirla_WhileKullan(dosya2);

	writeln("ListeHazirla_WhileKullan metodu ile elde edilen liste:");
	for (int j = 0; j < listeWhile.length; ++j)
	{
		writeln("Soru : ", listeWhile[j]);
	}
}

private string[] ListeHazirla_ForeachKullan(File dosya)
{
	string[] liste;

	int i = 0;
	foreach (satir; dosya.byLine())
	{

		string[] soru = cast(string[])split(satir, ":");

		liste.length = i + 1;
		liste[i] = soru[0];

		++i;
	}

	return liste;
}

private string[] ListeHazirla_WhileKullan(File dosya)
{
	string[] liste;

	int i = 0;
	while (!dosya.eof)
	{
		string satir = dosya.readln();
		string[] soru = split(satir, ":");

		if (!dosya.eof)
		{
			liste.length = i + 1;
			liste[i] = soru[0];

			++i;
		}
	}

	return liste;
}

Bu kod üzerinde aşamadığım bazı sorunlar yaşıyorum ayrıca aklıma takılan bazı durumlar söz konusu, maddeler halinde yazmadan önce bu kodun bendeki çıktısını aşağı ekliyorum.

Alıntı:

>

zafer@debian:~/DProjeler/TestD$ dmd -w main.d
zafer@debian:~/DProjeler/TestD$ ./main
ListeHazirla_ForeachKullan metodu ile elde edilen liste:
Soru : Dog:
Soru : Dog:K
Soru : Dog:K
Soru : Dog:
Soru : Dog:
Soru : Dog
ListeHazirla_WhileKullan metodu ile elde edilen liste:
Soru : Book
Soru : Table
Soru : Pencil
Soru : Door
Soru : Blue
Soru : Dog
zafer@debian:~/DProjeler/TestD$

Çıktıdan görüleceği üzere foreach ile oluşturulan liste sorunlu bir şekilde geliyor. Şimdi sorularım

  1. File bir yapı değil mi? Ben bir yapı olarak düşündüğüm için metoda göndeririken kendisinin değil bir kopyasının gönderileceğini düşündüm bu sebeple bir tane dosya değişkeni tanımlayıp iki metodada göndermeye çalıştım ama olmadı.

  2. Yukarıdada görüldüğü gibi foreach içinde oluşan listede sorun oluyor. Normalde dosyadan okuyup listeye eklerken her satırda listenin değerini kontrol ettiğimde bir sorun görünmüyor ama foreach döngüsünden çıkıp listeyi yazdırmaya çalıştığımda sadece dosyadaki en son değeri görüyorum.

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

October 21, 2011

Alıntı (zafer):

>

kodun bendeki çıktısını aşağı ekliyorum.

Ben de aynı çıktıyı alıyorum.

Alıntı:

>

Çıktıdan görüleceği üzere foreach ile oluşturulan liste sorunlu bir şekilde geliyor.

Bu sorun Digital Mars forumlarında da geçmişti. Ne yazık ki ByLine okuduğu satırlar için tek üye değişken tutuyor. dmd/src/phobos/std/stdio.d dosyasından:

   struct ByLine(Char, Terminator)
   {
       File file;
       Char[] line;   // <-- son okuduğu satır
// ...

       Char[] front()
       {
// ...
           return line;  // <-- onu döndürüyor
       }

// ...

       void popFront()
       {
// ...
           file.readln(line, terminator);  // <-- ona okuyor

Dizilerin referans özellikleri nedeniyle de senin dizinin içindeki bütün dilimler aynı karakterlere erişim sağlıyorlar. Hepsinin .ptr niteliği aynı:

   for (int j = 0; j < listeForeach.length; ++j)
   {
       writeln("Soru : ", listeForeach[j]);
       assert(listeForeach[j].ptr is listeForeach[0].ptr);  // <-- aynı
   }

Yanılmıyorsam o forum konusunda bunun hız için önemli olduğu söylenmişti. ByLine her satırı kendisi farklı olarak kopyalayacağına, satırları ayrı ayrı saklamak isteyenlerin kopyalamalarının daha etkin olacaktı.

Bu sorunu çözmek için bir .dup ekleyebiliriz:

       string[] soru = cast(string[])split(satir.dup, ":");

Artık listeye eklenenler ByLine'ın verdiği satırın kopyaları olurlar. while'lı yöntem şanslı çünkü 'string satir' while'ın içinde tanımlanmış. while'ın her dönüşünde yeni bir 'satir' nesnesi oluşur. O nesne listeye eklendikten sonra while içindeki referansın yaşamı sona eriyor ama bizim liste içindeki referans yaşamaya devam ediyor (çünkü açıkça gerektiği gibi while'ın dışında tanımlanmış.)

Alıntı:

>
  1. File bir yapı değil mi? Ben bir yapı olarak düşündüğüm için metoda göndeririken kendisinin değil bir kopyasının gönderileceğini düşündüm

Çok doğru ama işin garibi, File perde arkasında tek işletim sistemi kaynağı kullanıyor. Bir nesne ilerleyip o kaynağı sonuna kadar ilerlediğinde diğer nesnemiz de dosyanın sonunda olduğunu görüyor.

Alıntı:

>

bu sebeple bir tane dosya değişkeni tanımlayıp iki metodada göndermeye çalıştım ama olmadı.

Bu, InputRange ile ForwardRange kavramlarının farkını çok güzel gösteren bir örnek.

stdin InputRange olmak zorundadır. Bir işlevin ondan çekip çıkarttığı karakteri başka işlev göremez.

Öte yandan diskte duran dosyalar teoride ForwardRange olabilirler, çünkü belirli bir durumlarını saklamak ve sonra örneğin C'deki fsetpos ile belirli bir noktasına geri dönmek mümkündür.

Bir sorun, Phobos'ta ForwardFile diye bir kavramın bulunmuyor olması. Bunu Digital Mars forumunda dile getirmek ilginç olabilir.

Yani sonuçta File soyutlaması stdin gibi durumları saklanamayan akımları da kapsadığı için File nesnelerinin kopyalanmaları senin (ve benim) beklediğim sonucu vermiyor.

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

October 22, 2011
import std.stdio;
import std.array;

void main()
{
   File dosya = File("data.txt", "rb");
   string[] listeForeach = ListeHazirla_ForeachKullan(dosya);

   writeln("ListeHazirla_ForeachKullan metodu ile elde edilen liste:");
   for (int j = 0; j < listeForeach.length; ++j)
   {
       writeln("Soru : ", listeForeach[j]);
   }
}

private string[] ListeHazirla_ForeachKullan(File dosya)
{
   string[] liste;
   string satir1;

   int i = 0;
   foreach (satir; dosya.byLine())
   {
	satir1 = cast(string)satir;

	writefln("satir1 : %s \t-> adresi1 : %s \t-> ptr1: %s", satir1, &satir1[0], satir1.ptr);

	liste.length = i + 1;
	liste[i] = satir1;

	++i;
   }

   return liste;
}

Alıntı:

>

zafer@debian:~/DProjeler/TestD$ dmd -w main.d
zafer@debian:~/DProjeler/TestD$ ./main
satir1 : Book:Defter -> adresi1 : F752EFD0 -> ptr1: F752EFD0
satir1 : Table:Masa -> adresi1 : F752EFD0 -> ptr1: F752EFD0
satir1 : Pencil:Kalem -> adresi1 : F752EFD0 -> ptr1: F752EFD0
satir1 : Door:KapI -> adresi1 : F752EFD0 -> ptr1: F752EFD0
satir1 : Blue:Mavİ -> adresi1 : F752EFD0 -> ptr1: F752EFD0
satir1 : Dog:Köpek -> adresi1 : F752EFD0 -> ptr1: F752EFD0
ListeHazirla_ForeachKullan metodu ile elde edilen liste:
Soru : Dog:Köpek

Soru : Dog:Köpek
Soru : Dog:Köpek
m
Soru : Dog:Köpe
Soru : Dog:Köpek
Soru : Dog:Köpek
zafer@debian:~/DProjeler/TestD$

"Bilmemek ayıp değil, öğrenmemek ayıp!" sözünü benimsemiş birisi olarak belki basit gelecek ama anlamadığım bazı noktaları hatta hepsini :) sormak istiyorum. Benim kafam biraz karıştı, anladıklarımı bir yazayım yanlışlar varsa düzeltelim.

Öncelikle ByLine() yapısı içindeki yapılan işlemler sonucunda dosyadan bir satır okunuyor ve bu satır bilgisini kendi üye değişkeni olan line üzerinde depoluyor. Ardından isteyen kişiye bunu gönderiyor. Gönderiyor ama gönderdiği bir char[] dizisi olduğu için aslında bilgiyi değil bu bilgiye erişim sağlayacak bir referans gönderiyor. Bundan dolayı foreach'in satır değişkeni (gerçekte böyle olmasada) bir referans değişkeni gibi davranmaya başlıyor. Burada satir.ptr değerinden hareketle tüm satırların aynı adresi göstermesi buna bir kanıt olabilir mi?

Durum böyle olsa bile bu liste dizisi ile ilgili sorunu açıklamıyor. Neden? Çünkü çıktıda da görüldüğü gibi adresler aynı olsada aslında her düngüde dosyadan istediğimiz satır bilgisini alıyoruz ve bu bilgi çıktıda da doğru görünüyor. Buradan hareketle aslında ben liste dizisine her defasında doğru değeri ekliyorum diye düşünüyorum, haklı mıyım? Eğer durum böyleyse, yani liste dizisinin her elemanı doğru ise nasıl oluyorda en son eleman dizinin tüm elemanlarına ulaşıp kendisi ile değiştiriyor. Bu kısmı bir türlü anlamadım.

File konusuna ayrıca gelicem, bu konu kafamı çok karıştırdı :)

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

October 24, 2011

http://www.zafercelenk.net/dizi.png

Eğer resimdeki gösterim doğruysa sorun yok aksi taktirde halimiz yaman :-D

Bu konuya fena takıldım ama yazdığın mesaj oldukça açıklayıcı ve güzel ama hala durum kafamda tam olarak netleşmedi. Anladıklarımı yazıyorum yanlışları düzeltirsen bu iş tamam sanırım.

Öncelikle benim kafamın esas takıldığı mesele, ben dizimin (liste) elemanını oluşturduktan ve değerini yazıp sonraki elemana geçtikten hatta 4,5 eleman ekledikten sonra nasıl olupta diziye eklenmiş bu değerlerin geriye dönüp değiştirilebildiği noktasında karışmıştı. Ben dinamik dizi içinde aynı sabit dizi gibi değerler olduğunu düşünüyordum ama aslında sadece referanslar var. Eğer durum böyleyse herşey zaten apaçık ortada öyle değil mi?

Alıntı (Başka Dizi Olanakları):

>

Buradaki önemli nokta, o dilimlerin kendilerine ait elemanlarının bulunmuyor olmasıdır. Onlar asıl dizinin elemanlarına erişim sağlarlar. Bir dilimdeki bir elemanın değiştirilmesi asıl dizideki asıl elemanı etkiler.

Sanırım bu durumda dinamik dizi veya daha doğrusu dilim gerçekte bu elemanlara zaten hiçbir zaman sahip olamıyor o sadece line olarak bildiğimiz bölgeye erişim sağlıyor. Dolayısıyla line değerindeki değişim dilimi etkiliyor. Benim anlayamadığım önceki değerler nasıl değişiyor durumu ise aslında otomatikman ortaya çıkıyor. Yukarıdaki resimde de görüldüğü üzere aslında dilime yeni parçalar ekleniyor ama bunlar gerçek değerin referansları olduğu için değerler değiştikçe dilimin referanlarıda bundan etkileniyor. (Daha doğrusu refere ettiği değeri gösterdiği için tüm dilimler aynı anda değişiyor) Dolayısıyla ikinci mesajında belirttiğin gibi uzunluk değiştiğinde tekrarlayan değerin değişmeside sanırım refere edilen line değişkeninin adresin değişmesinden (uzunluktan dolayı artık eski yerine sığmıyor?) kaynaklanıyor?

Bunları yazıp okuduktan sonra dinamik diziler, aslında dilimler hakkında hiç bir şey bilmediğimi anladım. Eğer bunlar doğruysa olayın aslında çok karışık olmadığınıda farkettim, herşeye rağmen keşfetmek ve kavramanın keyfi başka bir keyif yardımların için çok teşkkürler Ali.

Bu arada bende senin gibi çizim yapmaya çalıştım ama beceremedim. Bende bir resim programında yapıp ekledim. Yoksa resim konusunda senin çalışmalarını keyifle izliyorum :-D

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

October 24, 2011

Alıntı (zafer:1319272041):

>

Öncelikle ByLine() yapısı içindeki yapılan işlemler sonucunda dosyadan bir satır okunuyor ve bu satır bilgisini kendi üye değişkeni olan line üzerinde depoluyor.

Doğru.

Alıntı:

>

Ardından isteyen kişiye bunu gönderiyor.

Evet. ByLine bir InputRange olduğu için de foreach perde arkasında front()'u çağırıyor ve foreach'in 'satir' değişkeni olarak bize veriyor.

Alıntı:

>

Gönderiyor ama gönderdiği bir char[] dizisi olduğu için aslında bilgiyi değil bu bilgiye erişim sağlayacak bir referans gönderiyor.

Doğru. Diziler referanstırlar. Asıl bilgi D çalışma ortamı (runtime) tarafından sahiplenilmiştir; diziler ona erişim sağlarlar.

Not 1: Dizi diyoruz ama aslında dilim demek daha doğru.

Not 2: 'line' dinamik bir dizi olduğu için asıl bilginin D çalışma ortamı tarafından sahiplenilmiş olduğunu söylüyoruz. Sabit uzunluklu dizi olsa bilgiye dizinin kendisinin sahip olduğunu düşünmek doğru olur.

Alıntı:

>

Bundan dolayı foreach'in satır değişkeni (gerçekte böyle olmasada) bir referans değişkeni gibi davranmaya başlıyor.

Doğru.

Alıntı:

>

Burada satir.ptr değerinden hareketle tüm satırların aynı adresi göstermesi buna bir kanıt olabilir mi?

satir.ptr değerlerinin aynı çıkması hepsinin ilk karakterlerinin aynı yerde bulunduğunu gösterir. (Ama örneğin dizilerin aynı olduklarını göstermez; çünkü uzunlukları farklı olabilir.)

Alıntı:

>

Durum böyle olsa bile bu liste dizisi ile ilgili sorunu açıklamıyor. Neden? Çünkü çıktıda da görüldüğü gibi adresler aynı olsada aslında her düngüde dosyadan istediğimiz satır bilgisini alıyoruz ve bu bilgi çıktıda da doğru görünüyor. Buradan hareketle aslında ben liste dizisine her defasında doğru değeri ekliyorum diye düşünüyorum, haklı mıyım?

Dosyadan her okuduğunda 'line' gerçekten de son okunan satırı içerir. Sen listeye eklediğinde de gerçekten son satırı eklersin. Ama dikkat edersen 'line' ve senin liste elemanın aynı bilgiyi paylaşıyorlar. Bu bir paylaşım olduğu için 'line' bilgiyi değiştirdikçe liste elemanlarının eriştirdiği veriler de değişmiş oluyor.

Alıntı:

>

Eğer durum böyleyse, yani liste dizisinin her elemanı doğru ise nasıl oluyorda en son eleman dizinin tüm elemanlarına ulaşıp kendisi ile değiştiriyor. Bu kısmı bir türlü anlamadım.

Çünkü tek veri var ve o veri son okunan satırı içeriyor. Ancak, senin verilerinin uzunluklarının birbirlerine bu kadar yakın olmaları da akıl karıştıran önemli bir unsur. Derinlemesine incelemedim ama ByLine readln'ı kullanıyor. readln da sanıyorum bir eniyileştirme olarak eğer satırda zaten yer varsa öncelikle oraya yazıyor.

Olayı daha basit bir kodla görelim. Kısa olsun diye yalnızca iki satır olsun:

'Book:Defter
Table:Masa'

import std.stdio;

void main()
{
   string[] liste;

   // --- Birinci satır ---
   char[] line = "Book:Defter".dup;
   string satir_0 = cast(string)line;
   liste ~= satir_0;   /* Ayrıca not: Önce uzunluğu arttırıp sonra '= satir'
                          yapmak yerine ~= daha kısa ve bence açık. */

   // --- İkinci satır ---
   //
   // "Table:Masa" için 'line'da yer olduğu için teker teker var olan
   // karakterlerin üstüne yazılıyor. Bu iş için bir C sistem kütüphanesi
   // kullanıyor olabilirler ama sonuçta tahminim doğruysa 'line'ın var olan
   // karakterlerinin yerine yeni satırın karakterleri geliyor
   assert(line.length >= "Table:Masa".length);
   foreach (i, karakter; "Table:Masa") {
       line[i] = karakter;
   }
   // Ve o işlemin sonucunda 'liste' bozuldu bile:
   writeln(liste);
}

Çıktısı:

'["Table:Masar"]'

satir_1'i de listeye ekleyen üç kod satırı daha ekleyerek devam edelim:

   foreach (i, karakter; "Table:Masa") {
       line[i] = karakter;
   }
   line.length = "Table:Masa".length;
   string satir_1 = cast(string)line;
   liste ~= satir_1;

Şimdiki çıktısı:

'["Table:Masar", "Table:Masa"]'

Dikkat edersen dizinin ilk elemanı hâlâ "Book:Defter"in son r'sini de görüyor.

Şu anda elimizde 'line' ve 'liste' açısından ne bulunduğunu çizeceğim:

'

veri: Table:Masar
^
|
line: |
ptr ---------|
length==10 |
|
liste |
======== |
eleman0: |
ptr --------|
length==11 |
======== |
eleman1: |
ptr --------
length==10
'

Yani sanıyorum bu iş aslında readln'ın 'line'ın karakterlerinin başkaları tarafından paylaşıldığından haberinin olmamasından kaynaklanıyor. Bunun bir eniyileştirme olduğunu düşünebiliriz; kopyalanması gerekmiyorsa bellekten boş yere yeni yer ayrılması gerekmiyor.

Bu arada, şu tür dönüşümü bana sağlam gelmedi:

satir1 = cast(string)satir;

Değişebilen bir diziyi "bunun karakterlerinin artık değişmeyeceğinden eminim" diyerek string'e dönüştürmek doğru değil. Burada yaşadığımız sorunda da olduğu gibi, 'satir'ın sahibi onun karakterlerini değiştirdiğinde satir1 de değişmiş olur.

import std.stdio;

void main()
{
   char[] değişebilen;
   değişebilen ~= "abc";

   // Güvensiz tür dönüşümü!
   string değişmez = cast(string)değişebilen;

   değişebilen[0] = 'A';  // KÖTÜ: değişmez de değişir!
}

Bence burada en iyisi .idup kullanmak. Zaten o zaman bütün sorun da ortadan kalkar:

   satir1 = satir.idup;

Not: Benim önerdiğim cast güvensiz değil, çünkü o cast split'in üreterek döndürdüğü sonuca uygulanıyordu:

string[] soru = cast(string[])split(satir.dup, ":");

Üstelik satir.dup ile kopyasını da aldığımız için split'e verilen o kopyanın da değiştirilmediğini kendimiz biliyoruz. Böyle kesinlikle emin olduğumuz durumlarda değişebilen türlerden immutable'a dönüşüm yapabiliriz.

Tabii ByLine da döndürdüğü değeri hiç değiştirmeyeceğini belgelemiş olsaydı o zaman tür dönüşümü kullanabilirdik.

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

October 24, 2011

Bir önceki mesajımda, gördüğümüz sonucun satır uzunluklarının yakın olmalarına da bağlı olduklarını söylemiştim.

Senin son programını kullanarak bu sefer şu data.txt dosyası ile deneyelim:

'
Book:Defter
Table:Masa
Pencil:Kalem
Door:KapI0123456789
Blue:Mavİ
Dog:Köpek
'

Door'lu satırdan önceki satırlar 'line'a sığabiliyorlar. Ama Door'a gelince readln yeni satırın sığamayacağını anlıyor ve 'line' için yeni bir yer ayrılıyor. O yüzden programın yeni çıktısı şöyle:

'Soru : Pencil:Kale
Soru : Pencil:Kal
Soru : Pencil:Kalem
Soru : Dog:Köpek
23456789
Soru : Dog:Köpek
Soru : Dog:Köpek
'

Yani baştaki satırlarla sonraki satırların .ptr'ları artık aynı değil.

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

October 24, 2011

Söylediklerinin hepsi doğru! Sonunda anlaştık. :)

Teknik olarak biraz ağır olabilir ama şu makale perde arkasında neler olup bittiğini çok iyi açıklar (çevirisi bazı yerlerde kötü; elim değdikçe daha akıcı hale getireceğim):

http://ddili.org/makale/d_dilimleri.html

Alıntı (zafer):

>

resim konusunda senin çalışmalarını keyifle izliyorum

Ben elle çiziyorum ama Emacs'te o iş aslında çok daha kolay: :)

http://www.cinsk.org/emacs/emacs-artist.html

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

October 24, 2011

Alıntı (acehreli):

>

Söylediklerinin hepsi doğru! Sonunda anlaştık. :)

Ali, biz seninle her zaman anlaşırız :) Mühim olan olayları kavramak işin keyifli kısmı burada saklı.

Diğer taraftan aklıma şöyle bir soru takıldı. Dizinin elemanları birer referans ise ve refere ettikleri değişkenin tanımlandığı blok çalışıp sonlanmışsa yani değişken artık ömrünü tamamlamışsa dizi bu değerlere nasıl ulaşıyor? Gerçi bunun için aklıma şöyle bir açıklama geliyor ama emin değilim.

Alıntı:

>

Doğru. Diziler referanstırlar. Asıl bilgi D çalışma ortamı (runtime) tarafından sahiplenilmiştir; diziler ona erişim sağlarlar.

Seninde söylediğin gibi bilginin sahibi D çalışma ortamı ise sanırım diziden erişim olduğu sürece normalde değişkenin ömrü sona ermiş olsa bile onu kullanmaya izin veriyor ama bu gerçekten böyle mi?

Ayrıca dinamik dizi yerine sabit uzunluklu bir dizi ile bu durumu denedim aynı durum sabit uzunluklu dizide de bu şekilde oluyor. Bu durumda D dizilerinin elemanları içerisinde hep referanslar mı bulunuyor?

import std.stdio;

void main()
{
	int[2] dizi;

	int[0] = 5;
	int[1] = 6;
}

Örneğin yukarıdaki tanımda D çalışma ortamı 5 ve 6 değerleri için bellekte birer alan ayırıp bu değeleri içlerine yerleştirdikten sonra dizinin 0 ve 1. indeksine bunların referanlarını mı aktarıyor acaba? Çok detay sorular sorup senide bunaltmak istemiyorum ama temel sağlam olmadan üzerine inşa edilenlerden de bir fayda olmayacağını düşünüyorum.

Alıntı:

>

http://ddili.org/makale/d_dilimleri.html

Eline sağlık bence güzel bir çeviri olmuş, o yazıyı bir kaç defa okudum. Yinede tekrar okuyacağım :)

Alıntı:

>

Ben elle çiziyorum ama Emacs'te o iş aslında çok daha kolay: :)
http://www.cinsk.org/emacs/emacs-artist.html

Gerçekten insnalar neler yapmışlar, açıkcası fikre hayran kaldım. ASCII karekterlerle çizim işlemlerini düşünmek ve gerçekleştirmek, tebrik ediyorum. Bu arada bu gidişle bende IDE'leri bırakıp Emacs'a geçecem, ne ararsan var :)

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

October 25, 2011

Alıntı:

>

Dizinin elemanları birer referans ise ve refere ettikleri değişkenin tanımlandığı blok çalışıp sonlanmışsa yani değişken artık ömrünü tamamlamışsa dizi bu değerlere nasıl ulaşıyor?

Bizim dilim yaşadığı sürece o elemanlar geçerlidirler. Bu, benim çok iyi bilmediğim çöp toplayıcı teknolojisi ile ilgili bir konudur. Çöp toplayıcı arada bir programın belleğini tarayarak artık hiçbir yerden erişilmeyen bellek bölgelerini daha sonra kullanılmak üzere boş olarak işaretler.

Dilim yaşadıkça bizim elemanlar geçerlidir. Aslında her ne kadar çalışma ortamı tarafından sahiplenildiğini söylüyorsak da, dolaylı olarak o elemanların sahipliğinde bizim dilimin de payı oluyor.

Alıntı:

>

diziden erişim olduğu sürece normalde değişkenin ömrü sona ermiş olsa bile onu kullanmaya izin veriyor

Evet.

Alıntı:

>

sabit uzunluklu bir dizi ile bu durumu denedim aynı durum sabit uzunluklu dizide de bu şekilde oluyor. Bu durumda D dizilerinin elemanları içerisinde hep referanslar mı bulunuyor?

Hem evet, hem hayır. :)

void main()
{
   int[2] a;
   int[2] b = a;       // a'nın elemanlarının kopyasıdır

   a[0] = 42;          // yalnızca a değişir

   assert(b[0] == 0);  // b etkilenmemiştir
}

Dün konuştuğumuz konuda sabit uzunluklu dizileri unuttuğumu farkettim. Bu program C'deki diziler gibi sonuç veriyor:

import std.stdio;

void main()
{
   int[2] a;

   writeln("&a   : ", &a);
   writeln("a.ptr: ", a.ptr);
   writeln("&a[0]: ", &a[0]);
}

Çıktısında üç adres de aynı:

'&a : 7FFF55552308
a.ptr: 7FFF55552308
&a[0]: 7FFF55552308
'

Çünkü sabit uzunluklu dizilerde dilimlerde olduğu gibi ptr ve length'ten oluşan ayrıca bir nesne yoktur.

Senin programının satırlarına numara yerleştirerek her satırdan sonraki durumda belleğin nasıl olduğunu çizeceğim:

Alıntı:

>
> import std.stdio;
>
> void main()
> {
>     int[2] dizi;  // (1)
>
>     int[0] = 5;   // (2)
>     int[1] = 6;   // (3)
> }
> ```


'
            --+--------+--------+--
(1)            |    0   |    0   |
            --+--------+--------+--

            --+--------+--------+--
(2)            |    5   |    0   |
            --+--------+--------+--

            --+--------+--------+--
(3)            |    5   |    6   |
            --+--------+--------+--
'

Yani ayrıca 'dizi' diye nesne yok. 'dizi', C ve C++'ta da olduğu gibi o iki int'in kendileri anlamına geliyor. (Ama çok büyük bir fark, D'nin sabit uzunluklu dizileri her zaman için değer türüdür. Örneğin C ve C++'ta olduğu gibi işlevlere *ilk elemanlarının adresi* olarak gönderilmezler; her zaman için kopyalanırlar.)

sizeof da bilgilendirici oluyor:


import std.stdio;

void main()
{
int[1000] sabit;
int[] dilim;
dilim.length = 1000;

writeln(sabit.sizeof);
writeln(dilim.sizeof);
}



Çıktısı:

'4000
16'

Anlaşılan, benim ortamım 64 bitlik olduğundan hem ptr hem de length 8 baytlıkmış. O yüzden eleman adedinden bağımsız olarak dilim'in büyüklüğü hep 16 bayt.

Alıntı:
> Örneğin yukarıdaki tanımda D çalışma ortamı 5 ve 6 değerleri için bellekte birer alan ayırıp bu değeleri içlerine yerleştirdikten sonra dizinin 0 ve 1. indeksine bunların referanlarını mı aktarıyor acaba?

Yukarıda göstermeye çalıştığım gibi, dizi için tek bir yer ayırıyor. 5 ve 6 değerleri için ayrıca yer ayrılmıyor. Her atama için mikro işlemciye tek emir verilir (sözde bir makine kodu kullanarak):

* sevgili mikro işlemci, şu bellek adresine 5 değerini yaz

Bunu dmd'nin ürettiği makine kodunda görebiliriz. Makine kodunda değerler normal olarak onaltılı düzende oldukları için ayırt edebilmek için özel değerlerle şu programı kullanalım:


import std.stdio;

void main()
{
int[2] dizi;
dizi[0] = 0x1111_1111;
dizi[1] = 0x2222_2222;
writeln(dizi);
}



Konsolda dmd ve onunla gelen obj2asm programıyla (umarım obj2asm Windows'da da vardır; ve varsa, deneme.o değil deneme.obj yazmak gerekir):

'$ dmd deneme.d -g
$ obj2asm deneme.o > makine_kodu'

Şimdi makine_kodu isimli dosyayı açıp "_Dmain:" ile başlayan satıra gidiyoruz:

'_Dmain:
		push	EBP
		mov	EBP,ESP
		sub	ESP,8
		lea	EAX,-8[EBP]
		xor	ECX,ECX
		mov	[EAX],ECX
		mov	4[EAX],ECX
		mov	dword ptr -8[EBP],011111111h
		mov	dword ptr -4[EBP],022222222h
		push	dword ptr -4[EBP]
		push	dword ptr -8[EBP]
		call	  _D3std5stdio16__T7writelnTG2iZ7writelnFG2iZv@PC32
		xor	EAX,EAX
		leave
		ret
		nop
		nop
		nop
text._Dmain	ends
'

Yukarıdaki bölüm bizim main() içine yazdığımız kodun derlenmiş halidir. Programa yazdığımız hazır değerleri hemen tanıyoruz: 'mov dword ptr -8[EBP],011111111h' komutunun anlamı, "sevgili mikro işlemci, 011111111h değerini EBP yazmacından 8 adres önceye yerleştir" demek. (Yani 'dizi', EBP yazmacından 8 bayt gerideki bellek bölgesiymiş.)

Aynısını dilimlerle denediğinizde işlerin çok daha karmaşık olduğunu göreceksiniz.

Alıntı:
> ASCII karekterlerle çizim işlemlerini düşünmek ve gerçekleştirmek, tebrik ediyorum.

Böyle çizimlerin o karakterlerle başladığını unutmayalım. :)

Ali

-- 
[ Bu gönderi, <http://ddili.org/forum>'dan dönüştürülmüştür. ]
October 25, 2011

En azından sabit dizilerin hala hatırladığım gibi çalıştığına sevindim :)

Alıntı:

>

Konsolda dmd ve onunla gelen obj2asm programıyla (umarım obj2asm Windows'da da vardır; ve varsa, deneme.o değil deneme.obj yazmak gerekir):

Sanırım obj2asm veya muadili bir programı windows platformu için bulmak zor olmaz. Ancak bende D ile olan çalışmalarımı çoğunlukla Debian 6 üzerinde gerçekleştiriyorum. Bırakalım obj2asm sorununu sadece windows ile çalışanlar düşünsün ;-)

Doğrusu bir soru daha yazmaya korkuyorum sanırım bundan sonra transistörlere doğru gidip olayı ikili kod düzeyinde incelemeye başlayacağız :-D

Ali hoşgörün ve yardımın için tekrar teşekkürler, doğruyu söylemek gerekirse kafamda her şey tam olarak netleşdi diyemem ama büyük oranda sisler dağıldı.Sanırım D'nin diilmleri ile daha fazla pratik yapmam gerekecek.

Not: Bu arada şu "sevgili mikro işlemci..." şeklinde başlayan anlatımları seviyorum. Anlatımlarda mikro işlemci ve diğerlerine olan sevgimizi belirterek olaya sevgi katıyoruz ya anlatım daha iyi oluyor. :-D Biraz derin ve felsefi bir konu sanırım :-D :-p

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

« First   ‹ Prev
1 2