Döngü Yapısı (Loop) – For, While, Do while
Döngüler belirli kod bloklarını tekrar etmek için kullanılır. Döngü yapılarının en temel kullanım şekli, tekrar tekrar çalıştırılması gereken (mesaj panoları gibi) karmaşık kodları sizin için tekrar tekrar çalıştırır. Az sayıda görev yürütüyor olabilirler, ancak ilke olarak, mesajların bir listesini oluşturmak sadece bazı verilerin okunması işleminin tekrar edilmesini ve gösterilmesini gerektirir. Şimdi bunun ne anlama geldiğini düşünün: Döngüler, yazılan çok basit seviyedeki kodların, tekrar çalıştırılmasını sağlayarak, çok büyük çıktılar üretmesine olanak tanır.
Ufak bir uyarı: Başlamadan önce C’nin kendi doğru (true) ve yanlış (false) kavramlarını anlamış olmalısınız. Bir önceki Koşullu ifadeler (If statements) yazısında bunlar anlatıldı. Ortada üç çeşit döngü yapısı var, bunlar: for, while ve do..while. Herbirinin kendine has kullanım şekilleri var.
FOR LOOP (for döngü yapısı)
for döngüleri en çok kullanılan tiptir. for döngüsünün imlası (syntax) şu şekildedir:
for ( değişken başlatma; koşul; değişken güncelleme ) { Koşul doğru ise çalıştırılacak kodlar }
Değişken başlatma, bir değişkeni tanımlamanıza ve ona bir değer vermenize veya mevcut bir değişkene değer vermenize izin verir. İkinci kısım olan koşul, doğru olduğu sürece programın kod bloğu tekrar tekrar çalıştırılacaktır. Değişken güncelleme, for döngüsünün değişkeninin en kolay değiştirildiği kısımdır. Şu tarz kullanımlara izin verir: x++, x = x+10 hatta x = random(5) gibi. Eğer isterseniz, değişken üzerinde bir etkisi olmayan ancak yinede kod üzerinde yararlı etkiye sahip fonksiyonları da çağırabilirsiniz.
Noktalı virgülün bu bölümlerin her birini ayırdığına dikkat edin, bu önemlidir. Bütün bölümler boş da olabilirdi, ancak yine de noktalı virgül orada olmak zorunda. Bütün bölümler boş olabilirdi derken onu da biraz açalım. Üç farklı bölümümüz olduğundan bahsettik, değişken başlatma, koşul ve değişken güncelleme… Eğer koşul kısmına bir şey yazmazsanız yani iki noktalı virgül arasını boş bırakırsanız, for döngüsü doğru kabul edilecek ve bir şey onu durdurana kadar durmadan dönecektir.
For döngüsüne bir örnek verelim:
#include <stdio.h> int main() { int x; /* x < 10 iken döngü dönecek ve x her döngüde 1 artacak*/ for ( x = 0; x < 10; x++ ) { /* Koşul tekrar döngüye girmeden önce kontrol edilir. Sonuç olarak, x 10'a eşit durumunda döngü sonlanır. x değeri, koşul kontrol edilmeden önce güncellenir. */ printf( "%d\n", x ); } getchar(); }
Açıklaması gayet basit bir for döngüsü yarattık. x değeri sıfıra eşitlenir, x değeri 10 değerinden küçük olduğu sürece ekrana x değeri yazılır, ve son olarak x değerine 1 eklenir. Koşul doğru olduğu sürece bu sürer.
WHILE LOOP (while döngü yapısı)
while döngüleri çok basittir. Temel yapı şu şekildedir:
while ( koşul ) { çalıştırılacak kısım }
Koşul kısmına yazılan ifadeler doğru olduğu sürece işlemler gerçekleşir. Koşul kısmına x==7 gibi bir ifade yazılırsa ve bu ifade doğru ise işlem gerçekleştirilir. x != 7 gibi bir ifade de yazılabilir. x değerinin 6 olduğunu farzedelim. 6 != 7 ifadesi doğru olacağı için yine kod bloğu çalıştırılır. Koşul kısmına birden fazla ifade de yazabilirsiniz. x==7 | y==6 veya x==7 && y==6 gibi… |
Görüldüğü üzere for döngüsünde olduğu gibi koşul bölümünde bulunan değişkenin güncellenebileceği bir kısım bulundurmuyor. Bununla birlikte yine for döngüsünde olduğu gibi koşul kısmını boş bırakmanız kurallara aykırıdır. Eğer döngünün sürekli dönmesini istiyorsanız, boş bırakmak yerine koşul ifadesinin bulunduğu yere 1 yazmanız yeterli olacaktır.
#include <stdio.h> int main() { int x = 0; /* Değişkeni tanımlamayı unutmuyoruz*/ while ( x < 10 ) { /* x, 10 dan küçük olduğu sürece */ printf( "%d\n", x ); x++; /* x değerini güncelleyelim ki döngü sonlanabilsin */ } getchar(); }
Aslında bu örnek while döngüsünü anlamak için yeterli olacaktır ancak “neden for yerine while kullanayım ki?” gibi bir soru aklınıza gelmiştir. Aslında her döngü birbiri yerine kullanılabilir. Ancak bazı durumlarda while kullanmak kod’un okunabilirliği ve kolay yazım açısından avantajlar sağlayabilir. Şimdi şöyle bir durum düşünelim. Elimizde bir sayı var. Bu sayı 0’a eşit olmadığı sürece döngünün dönmesini istiyoruz. Her seferinde sayıyı 10’a böleceğiz. Örneğe bakalım.
#include <stdio.h> int main() { int sayi; /* Değişkeni tanımlamayı unutmuyoruz*/ printf("Bir sayi girin: "); scanf("%d", &sayi); while ( sayi != 0 ) { /* sayi, 0'a eşit olmadığı sürece */ printf( "%d\n", sayi ); sayi /= 10; /* sayi değerini güncelleyelim ki döngü sonlanabilsin */ } getchar(); }
Şimdi bu elimizde kullanıcıdan alınan bir sayı bulunuyor. Bu sayı 0 olana kadar 10 a bölmemiz gerekiyor. Kaç adımda sıfır olacağını bilmiyoruz. Kullanıcı 10 basamaklı bir sayı da girebilir, 2 basamaklı bir sayıda girebilir. Kullanıcının 12345 sayısını girdiğini farzedelim. Programın çıktısı şu şekilde olacaktır:
Bir sayi girin: 12345 12345 1234 123 12 1
Görüldüğü üzere sayı kaç basamaklı ise o kadar kez tekrar etmesini sağladık. Şimdi teorik olarak programın sonsuz kez tekrar etmesi gerekiyor gibi düşünebilirsiniz. Çünkü aslında sayı hiçbir zaman sıfır olmaz. Ancak int tipinde bir değişken olduğunu unutmayın.
Daha fazla uzatmadan Do while döngüsüne geçelim.
DO..WHILE LOOP (do..while döngü yapısı)
do..while döngüleri bir kod bloğunu döngüye girmeden önce en azından bir kere çalıştırmanıza olanak verir. Döngü yapısı şu şekildedir:
do { } while ( koşul );
Koşul‘un do bloğunun sonunda kontrol edildiğine dikkat edin. Böylece kod bloğu en azından bir kere çalıştırılacaktır. Eğer koşul doğru ise, bloğuna başına sıçrayarak bloğu tekrardan çalıştıracaktır. Bir do..while döngüsü while döngüsüne oldukça benzer bir yapıdır. Aralarındaki ufak fark ise, do..while döngüsünün kod bloğunun en azından bir kere çalıştıracağının garantisini vermesidir. While döngüsü şunu söylerken: “Koşul doğru ise, kod bloğunu çalıştır“, do..while döngüsü şunu söyler: “Kod bloğunu çalıştır, koşul doğru ise döngüye devam et“.
Bir örnek verelim:
#include <stdio.h> int main() { int x; x = 0; do { /* "Merhaba, Cypher!" yazısı koşul yanlış olsa bile bir kere yazdırılacak */ printf( "Merhaba, Cypher!\n" ); } while ( x != 0 ); getchar(); }
Yukarıdaki örnekteki gibi son kısıma noktalı virgülü koymayı unutmayın. Bu unutluduğu için çok sık hatalar ile karşılaşılıyor.
Break ve Continue Yapısı
Döngü yapılarında kullanılan çok önemli iki anahtar kelimeyi ele alacağız. Bunlar break komutu ve continue komutları olacak.
Break komutu, döngünün koşulu ne olursa olsun döngüyü kırar ve sonlandırır. Break, bazı özel koşullarda döngüyü sonlandırmak için çok kullanışlıdır. Örneğin iki kişilik bir dama oyunu programladığımızı düşünelim. Kodun temel yapısı şu yapıya benzer bir yapıda olacaktır:
while (true) { sirayi_al(player1); sirayi_al(player2); }
Bu yapı, player1 ve player2’nin sıra ile oyun sırasını devralmalarını sağlar. Mantıktaki tek hata oyundan hiçbir şekilde çıkış yapılamıyor olması; döngü sonsuza kadar dönecek! Şimdi bazı şeyleri değiştirelim:
while(true) { if (birisi_kazanirsa() || birisi_cikmak_isterse() == TRUE) {break;} sirayi_al(player1); if (birisi_kazanirsa() || birisi_cikmak_isterse() == TRUE) {break;} sirayi_al(player2); }
Bu kod normal koşullar altında oyunun devam etmesini sağlarken özel koşullarda (kazanma veya çıkış yapma) program akışının durdurulmasını ve döngünün sonlandırılmasını sağlıyor.
Continue komutu ise döngü kontrolünü sağlarken kullanacağımız bir diğer anahtar kelimedir. Bir döngü yürütüldüğünde continue ifadesini kullanırsanız, döngü mevcut yinelemeyi durduracak kendisini güncelleyerek üstten tekrar yürütmeye başlayacaktır. Continue aslında şunu söyler: “Gerekli yinelemeler yapıldı, bu satırdan sonra her ne kodu olursa olsun yinelemeden kodun üst kısmından devam edelim“. Diyelimki Monopoly oyununu programlıyoruz. Yukarıdaki örnekte olduğu gibi sıranın kimde olduğunu kontrol eden bir döngü yapısı oluşturalım ama Monopoly, dama oyununa göre daha karmaşık bir yapıya sahiptir. Kodun temel yapısı şuna benzer olacaktır:
for (oyuncu = 1; birisi_kazandi == FALSE; oyuncu++) { if (oyuncu > toplam_oyuncu_sayisi) {oyuncu = 1;} if (iflas_etti(oyuncu)) {continue;} sirayi_al(oyuncu); }
Buradaki gibi bir oyuncu kendi sırasını alamazsa, oyun herkes için kesilmez; o oyuncuyu geçerek, sırayı sonraki oyuncuya devreder.
Bu bölümde döngü yapılarından do..while döngü yapısı, while döngü yapısı ve for döngü yapısını öğrendik.
Sonraki bölümde Fonksiyonlara giriş yapacağız ve Program Organizasyonunu ele alacağız.