FOR DÖNGÜSÜ ------------ for döngüsü, ilk atama, koşul kontrolü ve döngü kontrol güncellemesini tek satırda yapmaya yarayan bir söz dizime sahip özel bir döngüdür. while döngüsüne alternatiftir. Genel olarak, while döngüsünü koşul odaklı kullanırken, for ise tekrar adımı odaklıdır. örnek: basamak sayısı hesaplama örneğinde, while(n != 0) şeklinde döngü koşulu yapar, while döngüsünü tercih ederiz. Burada n 0'dan farklı olduğu sürece bu işi yap dediğimiz için, while daha anlamlı olur. Ama 1'den n'e kadar sayıları yazdırma örneğinde, bir ilk değer ataması, ve belirli bir tekrar sayısı, her adımda 1 artırma işlemi olduğu için for yazma ve okuma açısından daha anlamlı gelir. Ama bu iki döngü türü birbirine alternatiftir. Bir döngüyü for ile yapabiliyorsak, while ile de mümkündür. Temel söz dizimi: for (ilk atama ; koşul; güncelleme) { //her adımda yapılacak işlemler. } Yukarıda for döngüsünün temel yapısı verilmiştir. {} işaretlerinin işlevi while ile aynıdır. Döngünün her adımında yapılacak işlemlerin ifadeleri yer alır. for döngüsünde temel olan () içindeki ifadelerdir. 3 kısımdan oluşur, ve bu kısımlar ; ile birbirinden ayrılır. Bu 3 kısımdan biri, ikisi veya hepsi boş bırakılabilir, bu durum derleme hatasına yol açmaz. Ama boş bırakılsalar bile, for parantezleri içinde 2 adet ; olmak zorundadır. İlk kısım ilk değer atama kısmıdır. for döngüsü kurarken genellikle bir döngü kontrol değişkeni tanımlarız. Bu değişkene for döngüsünün 1. kısmında ilk değerini veririz. Bu ilk değer atama işlemi sadece 1 kez yapılır. Döngünün sonraki iterasyonlarında tekrar tekrar ilk değer ataması yapılmaz. 2. kısım koşul kısmıdır. Burada, aynen while döngüsünde olduğu gibi, doğru/yanlış sonucu veren bir kontrol olur, ve doğru sonuç verdiği sürece döngü içi ifade tekrar çalışır. 3. kısım ise güncelleme kısmıdır. Tanımlanan döngü kontrol değişkenine ilk değer verilir(i = 0 gibi), koşul kontrolü de genelde bu değişkenin bir değere ulaşması üzerinden yapılır.(i < 10 gibi), döngümüzün sonsuz olmaması için, 2. kısımdaki kontrol bir aşamada yanlış olmalıdır. Bunun için, while döngüsünde blok içinde yaptığımız değer güncelleme işlemi, for döngüsünün 3. kısmında yazılır. (i++ gibi) Buraya yazılan güncelleme ifadesi, for döngüsündeki {} içerisinde yazılan tüm ifadeler çalıştıktan sonra, döngü bir sonraki adıma geçip geçmemeye karar vermek üzere başa dönmeden önce yapılır. Yani {} içerinde son satırda gizli olarak yer alır gibi düşünebiliriz. örnek kullanım: int i; for(i = 0; i < 5; i++) { printf("%d\n", i); } Yukarıdaki döngü, i değişkenine 0 ilk değerini verir(sadece ilk çalışmasında), i < 5 koşulu doğru olduğu sürece, içerideki ifade çalışır, yani i değerini konsola yazar. Ve yazdıktan sonra i değeri 1 artırılır, döngü başa dönüp tekrar koşul kontrolü yapar(i hala 5'ten küçük mü?) İlk çalışmada, i 0 değerini alır, i < 5 koşulu doğrudur, ve blok içine girilir, içerideki printf çalışır ve 0 yazar, güncelleme kısmındaki i++ çalışır, i 1 olur, döngü tekrar kontrol etmek üzere başa döner. i = 0 ataması artık çalışmaz. i < 5 hala doğrudur, 1 yazdırılır, i 2 değerini alır, başa döner..... koşul yanlış olana kadar i değeri yazdırılır. * for döngüsünü kontrol etmek için kullandığımız i değişkeninin declare edilmesi, aynen örnekte olduğu gibi, for döngüsünün üzerinde yapılmalıdır. Her ne kadar bazı C versiyonları içeride tanımlamaya izin verse de, versiyon problemi yaşamamak için, garanti yol olan, dışarıda tanımlama işlemi yapılmalıdır. Kodu taşıdığımız sistem, bunu kabul eden versiyonda çalışmıyor olabilir. * İlk değer ataması da for dışında yapılabilir, ve döngünün 1. kısmı boş bırakılabilir. Ama ilgili kısmı ayırmak için ; unutulmamalıdır. int i = 0; for(; i < 5; i++) { printf("%d\n", i); } * Koşul kontrolü de boş bırakılabilir, ama bu önerilmez. Döngünün sonlu olması, bir noktada bu koşulun yanlış olmasına bağlıdır. Koşul boş bırakılırsa sonsuz döngü oluşabilir. Bu durumda döngüyü bir noktada bitiren break anahtar kelimesi de işimizi görebilir. int i; for(i = 0; ; i++) { if (i == 5) { break; } printf("%d\n", i); } Yukarıdaki örnekte, bir koşul kontrolü olmasa da, döngü her adımda i değerini 1 artıracak, 5 e ulaştığında if koşulu çalışacak, ve break döngüyü sonlandıracaktır. * break ve continue kullanımı while döngüsü ile aynıdır. * Güncelleme kısmı da boş bırakılabilir, ama bu durumda döngüyü kontrol eden değişkenin değeri, while döngüsünde olduğu gibi, blok içinde güncellenmelidir. örnek kullanım: int i; for(i = 0; i < 5; ) { printf("%d\n", i++); } for döngüsü içindeki 3 kısmın hepsi boş bırakılabilir, ama bu durumda sonsuz döngü oluşturma riski fazladır, bu sebeple uygun olan davranış, 3 kısmı da kullanmak anlamlı olduğunda for döngüsü kullanmaktır. * Dikkat edilmesi gereken bir başka konu, for() dışında, { açmadan ; kullanMAmaktır. int i; for(i = 0; i < 5; i++); { printf("%d\n", i); } Yukarıdaki örnekte, for kapanış parantezi sonrası koyulan ; döngüyü blok tanımlamadan sonlandırır. (0'dan 4'e kadar hiçbir şey yapmayan bir döngü tanımlanmış olur.) Sonrasında gelen {}, döngüden tamamen bağımsız hale gelir. DİZİLER(ARRAYS) --------------- Aynı türde birden fazla veriyi bir arada tutmamızı sağlayan bir veri yapısıdır. Değişken tanımlarken kullandığımız temel türlerdeki (int, char, double vs.) birden fazla veri bu yapıda tutulur. -Tanımı için, aynen değişken tanımında olduğu gibi, tür ve isim verilir. Ama ismin hemen yanına [] işaretleri koyulmalıdır. Tanımladığımız değişkenin, birden fazla veri tutan bir yapı olduğunu derleyiciye bu köşeli parantezler bildirir. -Diziler sabit boyutludur, boyutu tanım aşamasında verilmelidir, ve sonrasında değiştirilemez. Dizi tanımında boyut verilmesinin sebebi bellekte yer ayırmaktır. Ayrılacak yer başlangıçta bildirilmelidir, çünkü dizinin tüm elemanları, bellekte birbirini takip eden adreslerde bulunur. -Dizi tanımında verilen ad, dizinin ilk elemanının adresine karşılık gelir. -Dizi elemanlarına erişmek için indeks kullanılır. İndeksler 0'dan başlar, ve [] içinde verilen tam sayı indeks değeri ile bir sıradaki elemana ulaşabiliriz. 5 elemanlı bir dizinin ilk elemanına erişmek için dizi[0], son elemanı için dizi[4] ifadesi kullanılır. dizi[5] ifadesi, diziye ayrılan bellek alanı dışında bir değere erişmeye çalıştığı için yanlış bir kullanımdır. int dizi[]; //Burada bir dizi tanimi yapilmistir. Ama kullanim hatalidir. Bir boyut verilmemistir. int dizi[3];//Bu kullanim dogrudur, 3 eleman tutan bir tam sayi dizisi tanimlanmis, bellekte ardisik 3 adet, 4'er baytlik alan ayrilmistir. //Yukaridaki dizi tanimda, herhangi bir deger verilmediginden, dizi cop degerler icermektedir. //atama asagidaki gibi yapilabilir. dizi[0] = 3;//ilk elemana 3 degerini atar dizi[1] = 3;//2. elemana 3 degerini atar dizi[2] = 3;//3. elemana 3 degerini atar dizi[3] = 3;//Hatali kullanim! 3 elemanli dizinin son elemani dizi[2] dir. Derleme hatasi vermez. Calisma zamani hatasina, veya sistemin yanlis calismasina neden olur. * int dizi[] = {1,2,3}; Bu tanım geçerli bir tanımdır. Boyut belirtilmemesine rağmen, {} içinde dizinin değerleri belirlenmiştir. Kaç değer verildiyse, dizi o boyuta sahip olur. Dizide kullanacağımız elemanlar belliyse bu kullanım uygun ve pratiktir. ** Bu kullanımda {} sonrası ; koymak unutulmamalıdır. * Diziye hem boyut verip hem de ilk değer ataması yapılabilir. int dizi[3] = {1,2,3}; Burada dikkat edilmesi gereken nokta, diziye, {} içinde verilen eleman sayısından küçük bir boyut vermemektir. Ama daha büyük bir boyut verilebilir. Bu durumda verdiğimiz elemanlar baştan itibaren diziye yerleştirilirken, geri kalan elemanlara 0 değeri verilir. int dizi[3] = {1}; Bu tanım sonrası dizinin ilk elemanı 1, diğer 2 elemanı 0 değerini alır. Bu tanım şeklini, dizinin tüm elemanlarına 0 ilk değerini vermek için de kullanabiliriz. Diziye bir boyut verip, {} içini de boş bırakırsak, verilen boyut kadar 0 içeren bir dizi elde ederiz. int dizi[3] = {}; Bu tanım, tüm elemanları 0 olan 3 elemanlı dizi oluşturur. ** Dizi tanımlanırken değişkenler boyut olarak kullanılabilir. Örneğin, kullanıcıdan alınan bir n sayısı, int dizi[n] şeklinde boyut olarak verilebilir. Bu durumda dikkat edilmesi gereken nokta, değişken boyut tanımlanmış dizilere {} ile ilk değer verilMEmesi gerektiğidir. sizeof -------- sizeof operatörü, bir değişkenin veya türün, bayt cinsinden boyutunu dönen bir operatördür. int x = sizeof(int);// x 4 değerini alır. int x = sizeof(char);// x 1 değerini alır. int x = sizeof(double);// x 8 değerini alır. int y; int x = sizeof(y);// x 4 değerini alır. Son örnekte, y değişkeni declare edildiğinde, türü int olduğu için, bellekte 4 bayt yer ayrılmıştır. Bunun için değer verilmesine gerek yoktur, zira ayrılan bellek alanında bulunan bir değeri vardır. Bu nedenle sizeof yine 4 döner. sizeof dizilerin de boyutunu hesaplayabilir. int dizi[3]; int x = sizeof(dizi);//x 12 değerini alır, çünkü dizi 3 tane 4 bayt yer kaplayan int tutuyor. sizeof bayt cinsinden değer verdiği için, bir dizinin eleman sayısını bulmak istiyorsak, dizinin boyutunu, türün boyutuna bölmeliyiz. int size = sizeof(dizi)/sizeof(int); veya int size = sizeof(dizi)/sizeof(dizi[0]); DİZİLERİN PARAMETRE GEÇİLMESİ ----------------------------- Dizilerin bir fonksiyona parametre geçilmesi yazım açısından diğer değişkenlerle aynıdır. Sadece, tanımda da olduğu gibi, fonksiyon parametre tanımında [] unutulmamalıdır. Ama fonksiyon çağrılırken [] verilmez, dizinin adını vermek yeterlidir. void printArray(int dizi[], int n) { } Yukarıdaki fonksiyonu çağırma şekli: int dizi[5]; printArray(dizi, 5); Prototip tanımı da aynı şekilde yapılır. Yukarıdaki fonksiyonun prototipi: void printArray(int dizi[], int n); *prototip kullanımında, değişken ismi vermek zorunlu olmadığından, aşağıdaki kullanım da geçerlidir: void printArray(int [], int); * Eğer diziyi parametre alan fonksiyon, bir döngü ile dizi üzerinde gezecekse, dizi boyutu da parametre olarak verilmelidir. sizeof kullanımı, dizi için, dizinin tanımlandığı yerde doğru sonuç verirken, fonksiyon içinde bir işaretçi(pointer) olarak algılandığından, dizinin bayt cinsinden boyutunu vermez. ** Diziler, değişkenlerden farklı olarak, fonksiyonlara pass-by value şeklinde değil, pass-by reference şeklinde parametre verilir. Bunu sebebi, dizi adının ilk elemanın adresine karşılık gelmesidir. Yani orijinal dizinin bellek adresi fonksiyona verilir, ve bu fonksiyonda yapılan değişiklik ilgili bellek alanını günceller. Değişkenlerdeki gibi kopyası oluşturulup, çağrılan yerde asıl değerin korunması olayı geçerli değildir.