Emrah Porgalı
emrah@csharpturk.net

while Döngüsü

01 Şubat 2007

Programlama gerçekten de tekrarlamadan ibarettir. Bizler nadiren sadece bir kez çalışan programlar yazarız. Yazdığımız çoğu program bir kez çalışır ve her çalışmasında hemen hemen aynı şeyi tekrarlar. Ancak her çalışmada doğru sonucu oluşturacak kadar ufak farklar vardır. Sıklıkla, bir programın içinde bile tekrarlamalar bulunur. Tabi yine ufak farklarla. Bu da bizim bu makalede inceleyeceğimiz konu. C# dili özellik olarak tekrarlama durumlarını icra eder. Biz bu tekrarlama durumlarına Döngü deriz.

Yeni kiraladığımız bir evin kirasının 1000 YTL olduğunu varsayalım. Ve her yıl kirayı %5 arttıracağımızı düşünelim. Önümüzdeki 10 yıl içinde vereceğimiz kira miktarının ne olacağını hesaplayan bir program yazalım.

using System;

class KiraHesabi
{
    static void Main()
    {
        decimal Kira = 1000, ArtisMiktari = 5.0m;
        Console.WriteLine("2006 yılındaki kira={0} YTL", Kira);
        Console.WriteLine("2007 yılındaki kira={0} YTL", Kira *= (1 + ArtisMiktari / 100));
        Console.WriteLine("2008 yılındaki kira={0} YTL", Kira *= (1 + ArtisMiktari / 100));
        Console.WriteLine("2009 yılındaki kira={0} YTL", Kira *= (1 + ArtisMiktari / 100));
        Console.WriteLine("2010 yılındaki kira={0} YTL", Kira *= (1 + ArtisMiktari / 100));
        Console.WriteLine("2011 yılındaki kira={0} YTL", Kira *= (1 + ArtisMiktari / 100));
        Console.WriteLine("2012 yılındaki kira={0} YTL", Kira *= (1 + ArtisMiktari / 100));
        Console.WriteLine("2013 yılındaki kira={0} YTL", Kira *= (1 + ArtisMiktari / 100));
        Console.WriteLine("2014 yılındaki kira={0} YTL", Kira *= (1 + ArtisMiktari / 100));
        Console.WriteLine("2015 yılındaki kira={0} YTL", Kira *= (1 + ArtisMiktari / 100));
        Console.WriteLine("2016 yılındaki kira={0} YTL", Kira *= (1 + ArtisMiktari / 100));
    }

}

Kopyalama ve yapıştırma mükemmel değil mi? Rakamların alt alta gelmesi için matematik hesabını WriteLine cümlesinin içinde yaptık. Her ifade Kira değişkeninin değerini arttırıyor. 2005 yılı için ifadeyi yazdıktan sonra bu ifadeyi kopyaladım ve 9 kere yapıştırdım ve yılların yazıldığı rakamları değiştirdim. Sonucu aşağıdaki gibi elde ettik.

decimal değişken kullandığımızdan dolayı oluşan fazla haneleri saymasak iyi çalışmış gibi görünüyor. Fakat eminim ki bu programda güzel bir şeylerin eksik olduğuna benle aynı fikirdesiniz. Sadece birkaç yıl için pek fazla kötü görünmüyor. Fakat daha fazla yıl için bir hesaplama yapacak olsak işler kötüye giderdi. Birbirinin aynı koddan sayfalar dolusu istemezsiniz. Ya bu kodları yazdıktan sonra küçük bir yanlışlığa rastlarsanız ne olacak?

Zorlama ile bazı problemler çözmek işe yarayabilir, genellikle döngü kullanmaktan daha kolaydır. C# ‘ta en basit döngü while ifadesidir. else  kısmı olmayan bir if ifadesine  çok benziyor. while anahtar kelimesini bir parantezler içerisindeki bir boolean ifade takip eder. Bir çift küme parantezi bir veya birden fazla döngü kodunu takip eder.

while (boolean ifade)
{
    // döngünün içindeki diğer ifadeler
}

while  ile if arasındaki farklar şunlardır:

if cümlesinde eğerboolean ifade doğru (true) ise küme parantezleri arasındaki ifadeleri sadece bir kez çalıştırır. while ise boolean ifadesi doğru olduğu müddetçe küme parantezleri arasındaki ifadeleri çalıştırmaya devam eder. Çalışma boolean ifade yanlış (false) olana kadara devam eder.

Değeri 55 olan bir i değişkeni olduğunu varsayalım. Şimdi bir if cümlesi yazalım

if ( i < 100 )
{
    Console.WriteLine ( i ) ;
}

Sonuç 55 olarak ekrana yazılacaktır.

Aynı ifadeyi while için yazalım.

while ( i < 100 ) 
{
    Console.WriteLine( i ) ;    
}

Bu sefer sonuç aşağıdaki gibi olacaktır:

55
55
55
55
...

Sonsuz döngü olarak bilinen bu döngü devamlı çalışmaya devam edecektir. Fakat genellikle program bitmeden bu sonsuz döngüleri bitirmek isteyeceksin. Program sonsuz döngüye girdiğinde konsol penceresini kapatarak veya "Ctrl +C" tuşlarını kullanarak döngüyü durdurabilirsin. Tabiî ki kesinlikle sonsuz döngü içeren uygulamalar var, fakat çoğu durumda küme parantezinin içindeki kodlar boolean ifadenin içindeki değişkeni değiştirirler.

Şimdi 100’e kadar sayan bir program yazalım.

using System;

class CountUntill100 // 100'e kadar say 
{
    static void Main()
    {
        int i = 0;
        while (i < 100)
        {
            Console.WriteLine(i);
            i++;
        }
        Console.WriteLine("i'nin son değeri:{0}", i);
    }
}

i’nin değeri 100’den küçük olduğundan, işletimin devamında while ifadesine gelindiğinde işletim while ifadesinin küme parantezlerini işleterek ilerleyecek. Küme parantezlerinin içindeki ifade i’nin değerinin yazacak ve değişkeni arttıracak. Ve işletim boolean ifadeye geri dönecek. i hala 100’dem küçük mü? Eğer öyleyse küme parantezinin içindeki ifade tekrar işletilecek. Bu işlemlerin her bir ilerlemesine iteraston (yineleme) adı verilir. Programın çıktısı aşağıdaki gibidir.

Konsol Çıktısı

99 gösterildikten sonra i’nin değeri 100 e arttırılır. Programın devamı boolean ifadeye döner. i’nin değeri 100’den küçük mü? Hayır. Programın işletimi while ifadesinden sonraki program kodu ile devam eder. Şimdi i değişkenin değeri 100’e eşit oldu. En son olarak program "i'nin son değeri 100" yazar.

i’nin değeri 100’e ulaştığında ( veya 100 değerinin üzerine ulaştığında ) küme parantezleri içerisindeki ifadeler işletilmeyecek.

Aşağıda bu programda kullandığımız while döngüsünün başka bir varyasyonu gösterilmektedir.

while ( i < 100 )
{
    i++;
    Console.WriteLine(i);
}

i’nin değeri Console.WriteLine çağrısından önce arttırıldığı için bu döngü 1 den 100 e kadar olan sayıları gösterir. Döngü i değeri 100’e ulaştığında hemen durmaz. WriteLine çağrısından sonra işletim döngünün başına döner ve bundan sonra boolean ifade tekrar kontrol edilir.

Not: Küme parantezleri arasında sadece 1 ifade varsa küme parantezlerini kullanmanıza gerek yoktur.

Şimdi i değişkenin değerini Console.WriteLine çağrısının içinde arttırarak küme parantezlerini kullanma derdinden de kurtulalım.

while ( i < 100 )
    Console.WriteLine(i++);

Sonek arttırma operatörü değişkenin değerini ekranda gösterildikten sonra arttırır. Bu örnekte program 0’dan 99’a kadar sayıları ekranda gösterir. Eğer önek arttırma operatörünü kullanırsak;

while ( i < 100 )
    Console.WriteLine(++i);

değişken ekranda gösterilmeden önce arttırılacak ve program ekranda 1’den 100’e kadar olan sayıları gösterecek.

Aynı zamanda i değişkenini boolean ifadenin içinde de arttırabiliriz. Örneğin;

while ( i++ < 100 )
    Console.WtiteLine(i);

Sonek artırım operatörü i değişkenin değerini boolean ifadede kullanıldıktan sonra, Console.WriteLine çağrısından önce artırıyor. Program ekranda 1’den 100’e kadar sayıları gösteriyor. Aynı ifadenin önekli versiyonu;

while ( ++i < 100 )
    Console.WriteLine(i);

Şimdi ise program ekranda 1’den 99’a kadar sayıları görüntülüyor. i değişkenin değeri 100’e artırıldığında boolean ifaden yanlış döner ve programın işletimi while döngüsünden bir sonraki ifadeden devam eder.

while döngü gövdesindeki bu farkları özellikle vurguluyorum. Problem genellikle while döngüsünün başlangıç ve bitiş sınırlarının yönetiminde ortaya çıkar. boolean ifadedeki değişkeni nerede ve nasıl değiştireceğini dikkatlice belirlemen gerekiyor. Boolean ifadede kullanılan < yerine <= ve > yerine >= ifadelerini de kullanarak döngünün sonunda ek bir döngü sağlayabilirsin.

Şimdi kira hesabı yapan programımızı tekrar yazalım.

using System;

class KiraHesabi
{
    static void Main()
    {
        int BaslangicYili = 2006;
        int BitisYili = 2016;
        decimal Kira = 1000;
        decimal ArtisMiktari = 5.0m;

        while (BaslangicYili <= BitisYili)
        {
            Console.WriteLine("{0} {1}", BaslangicYili, Kira);
            Kira *= (1 + ArtisMiktari / 100);
            Kira = Decimal.Round(Kira, 2);
            BaslangicYili++;
        }
    }
}

Bu hesaplama biraz değişik. Kirayı ve yılı ekrana yazdıktan sonra program gelecek yılın kirasını hesaplıyor ve decimal olarak tanımlanmış kira değerinin virgülden sonraki kısmını 2 basamak kalana kadar yuvarlıyor. Programın çıktısı aşağıdaki gibi olur.

Konsol Çıktısı

Program 2016 yılındaki son kirası hesapladıktan sonra, Kira ve BaslangicYili değerlerini arttırarak bir sonraki döngüye hazırlıyor. Kirayı hiçbir zaman kullanmayacak olmamıza rağmen hesaplıyor. Bu örnekte çok fazla bir yük oluşturmuyor ama daha büyük programlarda problem olabilir.

Programın çıktısına baktığımızda programın 2006 dan 2011 e kadar olanları kiraları hesaplamak için 11 tane WriteLine çağrısı yaptığını fark ederiz. Fakat program bu yıllar arasındaki kiraları hesaplamak için 10 kez hesap yapmaya ihtiyaç duyar. Bunun için while döngüsünün dışında fazladan bir WriteLine çağrısı yaparak bir çözüm oluşturabiliriz.

using System;

class KiraHesabi
{
    static void Main()
    {
        int BaslangicYili = 2006;
        int BitisYili = 2016;
        decimal Kira = 1000;
        decimal ArtisMiktari = 5.0m;

        while (BaslangicYili < BitisYili)
        {
            Console.WriteLine("{0} {1}", BaslangicYili, Kira);
            Kira *= (1 + ArtisMiktari / 100);
            Kira = Decimal.Round(Kira, 2);
            BaslangicYili++;
        }
        Console.WriteLine("{0} {1}", BaslangicYili, Kira);

    }
}

Yeni program çıktısı aşağıda.

Konsol Çıktısı

Dikkat ederseniz boolean ifadede ki içindeki <= karşılaştırmasını < olarak değistirdim. Böylelikle döngünün içinde en son olarak 2015 yılı için hesap yapılacak. Döngünün altındaki WriteLine çağrısı döngünün içinde önceden hesaplanan 2016 yılının kirasını ekrana yazdırıyor.

Bir diğer varyasyon ise Console.WriteLine ile döngüden önce ilk yılı ve kirasını ekrana yazdırıp daha sonra bu değerleri döngünün içinde arttırarak yazma işlemi yapmak. Yani hesaplama döngünün başında yapılıyor ve WriteLine çağrısı döngünün en altında yapılıyor.

using System;

class KiraHesabi
{
    static void Main()
    {
        int BaslangicYili = 2006;
        int BitisYili = 2016;
        decimal Kira = 1000;
        decimal ArtisMiktari = 5.0m;

        Console.WriteLine("{0} {1}", BaslangicYili, Kira);
        while (BaslangicYili < BitisYili)
        {
            BaslangicYili++;
            Kira *= (1 + ArtisMiktari / 100);
            Kira = Decimal.Round(Kira, 2);
            Console.WriteLine("{0} {1}", BaslangicYili, Kira);

        }

    }
}

Yine çıktısı aşağıda görülüyor.

Konsol Çıktısı

Bu iki çözüm de ideal değil çünkü ikisi de birbiri ile aynı WriteLine çağrısı içermektedir. Birini değiştirdiğinde diğerini de değiştirmek zorundasın.

Biz bu örnekte olduğu gibi döngünün içinde 11 WriteLine çağrısı ve 10 kez de hesap yapmak istiyorsak döngünün ortalarında bir yerde döngüden çıkmamız gerekiyor. break olarak adlandırılan ifade ile döngünün ortasında döngüden çıkabilirsin. Bu ifade her zaman aşağıdaki şekilde kullanılır.

break;

break ifadesini noktalı virgül takip eder. Bu ifade kullanıldığında döngüden çıkmaya ve programın döngüden bir sonraki ifadeden devam etmesine neden olur. Genellikle break ifadesi bir if bloğu ile kullanılır.

if ( BaslangicYili == BitisYili )
    break;

Kira hesabının bir diğer versiyonu aşağıdaki gibi yazıldığında gereksiz bir hesaplamadan bizi kurtarır.

using System;

class KiraHesabi
{
    static void Main()
    {
        int BaslangicYili = 2006;
        int BitisYili = 2016;
        decimal Kira = 1000;
        decimal ArtisMiktari = 5.0m;

        while (BaslangicYili <= BitisYili)
        {
            Console.WriteLine("{0} {1}", BaslangicYili, Kira);
            if (BaslangicYili == BitisYili)
                break;

            Kira *= (1 + ArtisMiktari / 100);
            Kira = Decimal.Round(Kira, 2);
            BaslangicYili++;
        }
    }
}

Şimdi while döngüsündeki boolean ifadeyi true kullanarak programın başka bir versiyonunu yazalım. Unutmayın ki break olmadan bu bir sonsuz döngü olacaktır.

using System;

class KiraHesabi
{
    static void Main()
    {
        int BaslangicYili = 2006;
        int BitisYili = 2016;
        decimal Kira = 1000;
        decimal ArtisMiktari = 5.0m;

        while (true)
        {
            Console.WriteLine("{0} {1}", BaslangicYili, Kira);
            if (BaslangicYili == BitisYili)
                break;

            Kira *= (1 + ArtisMiktari / 100);
            Kira = Decimal.Round(Kira, 2);
            BaslangicYili++;
        }
    }
}

break gibi while döngüsü içinde kullanılan bir diğer atlama komutu da continue’dur. Genellikle if karar yapısı ile tetiklenir. Bu ifade döngü içindeki arta kalan ifadenin atlanmasını sağlar. Ve program bir sonraki iterasyondan devam eder.

Örneğin, kira hesabı programımızda sonu 0 ile biten yıllarda kiranın artmamasını yani bir önceki yıl ile aynı kalmasını istediğimizi farz edelim. Yani 2010 yılında ki kiranın 2009’daki kira ile aynı kalmasını istediğimizi düşünelim.

Şimdi bir önceki yazdığımız orijinal koda bir bakalım.

while ( BaslangicYili<=BitisYili )
        {
            Console.WriteLine("{0} {1}", BaslangicYili,Kira);
            
if ( BaslangicYili == BitisYili )
                break;
            
            Kira *= ( 1 + ArtisMiktari/100);
            Kira = Decimal.Round(Kira,2);
            BaslangicYili++;
        }

Bu kodu sihirli 2010 yılı için if ifadesi ile yazmanın bir yolu aşağıdaki gibi olabilir.

while ( BaslangicYili<=BitisYili )
        {
            Console.WriteLine("{0} {1}", BaslangicYili,Kira);
            
if ( BaslangicYili != BitisYili )
            {                
                Kira *= ( 1 + ArtisMiktari/100);
                Kira = Decimal.Round(Kira,2);
            }
            BaslangicYili++;
        }

if ifadesi 2009 yılının kirası gösterildikten sonraki artışları engeller. Bu nedenle de 2009 ile 2010 yılları arasıdan kira artışı meydana gelmez. Bu işlemi aynı zamandan if ile birlikte continue

while ( BaslangicYili<=BitisYili )
        {
            Console.WriteLine("{0} {1}", BaslangicYili,Kira);
            BaslangicYili++;


if ( BaslangicYili ==2010 )
                continue;
                
            Kira *= ( 1 + ArtisMiktari/100);
            Kira = Decimal.Round(Kira,2);
        }

BaslangicYili değişkenin artırılmasını döngünün başına aldım ve if ifadesini bunun devamına yazdım. Eğer BaslangicYili değişkeni 2010’a ulaşırsa continue ifadesi döngünün bir sonraki iterasyondan devam etmesini sağlayacak. Döngünün için deki son iki ifade bu şekilde atlanmış oluyor.

while döngüsünün bir diğer çeşidi de do döngüsü. while  döngüsünün genel ifadesini bir kez daha hatırlayalım.

while ( boolean ifade )
{
    // while döngüsünün gövdesi
}

Şimdide do döngüsünün genel ifadesini tanıyalım. do döngüsü aynı zamanda while komutunu da içeriyor.

do
{
    // do döngüsünün gövdesi
{
while ( boolean ifade );

do döngüsün en sonunda noktalı virgül olduğuna dikkat edin. while döngüsünde olduğu gibi do döngüsünde de break ve continue ifadelerini kullanabilirsin.

do döngüsünün yapısı boolean ifadeyi döngünün başında değil de sonunda değerlendirir. do döngüsünde gövde boolean ifadeyi dikkate alınmadan en az kez çalışır.

do döngüsü kullanıcıdan giriş alan programlarda kullanışlıdır. Şimdi toplama yapan basit bir program yazalım.

using System;

class TopamaProgrami
{
    static void Main()
    {
        string Cevap;

        do
        {
            Console.Write("Birinci sayıyı gir: ");
            double d1 = Double.Parse(Console.ReadLine());

            Console.Write("ikinci sayıyı gir: ");
            double d2 = Double.Parse(Console.ReadLine());

            Console.WriteLine("Toplam : {0}", d1 + d2);

            Console.WriteLine("Başka bir toplama yapmak ister misin?(e/h)");
            Cevap = Console.ReadLine().Trim();

        } while (Cevap.Length > 0 && Cevap.ToLower()[0] == 'e');
    }
}

Buradaki string tipindeki Cevap değişkeni neden while bloğu içinde tanımlanmadı diye düşünebilirsiniz. Bunun nedeni; değişkenin bloğun altındaki while ifadesinin içindeki boolean ifadenin içinde kullanılmasıdır.

Bu programın anahtar kısmı do döngüsünün altına yakın yerde ortaya çıkar. Buradaki bir komut kullanıcıya bir tane daha hesaplama yapıp yapmayacağını sorar ve string tipindeki Cevap değişkeni bu cevabı saklar. while ifadesinin içindeki boolean ifade ilk önce Cevap değişkenin uzunluğunun 0’dan büyük olup olmadığını kontrol eder. Eğer öyleyse Cevap değişkenin büyük harflerle yazılmış olmasına karşın değişken küçük harflere çevriliyor ve ilk harfinin ‘e’ olup olmadığına bakıyor. Eğer ilk karakter ‘e’ ise programın işletimi döngünün en başına dönecek ve oradan devam edecek.

boolean ifadenin içindeki Cevap.Length ifadesi kullanıcın sorulan soruya karşılık olarak basitçe enter tuşuna basıp basmadığını kontrol etmek için kullanılıyor. Eğer kullanıcı cevap için sadece enter’e basmış ise Console.ReadLine boş bir string döndürecektir ve bu string’in ilk karakterine ulamaya çalışmak  kural dışı bir durum oluşturacaktır. Kullanıcı ‘Y’ veya ‘y’ ile başlayan bir şeyler yazdığında ki yazdıklarında boşluk bıraksa bile program devam edecek. Kullanıcıdan cevabını istediğimizde kullandığımız Trim() fonksiyonu boşluklardan kurtulmamızı sağlıyor.
Tabiî ki program eğer kullanıcı bizim sorduğumuz iki komuta doğru yanıtları vermez ise yani sayıları istediğimiz ve cevabı istediğimiz komutlara diğer tipler değişkenler yazarsa program hata verecektir. Bu hataları nasıl halledeceğimizi başka bir makalede anlatacağız.

Bazen aşağıdaki gibi hatalar yapabiliriz.

while ( i < 100 )
{
    // diğer ifadeler
}
while ( i < 101 )

Bu örnekte ilk önce bir while ifadesi yazıyoruz. Daha sonra do döngüsü oluşturduğumuzu düşünüp döngünün sonuna bir while daha yazıyoruz.

while ( i < 100 )
{
    // diğer ifadeler
}

Yukarıdaki kısımda i değişkeni döngü bittiğinde muhtemelen 100 değerini alacak olduğundan ikinci kısımdaki

while ( i < 101 )

ifadesi sonsuz bir döngü olacak. Bu program asılı kalacakmış gibi görünüyor. Ve muhtemelen bir çıktı da görüntülenemeyecek.

Ne zaman bir konsol programı asılı kalırsa ctrl+c tuşlarını kullanarak programı durdurabilirsin. Bundan sonra kaynak kodunu tekrar incelemeli ve sonsuz döngü nerede oluşuyor bulmaya çalışmalısın. Eğer kodunda bununla ilgili bir kanıt bulamıyorsan while döngüsünün başına ve sonuna birkaç tane “Burası döngünün girişi”, “Döngü bitiyor” gibi ifadeler içeren WriteLine çağrısı koyabilirsin. Böylelikle programı çalışırken inceleyebilirsin. Bu şekilde fazladan ihtimalleri sınırlamış olursun.

Döngülerin bir diğer yaygın kullanım alanı da dizilerle birlikte kullanımıdır. Şimdi önceden girilen bir sayı dizisinin sayılarının karelerini ve küplerini bula bir programı while döngüsü ile yapalım.

using System;
class KareKub
{
    static void Main()
    {
        int[] SayiDizisi = {10,11,12,13,14,15};
        
        int i = 0 ;
        
        while ( i < SayiDizisi.Length )
        {
Console.WriteLine("{0} {1,6} {2,6} " ,SayiDizisi[i], Math.Pow(SayiDizisi[i],3), Math.Pow(SayiDizisi[i],3));
            i++;
        }
    }
}

Burada girilen sayı dizisin içindeki sayıları karelerini ve küplerini alan bir programı yazdık. Dizinin eleman sayısı kadar dönen bir döngü oluşturduk. Programın çıktısı da aşağıdaki gibi oluşuyor

Konsol Çıktısı

Yorum Yaz

 
Ad  
Eposta     E-posta isteğe bağlıdır.
Yorum  
  Gönder       Temizle

Bu Makale İçin Yazılan Yorumlar

selcuk
05.07.2010
güsel bir makale tesekkurler
duygu kulaç
19.04.2010
ya o kadar program yazdik bunun gibisini daha hic gormedim ama cok guzel olmus
cem
02.01.2010
gerçekten harika bir paylaşım ..teşk.
Joe MARK
06.08.2009
Arkdaşım harika bir anlatım hoş güzel ama site tasarımı iyi değil sağ tarafta bulunan menüyü bırazdaha yana alsaydın yazıları eksiksiz görebilirdik umarım dikkate alırsın tekrardan teşekkür ederim anlatımın için iyi çalışmalar
ercan ferdan
06.04.2009
While dögüsünde yazdığımız sayılardan tek olanları toplamak istersen nasıl yapacağız? Yardım ederseniz sevinirim. Teşekkürler...
GÜLŞAH
19.03.2009
ÖNCELİKLE BİLGİLER İÇİN ÇOK TEŞEKKÜRLER NETRON'A EĞİTİME
GİDİYORUM İNANIN ŞU MANTIĞIN
%1'İ KAVRATILAMIYOR.ÇOK TEŞEKKÜRLER.
dilber
04.01.2009
emeğiniz için çok teşekkürler
solaktrk
14.07.2008
Slm. Tek kelimeyle harika. Benim istediğim bu şekilde açıklayıcı ve net bilgilerdi. Konu ile ilgili yerli ve yabancı kitapları okuyorum ama sizin anlatımınız arayıpta bulamadığım bir anlatım tarzıydı. Ben C# çalışmaya yeni/yeniden başladım. Bizim Türk kullanıcılar için bu tür kaynak sıkıntısı var mevcut kaynaklarda açık seçik değil sanki suya yazı yazmak gibi. Çünkü bizim algılama ve yorumlama işinde beynimiz farklı çalışıyor :) buda eğitim sistemimizden kaynaklanıyor olmalı... Beni gerçekten etkileyen bu anlatım için teşekkür eder çalışmalarınızın devamını dilerim.