Selamlar,
Bugünkü konularım:
- Veri tipi dönüşümü (type casting),
- Operatörler,
- Koşul ifadeleri (
if
–else
–switch
)
Veri Tipi Dönüşümü
C dilinde veri tipi dönüşümleri otomatik oalrak ya da programcının isteğine göre gerçekleşebiliyor.
#include <stdlib.h> #include <stdio.h> int main(void) { double doubleSayi1 = 3, doubleSayi2 = 6, doubleSayi3; int intSayi; char karakter; intSayi = doubleSayi1 / doubleSayi2; karakter = intSayi + 41; printf("doubleSayi1: %lf doubleSayi2: %lfn", doubleSayi1, doubleSayi2); printf("doubleSayi1 / doubleSayi2: %dn", intSayi); printf("Karakter: %c", karakter); }
Çıktı:
doubleSayi1: 3.000000 doubleSayi2: 6.000000 doubleSayi1 / doubleSayi2: 0 Karakter: )
8. satırda double
veri tipindeki değişkenleri tanımlarken tam sayı değerler atamıştım ama otomatik olarak double
veri tipine çevrilip yazıldılar.
9. satırda 3.0’ı 6.0’a bölüp sonucu int
veri tipindeki intSayi
değişkenine atıyorum. Sonuç=0.5 olmasına rağmen ekrana 0 yazdırıldı. Elde ettiğimiz sonuç int
veri tipine dönüştüğü için ondalık kısımlar saklanmıyor.
10. satırda ise intSayi
(0)+41 değeri char
veri tipindeki karakter değişkenine atılıyor. Ekrana ise “)” yazdırıldığını görüyorum. Çünkü ASCII tablosundaki 41. karakter “)”.
Veri tiplerini istediğimiz veri tipine dönüştürmek istersek yapmamız gereken çok basit: (yeni veri tipi) değişken
#include <stdlib.h> #include <stdio.h> int main(void) { int sayi1 = 3, sayi2 = 6, sayi3; float sonuc = sayi1 / sayi2; char karakter = ')'; printf("tip dönüşümü öncesin sayi1 / sayi2: %fn", sonuc); printf("karakter: %cn", karakter); sonuc = (float)sayi1 / (float)sayi2; sayi3 = (int)karakter; printf("tip dönüşümü sonrasın sayi1 / sayi2: %fn", sonuc); printf("karakter: %d", sayi3); }
Çıktı:
tip dönüşümü öncesi sayi1 / sayi2: 0.000000 karakter: ) tip dönüşümü sonrası sayi1 / sayi2: 0.500000 karakter: 41
int
veri tipini int
veri tipindeki bir değişkenle işleme sokunca sonuç yine int
veri tipinde dönüyor. Eğer int
veri tipindeki bir değişkeni float
veri tipindeki bir değişkenle işleme sokarsam sonuç ne olur?
Bu durumda veri tipi dönüşümü daha yüksek değerdeki veri tipine göre otomatik olarak dönüştürülür. Yani 3 / 6.0 işleminin sonucu 0.5 olacaktır. Eğer sonucu daha düşük değerdeki veri tipinde yazdırırsak, veri kaybı yaşayabiliriz.
printf("float veri tipi: %fn", 3 / 6.0); //0.500000 printf("int veri tipi: %dn", 3 / 6.0); //0
(DÜŞÜK) char <-> int <-> long <-> float <-> double (YÜKSEK) *
Operatörler
C içinde birçok operatörümüz var. Arttırma, azaltma, atama, karşılaştırma, mantıksal operatörler.
Arttırma – Azaltma – Atama
Operatör | Açıklama | Örnek | Anlamı |
= | atama | x = 7; | x = 7; |
+= | ekleyerek atama | x += 3 | x = x + 3 |
-= | eksilterek atama | x -= 5 | x = x - 5 |
*= | çarparak atama | x *= 4 | x = x * 4 |
/= | bölerek atama | x /= 2 | x = x / 2 |
%= | bölüp, kalanını atama | x %= 9 | x = x % 9 |
++ | bir arttırma | x++ veya ++x | x = x + 1 |
-- | bir azaltma | x-- veya --x | x = x - 1 |
Operatörlerimiz , açıklamaları ve örnek kullanımları tablodaki gibi. Daha iyi anlamak için biraz kod yazmak gerek.
int x = 7; printf("başlangıçtaki x: %dn", x); x += 3; // x = x + 3; printf("x += 3; için %dn", x); x = x - 3; // x -= 3; printf("x = x-3; için %dn", x); x -= 3; // x = x - 3; printf("x -= 3; için %dn", x); x *= 3; // x = x * 3; printf("x *= 3; için %dn", x); x++; // x = x + 1; printf("x ++; için %dn", x); x--; // x = x - 1; printf("x --; için %dn", x);
Çıktı:
başlangıçtaki x: 7 x += 3; için 10 x = x-3; için 7 x -= 3; için 4 x *= 3; için 12 x ++; için 13 x --; için 12
Arttırma ve azaltma operatörlerinde bir noktaya dikkat çekmek istiyorum.
x++
ve ++x
ya da x--
ve --x
, x değerini 1 arttırıp ya da 1 azaltır. ++
ve --
operatörlerinin değişkenden önce ya da sonra yazılması işlemin de önce ya da sonra yapılması gerektiğini sağlar. Şöyle ki:
int x = 7, y=1; printf("x değeri: %dn", x); puts("-------------"); printf("x++ sırasında: %dn", x++); printf("x++ sonrası: %dn", x); printf("++x sırasında: %dn", ++x); printf("++x sonrasında: %dn", x); puts("-------------"); printf("y değeri: %dn", y); puts("-------------"); printf("y-- sırasında: %dn", y--); printf("y-- sonrası: %dn", y); printf("--y sırasında: %dn", --y); printf("--y sonrasında: %dn", y);
Çıktı:
x değeri: 7 ------------- x++ sırasında: 7 x++ sonrası: 8 ++x sırasında: 9 ++x sonrasında: 9 ------------- y değeri: 1 ------------- y-- sırasında: 1 y-- sonrası: 0 --y sırasında: -1 --y sonrasında: -1
Yukarıda yazarında demek istediği gibi x++
önce işlemi yapar sonra x’in değerini 1 arttırır. ++x
ise önce x’in değerini 1 arttırır sonra işlemi yapar.
Karşılaştırma – Mantıksal
Adlarından anlaşıldğı gibi değerleri karşılaştırmak ya da mantıksal işlemlere sokmak için kullandığımız operatörlerdir bunlar.
Operatör | Açıklama | Örnek | Anlamı |
> | büyüktür | x > y | x, y den büyük mü? |
< | küçüktür | x < y | x, y den küçük mü? |
== | eşittir | x == y | x, y ye eşit mi? |
>= | büyük-eşittir | x >= y | x, y den büyük yada eşit mi? |
<= | küçük-eşittir | x <= y | x, y den küçük yada eşit mi? |
!= | eşit değil | x != y | x, y den farklı mı? |
&& | mantıksal VE | x>2 && x<y | x, 2 den büyük VE y den küçük mü? |
|| | mantıksal VEYA | x>2 || x<y | x, 2 den büyük VEYA y den küçük mü? |
! | mantıksal DEGIL | !(x>2) | x, 2 den büyük değilse |
Mantıksal Karşılaştırmalar
p | q | p&&q | p||q | !p |
0 | 0 | 0 | 0 | 1 |
0 | 1 | 0 | 1 | 1 |
1 | 0 | 0 | 1 | 0 |
1 | 1 | 1 | 1 | 0 |
“Tamam, operatörleri anladım ama x, y’den büyükse büyük, küçükse küçük. Ne yapalım büyükse ya da küçükse?”
Ee yani, boşu boşuna değerleri karşılaştırma ya da mantıksal işlemlere sokmayız. Belirli koşulların sağlanıp sağlanmadığını kontrol etmemiz gerektiğinde bunları uygulayacağız. Bunun için de koşul ifadelerini öğrenmen gerek.
Ama önce operatörlerin işlem önceliğine bakalım.
Şu örnek durumu gayet güzel açıklıyor:
int i=5, j=10, k=20; i > 5 * k % 3 && !( k- 2 != 18) i > 5 * k % 3 && !( 18 != 18) i > 5 * k % 3 && !0 i > 5 * k % 3 && 1 i > 100 % 3 && 1 i > 1 && 1 1 && 1 1
Koşul İfadeleri
Program akışında bazı kararlar verip, ona göre koşulları düzenlemek gerekebilir. Mesela, kullanıcıdan 1-10 arasında bir sayı girmesini istedik. Kullanıcı değeri girdikten sonra program kaldığı yerden devam edecek ama önce bir bak bakalım, gerçekten 1-10 arası bir sayı girmiş mi? Koşulumuzu kontrol ettikten sonra kararımızı verip programın akışına devam edebiliriz.
İşte bunun için kullandığımız bazı koşul ifadeleri var:
if
veelse
. Genelde bunlarif-else
ikilisi olarak bilinir. Ama ikisini birlikte kullanmak zorunda değiliz.- “
?
” ve “:
“. Bunlarda if-else ikilisinin şekil hali. switch
if-else
if(//koşul ifadesi burada) { //koşul doğruysa bu alandaki kodlar çalışacak } else { //if içindeki koşul doğru değilse bu alandaki kodlar çalışacak }
Basit bir if-else
bu şekilde çalışıyor. Şimdi basit bir örnek:
#include <stdlib.h> #include <stdio.h> int main(void) { int sayi; printf("1-10 arasında bir sayı girin: "); scanf("%d", &sayi); if(sayi >= 1 && sayi <= 10) { printf("Girdiğiniz sayı: %d", sayi); } else { printf("Sayı 1-10 aralığında değil."); } }
9. satırda girilen sayının 1-10 arasında olup olmadığını kontrol ettim. &&
kullanmanın sebebi ise, girilen sayının hem 1’den büyük olmasını hem de 10’dan küçük olmasını kontrol etmek.
8 değerini girdiğimizde (sayi>=1)
yani 8>=1 ifadesi doğru demektir. Ayrıca (sayi<=10)
için de ifade doğru demektir. Çünkü 8, 10’dan küçük. Sonuç olarak doğru && doğru
= doğru
demektir. Bu arada bilgisayar için doğru demek 1 demektir. Yanlış ise 0.
Sonuç olarak 9. satırdaki if
ifadesi doğru olduğu için if
bloğu içindeki kodlar çalışacaktır.
Şimdik if
ifadesindeki koşulu şu şekilde değiştiriyorum:
if(sayi >= 1 || sayi <= 10)
Bu durumda hangi sayıyı girersek girelim sonuç doğru çıkacaktır. 15 girdiğimizi düşünelim. (15>=1) ifadesi doğrudur. (15<=10) ifadesi yanlış. Sonuç olarak (doğru) || (yanlış) = (doğru)
yapacağından yine if
içerisindeki kodlar çalışacaktır.
Koşul ifadesini kontrol ettikten sonra yapacağımız işlem tek satırlık ise { } arasına almamıza gerek yok. Çünkü if
koşulu kontrol eder ve doğruysa hemen altındaki kod satırını çalıştırır. Aynısı else
içinde geçerli. Yani şöyle:
int sayi; printf("Bir sayı girin: "); scanf("%d", &sayi); if(sayi < 0) printf("Girilen sayı negatif."); printf("nBen hep buradayım...");
0 ve 0’dan büyük değerler için if
ifadesi yanlış çıkacaktır. Yani if
‘in hemen altındaki 11. satırdaki kodlar çalışmayacaktır. 13. satırdan devam edecektir.
if-else
ilişkisinde önemli bir detay var. “her else en yakın eşleşmemiş if ile eşleştirilir.“*
int a = -5, b = 10; if(a>0) if(b>0) printf("+"); else printf("#"); printf("Son");
Yukarıdaki kodu inceleyelim.
3. satırdaki if
için (-5>0)
ifadesi yanlıştır. Dolayısıyla if
‘in hemen altındaki 4. satırdaki kodlar çalışmayacaktır.
6.satırdaki else
ise kendisine en yakın olan if
‘e bağlı olduğu için, yani 4. satırdaki if
, program direkt 8. satıra geçecektir. Sonuç olarak ekrana sadece “Son” yazılacaktır.
else if
Eğer çok sayıda koşul kontrol edilecekse else if
ile kontrol edebiliriz. Koşullardan birisi doğru ise diğer koşulları kontrol etmemize gerek kalmaz. Bu da şöyle çalışmakta:
int sayi = 35; if(sayi > 50) { printf("50 den büyük"); } else if (sayi > 40) { printf("50 den küçük 40 dan büyük"); } else if (sayi > 30) { printf("40 dan küçük 30 dan büyük"); } else if (sayi > 20) { printf("30 dan küçük 20 den büyük"); } else { printf("20 ya da daha küçük"); }
Önce 3. satırdaki koşul kontrol ediliyor. İfade yanlış olduğu için 7. satırdaki else if
koşulu kontrol ediyor.
Koşul yine yanlış olduğu için 11. satırdaki else if
koşulu kontrol ediyor. İfade doğru olduğu için 15. ve 19. satırlardaki koşulların kontrol edilmesine gerek kalmıyor.
İşte böyle…
Dilersen { }
arasına istediğin kadar kod yazabilirsin. İç içe istediğin kadar if
, else
, else if
oluşturabilirsin. Ama şunu da unutmamak lazım ki programın ne kadar çok koşul kontrol etmesi gerekiyorsa o kadar çok durup düşünmesi gerekecek demektir. O yüzden koşulları kontrol ettirirken en basit ve efektif şekilde tasarlamak gerek.
?
ve :
(Conditional Operator)
?
ve :
operatörleri if
ve else
ile aynı mantıkta çalışıyor. Ne farkı var diye araştırdım. Kendileri ternary operation ailesine mensunpmuş. Yani 3 farklı argüman alıyor. Geriye dönen sonuç ve argümanlar farklı tiplerde olabiliyormuş.
Basit bir örnekle açıklamak daha iyi olur*:
#include <stdlib.h> #include <stdio.h> int main(void) { int sayi = 4, sonuc; sonuc = (sayi%2 == 0) ? 1 : 0; if(sonuc == 1) { puts("Sayı çift"); } else { puts("Sayı tek"); } return 0; }
7. satırda ?
ve :
kullanımını görüyoruz.
Öncelikle bir koşulumuz var: (sayi %2 == 0). Yani, sayi
değişkeninin 2 ile bölümünden kalan 0’a eşittir.
Koşuldan sonra ?
geliyor. Yani, “koşul doğru mu?” diye soruyor. Eğer doğruysa sonuc
değişkenine 1 değerini atıyor.
:
ise eğer koşul yanlışsa sonuç
değişkenine 0 değerini atıyor.
Yukarıdaki kodu daha pratik hale getirebiliriz. Şöyle ki:
(sayi%2==0) ? printf("Çift sayı") : printf("Tek sayı");
switch
if
‘ler else if
‘ler ile hemen hemen aynı sayılır. Ama aralarında bazı farklar var. En önemli fark, if - else, if
ile koşulları kontrol ederken doğru koşula ulaşınca diğer koşulları atlayarak yola devam ediyorduk. switch
ile istersek doğru koşul sağlansa bile diğer koşulları atlamayıp çalıştırabiliriz. Bunun için “break
” anahtar kelimesini kullanmak gerek.
if- else
‘de hiçbir koşul doğru değilse else
alanındaki kodlar çalışıyordu. switch'de
bu görevi “default
” üstleniyor.
Çok sayıda iç içe if-else
, else if
‘lerin kullanıldığı durumlarda bazen kodları okuması ve yorumlaması zor ve kafa karıştırıcı olabilir. Bu tip durumlarda switch
kullanmak hem daha performanslı hem de daha okunaklı kodlar elde etmeye yarıyor.
Önce hafif iç içe geçmiş bir if
örneği sunmak istiyorum:
if(koşul1) kodlar else { kodlar if(koşul2) { if(koşul3) kodlar else if(koşul 4) { kodlar } } else { kodlar } }
Yukarıdaki örnekte çok sayıda kod olduğunu düşünürsen, hata yapma olasılığının farkına varabilirsin. Şimdi switch
‘in genel kullanım yapısına bir göz atalım*:
switch(değişken) { case değer1 : kodlar break; case değer2: kodlar break; case value3 : body3 break; default : kodlar break; }
Görüldüğü üzere switch
çok sayıda içi içe if’e göre daha okunaklı. Ayrıca kaynağını hatırlamadığım bir yazıda, iyi geliştiricilerin if
yerine switch
tercih ettiği yazıyordu.
Basit bir örnek ile bugünkü dersimi de bitireyim.
int sayi; printf("lütfen bir sayı girin: "); scanf("%d", &sayi); switch(sayi) { case 1: puts("Sayı 1"); break; case 2: puts("Sayı 2"); case 3: puts("Sayı 3"); break; case 4: case 5: case 6: case 7: puts("4, 5, 6, 7 olabilir."); break; default: puts("1-7 arasında değil."); break; }
İlk olarak 1 değerini girdiğimi düşünelim. Bu durumda sayi
değişkeni 1 değerini tutuyor. Yani switch
1 olan durumu aramaya başlıyor. case 1
‘e geldiğinde koşul sağlanıyor ve puts("Sayı 1")
fonksiyonunu çalışıyor. Daha sonra break
komutu için switch içinden çıkıyoruz.
Şimdi 2 değerini girdiğimi düşünelim. case 1
koşulu sağlamıyor. case 2
koşulu sağladığı için puts()
çalışıyor. Henüz break
komutu olmadığından case 3
‘e geçiliyor ve buradaki komutlarda çalıştırılıyor. Önce puts()
çalışıyor. Ardından break
komutu geldiği için switch
sonlanıyor.
5 değeri için, case 1, case 2, case 3, case 4
çalışmıyor. case 5
ise koşulu sağlıyor ama herhangi bir komut olmadığı için case 6
ile devam ediyoruz. case 6'
da çalışıyor ve case 7
‘ye geliniyor. Önce puts()
çalışıyor ardından break
ile switch sonlanıyor.
case
haricinindeki bir değer girersek, 10 gibi, hiçbir case
koşulu sağlamadığı için default
alanındaki kodlar çalıştırılıyor. default
için break
komutu kullanmak opsiyonel.
Özet
- veri tipi dönüşümü otomatik ya da elle olsun, büyük değerden küçük değere dönüşüm yapılırken veri kaybı yaşanabilir. dikkat etmek lazım.
- x++, önce işlemleri yap sonra x’in değerini arttır, ++x önce x’i arttır sonra işlemleri yap.
- x *= 3 ile x = x* 3 aynı şey.
- her else kendine en yakın eşleşmemiş if ile eşleşir.
- koşulları karşılaştırırken switch kullanmaya özen göster. daha hızlı ve okunaklı.
Çalışma Soruları
//Güncellenecek.
Senaryo1: Girilen yılın, artık yıl olup olmadığı bulan bir program yazalım. Artık yıl, 4’ün katı olmalıdır. Eğer yıl 100’ün katıysa 400’e de kalansız olarak bölünmelidir. *
Senaryo2: Bir boyacı dükkanımız var. 3 farklı tipte (A, B, C) boyamız var ve bu tiplere göre boyanın fiyatı değişiyor. A boyası için, metre karesi 100.00 TL, B boyası için 125.00 TL, C boyası için 135.45 TL. Kullanıcı önce boya tipini daha sonra kaç metre kare boya yaptıracağını seçecek. Bunun sonucunda kullanıcıya fiyat bilgisi verilecek.
Senaryo3: x<1 –> f(x) = x^2 + 3x; x >= 1 –> 3x + 4 fonksiyonunu hesaplayan program.
Eğitimim için kullandığım örnekleri bu adresteki github reposunda saklıyorum. Ders başlığıyla eşit olan klasörde kaynak kodları bulabilirsiniz.
Senaryo1
#include <stdio.h> #include <stdlib.h> int main(int argc, char** argv) { int year; puts("Enter a year, please:"); scanf("%d", &year); if(year < 0) { puts("You have to enter positive integer."); } else { if( (year % 4) == 0 ) { if( (year % 100) == 0 ) { if( (year % 400) == 0 ) puts("Leap year!"); else puts("Not leap year!"); } else puts("Leap year!"); } else puts("Not leap year!"); } /** * Alternative solution * (http://stackoverflow.com/questions/3220163/how-to-find-leap-year-programatically-in-c) * if ((year & 3) == 0 && ((year % 25) != 0 || (year & 15) == 0)) { puts("Leap year!"); } else { puts("Not leap year!"); } * */ return (EXIT_SUCCESS); }
Senaryo2
#include <stdio.h> #include <stdlib.h> int main(int argc, char** argv) { char paintType; float sm, cost; float A = 100.00, B = 125.00, C = 135.45; puts("Enter paint type (A, B, C), please:"); scanf("%c", &paintType); switch(paintType) { case 'a': case 'A': puts("How many square meters will paint?"); scanf("%f", &sm); cost = A * sm; printf("Total cost: %.2f", cost); break; case 'b': case 'B': puts("How many square meters will paint?"); scanf("%f", &sm); cost = B * sm; printf("Total cost: %.2f", cost); break; case 'c': case 'C': puts("How many square meters will paint?"); scanf("%f", &sm); cost = C * sm; printf("Total cost: %.2f", cost); break; default: printf("Sorry, we don't have %c paint type", paintType); break; } return (EXIT_SUCCESS); }
Senaryo3
#include <stdio.h> #include <stdlib.h> int main(int argc, char** argv) { float x, fx; puts("Enter a number please:"); scanf("%f", &x); if(x >= 1) { fx = (3*x) + 4; } else { fx = (x * x) + (x*3); } printf("f(x) = %.3f", fx); return (EXIT_SUCCESS); }
Yorumlar