C Programlama Dersi – IV

Daha önceki yazımızda, koşullu ifadelerigörmüştük. Hatırlatmak için üzerinden geçersek, if ile bir ifadeyi kontrol ediyorve doğruysa, buna göre işlemler yapıyorduk. Bir de if – else yapısı vardı. if – elseyapısında da, koşulu gene kontrol ediyor, doğruysa if bloğunun altında kalanları yapıyorduk; yanlışsa, else bloğunda olan kodlar işleme alınıyordu. Son derece basitbir mantık üzerine kurulmuş bu yapıyla, yapılamayacak kontrol yoktur. Ancak öyledurumlar vardır ki, if – else yapısı yeterli verimliliği sunamaz.

Diyelim ki, birden fazla kontrol yapmanız gereken bir durum oluştu. Hatta örnekvererek konuyu daha da somutlaştıralım. İstenilen bir programda, klavyeden sizeyaş bilgisi veriliyor. Siz de bu bilgiye göre, şayet yaş 18’den küçükse çocuk;18-30 yaş arasında genç; 30-50 yaş arasında ortayaş diye bir mesaj bastırıyorsunuz.Basit bir program.

Şimdi bunu sadece if yapısıyla kuruyor olsaydık, her seferinde yaşın uygun aralıklaradüşüp düşmediğini kontrol eder ve ona göre sonucu ekrana bastırırdık. Ama buson derece verimsiz bir yöntem olurdu. Çünkü zaten yaş bilgisinin genç olduğunadair bir karar vermişsek, sonrasında tutup bunun yaşlı olup olmadığını kontroletmenin bir esprisi olmayacaktır. Verilebilecek en kötü cevabı aşağıda bulabilirsiniz:
/*
Sorulan soruya verilebilecek en
kötü cevap.
*/
#include<stdio.h>
int main( void )
{
int girilen_yas;
printf(“Lütfen yaşınızı giriniz> “);
scanf(“%d”,&girilen_yas);
if( girilen_yas < 18 )
printf(“Daha çocuk yaştasınız, hayatın başındasınız.\n”);
if( girilen_yas >= 18 && girilen_yas <= 30 )
printf(“Gençliğin, güzelliği bambaşka!\n”);
if( girilen_yas > 30 && girilen_yas <= 50 )
printf(“Hepsini boşverin, olgunluk ortayaşta başlar!\n”);
return 0;
}

Yukarda ki kodu if – else kullanarak daha efektif hale getirebiliriz:
/*
if – else yapısıyla daha
efektif bir yapı
*/
#include<stdio.h>
int main( void )
{
int girilen_yas;
printf(“Lütfen yaşınızı giriniz> “);
scanf(“%d”,&girilen_yas);
if( girilen_yas < 18 )
printf(“Daha çocuk yaştasınız, hayatın başındasınız.\n”);
else {
if( girilen_yas >= 18 && girilen_yas <= 30 )
printf(“Gençliğin, güzelliği bambaşka!\n”);
else {
if( girilen_yas > 30 && girilen_yas <= 50 )
printf(“Hepsini boşverin, olgunluk ortayaşta başlar!\n”);
}
}
return 0;
}

Yukardaki program daha efektif bir yapı sunmuş olmasına rağmen, eğer kontrol ettiğimizaralıkların sayısı çok fazla olsaydı, tam bir başbelası olacaktı! Çünkü if – else içinde,bir başka if – else bloğu ve onun içinde bir başkası… bu böyle sürüp gidecekti. Kısacası performans olarak çok bir şey değişmese de, kodu yazan ve/veya okuyacak olan için tam bireziyete dönüşecekti. İşte bu nedenlerle daha efektif yapılara ihtiyaç duyuyoruz.

if – else if Merdiveni

if – else if merdiveni yukarda verdiğimiz örnekler için biçilmiş kaftandır. if – else ifmerdiveni, doğru bir şey bulduğu zaman kontrolu orada keser ve diğer koşulları kontrol etmeden blok sonlandırılır.

Aşağıda if – else if yapısını ve akış diyagramını bulabilirsiniz:

if – else if Yapısı if – else if Akış Diyagramı
if( koşul 1 ) {
komut(lar) 1
}
else if( koşul 2 ) {
komut(lar) 2
}
.
.
.
else if( koşul n ) {
komut(lar) n
}
else {
komut(lar) n
}

[if – else if structure]

if – else if ile söylenebilecek son bir şey sonunda ki else’tir. else koymak zorunludeğildir. Ancak hiçbir koşula uymayan bir durumla karşılaştığınızda, else devreye girer.Örneğin yukarda anlatıp, kodunu vermiş olduğumuz programda, belirtilen yaş aralıklarındadeğer girilmezse, hiçbir şey ekrana bastırılmayacaktır. Çünkü programa tanınmayan yaş aralığında ne yapılacağı öğretilmemiştir. Şimdi bu durumu da içerecek şekilde,programamımızı if – else if yapısıyla tekrar yazalım:
#include<stdio.h>
int main( void )
{
int girilen_yas;
printf(“Lütfen yaşınızı giriniz> “);
scanf(“%d”,&girilen_yas);

if( girilen_yas < 18 )
printf(“Daha çocuk yaştasınız, hayatın başındasınız.\n”);
else if( girilen_yas >= 18 && girilen_yas <= 30 )
printf(“Gençliğin, güzelliği bambaşka!\n”);
else if( girilen_yas > 30 && girilen_yas <= 50 )
printf(“Hepsini boşverin, olgunluk ortayaşta başlar!\n”);
else
printf(“HATA: Girilen yaş tanımlı değildir!\n”);

return 0;
}

swicth – case ifadesi

switch – case, if – else if yapısına oldukça benzer bir ifadedir. Ancak aralarında ikifark vardır. Birincisi, switch – case yapısında, aralık değeri girmezsiniz. Direkt olarakifadelerin bir şeylere eşit olup olmadığına bakarsınız. İkinci farksa, switch – caseyapılarında, illa ki uygun koşulun sağlanmasıyla yapının kesilmek zorunda olmayışıdır.’break’ komutu kullanmadığınız takdirde, diğer şartların içindeki işlemleri de yapmaimkanınız olabilir. switch case en tepeden başlayarak şartları tek tek kontrol eder.Uygun şart yakalanırsa, bundan sonra ki ifadeleri kontrol etmeden doğru kabul eder.Ve şayet siz break koymamışsanız, eşitlik uygun olsun olmasın, alt tarafta kalan case’lereait komutlarda çalıştırılacaktır. if – else if ise daha önce söylemiş olduğumuz gibi böyle değildir.Uygun koşul sağlandığında, yapı dışarsına çıkılır.

switch case yapısında ki durumu, aşağıdaki tabloda görebilirsiniz:

switch case Yapısı switch case Akış Diyagramı
switch( degisken ) {
case sabit1:
komut(lar)
[break]
case sabit2:
komut(lar)
[break]
.
.
.
case sabitN:
komut(lar)
[break]
default:
komut(lar);
}

[switch case structure]

Sanırım gözünüze biraz farklı gözüktü. Yapı olarak şimdiye kadar görmüş olduğunuzif else gibi gözükmese de, bir örnekten sonra arasında pek bir fark olmadığını göreceksiniz.Her komut sonunda koyduğum break komutu, zorunlu değildir ve o nedenle köşeli parantezlebelirtilmiştir. break koyduğuz takdirde, uygun koşul sağlandıktan sonra, daha fazlakontrol yapılmayacak ve aynen if – else if yapısında olduğu gibi program orada kesilecektir.Ama break koymazsanız, altında kalan bütün işlemler -bir daha ki break’e kadar- yapılacaktır.

Kodun sonunda gördüğünüz default komutu, if – else if yapısında ki sonuncu else gibidir.Uygun hiçbir şart bulunamazsa, default komutu çalışır.

Öğrendiğimiz bilginin pekişmesi için biraz pratik yapalım. Bir not değerlendirme sistemiolsun. 100 – 90 arası A, 89 – 80 arası B, 79 – 70 arası C, 69 – 60 arası D, 59 ve altıysaF olsun. Eğer 100’den büyük veya negatif bir sayı girilirse, o zaman program hatalı birgiriş yapıldığını konusunda bizleri uyarsın. Bunu şimdiye kadar öğrendiğiniz bilgilerle,if – else if yapısını kullanarak rahatlıkla yanıtlayabilirsiniz. Ama şu an konumuzswitch case olduğundan, cevabını öyle verelim:
#include<stdio.h>
int main( void )
{
int not;
printf(“Lütfen notu giriniz> “);
scanf(“%d”,&not);
switch( not / 10 ) {
case 10:
case 9: printf(“NOT: A\n”); break;
case 8: printf(“NOT: B\n”); break;
case 7: printf(“NOT: C\n”); break;
case 6: printf(“NOT: D\n”); break;
case 5:
case 4:
case 3:
case 2:
case 1:
case 0: printf(“NOT: F\n”); break;
default:
printf(“HATA: Bilinmeyen bir değer girdiniz!\n”);
}

return 0;
}

Algoritmaya bakalım: Önce sayıyı alıyor ve 10’a bölüyoruz. Yani girilen not, 57 ise5.7 sonucunu elde ediyoruz. Ancak iki tam sayının sonucu bir virgüllü sayı veremez,tıpkı işleme giren değişkenler gibi tam sayı olarak döner. Dolayısıyla bilgisayarın eldeedeceği sonuç, 5.7 değil, sadece 5’tir. switch case yapısında koşullar yukardan başlayarakkontrol ediliyor. case 5’e gelindiğinde eşitlik sağlanıyor. Ama break konmadığı için,switch case’ten çıkılmıyor. Ve altında kalan işlemlerde yapılıyor. Altında herhangi birişlem veya break olmadığından case 0’a kadar bu böyle sürüyor. Ve case 0’da ekrana birçıktı alıp switch case yapısı break ile sonlandırılmaktadır.

switch case, if – else if yapısının sunduğu esnekliğe sahip değildir. Daha çok menüolarak sunulacak işlerde kullanılır. Örneğin Unix’in ünlü listeleme komutu ls içersinde, verilen parametrelerin kontrolü switch case kullanılarak sağlanmıştır. Open Solaris, FreeBSD veya Linux kodlarını incelerseniz bunun gibi yüzlerce örnek bulabilirsiniz.

Arttırma (Increment) ve azaltma (decrement) işlemleri

Daha önceki derslerimizde, aritmetik işlemlerden bahsetmiştik. Bunların dışındayapabileceğimiz başka şeylerde bulunmaktadır. Bunlardan biri de, arttırma ve azaltmaişlemleridir.

Eğer i adında bir değişkenin değerini 1 arttırmak isterseniz, i = i + 1 olarakyazarsınız. Veya 1 azaltmak isterseniz, benzer şekilde i = i – 1 de yazabilirsiniz.Arttırma ve azaltma işlemleri bu olayı daha basit bir forma sokmaktadır. i = i + 1yazmak yerine i++ veya i = i – 1 yazmak yerine i– yazabilirsiniz.

Arttırma ve azaltma işlemleri temelde iki çeşittir. Birinci yöntemde yukardayazdığımız gibi, arttırma/azaltma sonradan yapılır. İkinci yöntemdeyse arttırma/azaltmailk başta yapılır. Aşağıdaki örneklere bakalım.
/*
Bu programda, arttırma ve azaltma
işlemleri önce yapılacaktır.
*/
#include<stdio.h>
int main( void )
{
int i = 10, j = 60;
printf(“i = %d ve j = %d\n”, ++i, –j);
return 0;
}

Yukardaki programı yazar ve çalıştırısanız elde edeceğiniz çıktı şu şekilde görünecektir:

i = 11 ve j = 59

Çünkü arttırma ve azaltma işlemleri ekrana bastırmadan önce yapılmış ve i ile j’nindeğerleri değiştirilmiştir. Şimdi programı değiştirip şöyle yazalım:
/*
Bu programda, arttırma ve azaltma
işlemleri sonra yapılacaktır.
*/
#include<stdio.h>
int main( void )
{
int i = 10, j = 60;
printf(“i = %d ve j = %d\n”, i++, j–);
return 0;
}

Bu sefer program çıktısı şöyle olacaktır:

i = 10 ve j = 60

Farkettiğiniz üzere hiçbir değişiklik yapılmamış gibi duruyor. Aslında değişiklik yapıldı ve program sonlanmadan önce i 10 olurken, j’de 59 oldu. Ama arttırma ve azaltma işlemleriprintf komutu çalıştırıldıktan sonra yapıldığı için, biz bir değişiklik göremedik.

Kısacası önce arttırma (pre-increment) veya önce azaltma (pre-decrement) kullandığınızda,ilgili komut satırında çalışacak ilk şey bu komutlar olur. Ancak sonra arttırma(post increment) veya sonra azaltma kullanırsanız, o zaman bu işlemlerin etkileriilgili komut satırından sonra geçerli olacaktır. Aşağıdaki özel tabloya bakabilirsiniz:

Form Tip İsim Açıklama
i++ postfix post-increment İşlem sonrası arttırma
++i prefix pre-increment İşlem öncesi arttırma
i– postfix post-decrement İşlem sonrası azaltma
–i prefix pre-decrement İşlem öncesi azaltma

Gelişmiş atama (Advanced Assignment) yöntemleri

C’de yazım kolaylığı amacıyla sunulmuş bir başka konu da, gelişmiş aşama yöntemleridir.Biraz daha uzun yazacağınız kodu, kısaltmanıza yaramaktadır.

degisken_1 = degisken_1 (operator) degisken_2 şeklinde yazacağınız ifadeleri, dahakısa yazabilmeniz için, degisken_1 (operator) = degisken_2 şeklinde ifade edebilirsiniz.Gelişmiş atamalarda sunulan genel formlar şu şekildedir:

+= , -= , *= , /= , %=

Sanırım aşağıdaki örneklere bakarsanız, konuyu çok daha net anlayacaksınız:
1-) j = j * ( 3 + x ) ==> j *= ( 3 + x )
2-) a = a / ( 5 – z ) ==> a /= ( 5 – z )
3-) x = x – 5 ==> x -= 5

Conditional Operator ( ? )

Türkçe karşılık bulamadığım bir başka C kavramı da, Conditional Operator. Aslındamot a mot çeviri yaparsam, koşullu operatör anlamına geliyor. Ama şu ana kadargördüğümüz birçok yapıyı da bu şekilde tanımlamak mümkünken, koşullu operatörifadesini kullanmayı pek tercih etmiyorum. Neyse lafı uzatmayalım…

Conditional Operator, if-else ile tamamen aynı yapıdadır. Hiçbir farkı yoktur.Tek farkı koda bakıldığında anlaşılmasının biraz daha zor oluşudur. Bir de if – elsegibi yazıyla ifade edilmez. Onun yerine soru işareti (?) ve iki nokta üst üste( : ) kullanarak yazarız. Aşağıdaki tabloda if else yapısıyla karşılaştırılmalı olarak,Conditional Operator verilmiştir:

if-else Yapısı Conditional Operator ( ? ) Yapısı
if( koşul ) {
if_komut(lar)
}
else {
else_komut(lar)
}

koşul?if_komut(lar):else_komutlar

Conditional Operator ( ? ) Akış Diyagramı

[Conditional Operator structure]

Şimdi de aynı programı, hem if-else, hem de conditional operator kullanarak yazalım:
/*
Girilen tam sayının
10’dan büyük olup
olmadığını gösteren
program
*/
#include<stdio.h>
int main( void )
{
int sayi;
printf(“Lütfen bir sayı giriniz> “);
scanf(“%d”,&sayi);
if( sayi > 10 )
printf(“Sayı 10’dan büyüktür\n”);
else
printf(“Sayı 10’dan küçüktür veya 10’a eşittir\n”);
return 0;
}

Şimdi de aynı programı conditional operator kullanarak yazalım:
/*
Girilen tam sayının
10’dan büyük olup
olmadığını söyleyen
program
*/
#include<stdio.h>
int main( void )
{
int sayi;
printf(“Lütfen bir sayı giriniz> “);
scanf(“%d”,&sayi);
( sayi > 10 ) ? printf(“Sayı 10’dan büyüktür\n”):
printf(“Sayı 10’dan küçüktür veya 10’a eşittir\n”);
return 0;
}

Program gördüğünüz gibi biraz daha kısaldı.

Conditional Operator’ler pek kullanmayı sevmediğim bir yapıdır. Çünkükodun kısa olmasından çok, anlaşılabilir olması önemli. Ve conditionaloperator kullanmak ne yazık ki, kodu daha karmaşık hale getiriyor.UNIX filozofisinde bir şeyi akıllıca yapacağınıza, temiz/açık yapın diye biryaklaşım mevcut. Belki bu yüzden veya belki de tembellik, conditionaloperator’lere alışamadım gitti… 🙂

Şimdi örnek sorularımıza gelelim…

Örnek Sorular

Soru 1: Aşağıdaki kodu yorumlayınız:

s = ( x < 0 ) ? -1 : x * x

Cevap için tıklayınız…

Soru 2: İki tam sayı alacak ve verilecek operatöre göre (+, -, *, /, %) işlem yapacak bir program yazınız.

Cevap için tıklayınız…

Soru 3: Verilecek üç sayıdan en büyüğünü ekrana yazdıracak bir programyazınız.

Cevap için tıklayınız…