Veri Tipleri etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
Veri Tipleri etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

30 Nisan 2015 Perşembe

C Programlama Ders 3 - Aritmatiksel İşlemler ve Veri Dönüştürme

İlk bilgisayarların oda büyüklüğünde hesap makineleri olduğunu hatırlarsak, bilgisayarlar ve buna bağlı olarak programlar temelde işlem yapabilme yetenekleri üzerine kurulmuşlardır demek hiç de zor olmaz. C'de dört işlem yapma, temel seviyede bir matematik bilgisine sahip herkesin hiç zorlanmadan yapabileceği bir eylemdir. Kullanılan işaretler günlük hayatta matematik işlemlerinde kullandığımız işaretlerden farklı değildir. Matematik bilimindeki öncelik sırası, bire bir C programlama dili için de geçerlidir.

Bu dersteki örnekleri dikkatle incelediğinizde aritmetik işlemlere dair kafanızda bir soru işareti kalmayacaktır. Yapılan işlemlerin yanına yorum ekleyerek özel durumların gözünüzden kaçmaması için dikkatinizi çekmeye çalıştım.

İlk olarak bütün ders boyunca kullanacağımız tamsayı değişkenlerini tanımlayalım. (Dersin devamında sırası geldikçe bunlara değerler atayıp farklı işlemlerde kullanacağız.) Ardından tam1 ve tam2 değişkenine değer ataması yapalım:
int tam1,tam2,tam3,tam4;   

tam1= 1453;  
tam2= 16;

// Değerlerini değiştirmek için tekrar tanımlamaya gerek yoktur.

tam1= 19;   // tam1 artık 19'u temsil ediyor.
tam2= -67;  // tam2 artık -67'yi temsil ediyor.
//...
Şimdi tam1 ve tam2 sayılarını kullanarak matematiksel işlemler yapalım.
//...
tam1= 3+5;    // =8
tam2= 3+5*10; // =53  "Çarpma işlemi öncelikli.
++tam1;       // =9 "tam1'i 1 arttırır.
--tam2;       // =52 "tam2'yi bir azaltır.
tam1+=6;      // =15 "tam1'e 6 ekler.
tam2-=2;      // =50 "tam2'den 2 çıkarır.
//...
Peki eşitliğin her iki tarafında da aynı değişken olursa ne olur?
Bilinmelidir ki her zaman eşitliğin sağ tarafı önceliklidir. Sağ taraftaki işlem bittikten sonra sola aktarılır.
//...
// Önceki durum: tam1=15 - tam2=50
tam1=tam1+2;          // =17 "(15)+2=17
tam2=tam2-(tam1+10);  // =23 "(50)-(17+10)=23
//...

Önemli


C programlama dilinde aritmetik işlemlerde eşitliğin sağ tarafındaki sayılardan hiçbiri gerçel sayı(float veya double) değilse sonuç her zaman tam sayı çıkar. Bu durum kesme hatası (truncation error) olarak adlandırılır.

Örneğin 5/2=2.5 olması beklenir.
Fakat C'de bunun sonucu 5/2=2 şeklidedir.

C'nin tamsayılarla bölme mantığını şu algoritmayla daha iyi anlayabilirsiniz: (Bu algoritmanın bilinmesi gerekmez. Kafanızı karıştıracak gibiyse bu 3 adımı atlayın.)

Tam sayılarla 5/2 işlemi;
I.    5-2=3      bölüm=1 kalan=3      (Fark 0'dan büyük old. için kalana aktarıldı ve bölüm 1 arttı.)
II.   3-2=1      bölüm=2 kalan=1      ( I. Adımla aynı )
III.  1-2=-1                                          (Fark 0'dan küçük old. için bu adım atlandı ve işlem sonlandı.)

Böylelikle 5/2 işleminin sonucu 2 olur ve kalan 1'dir.

Mod Operatörü (%)


Bir bölme işleminden kalanı öğrenmek için ise mod operatörünü kullanırız. Mod alma işlemi bir sayının başka bir sayıya bölümünden kalan sayıyı döndürür. 5/2 işlemine mod uygularsak 1 döner. Mod operatörü %(yüzde) işareti ile uygulanır:

  • (bölünen) % (bölen)
Örnek:
15%6 işlemi 3'e eşittir.
"15 mod 6" veya "15'in 6'ya bölümünden kalan" diye okunabilir.

Tam sayılarla bölme işlemine ve mod operatörüne örnek olarak şu uygulamaya inceleyelim.
//...
tam3= 15/6;  // =2 " 2,5 değil !
tam4= 15%6;  // =3 " 15/6 'dan kalan=3
//...
Yani önemli başlığı altında verdiğim bilgi ve bu uygulama ışığında bölme işleminde işleme tabi tutulan sayıların hepsi tam sayı ise gerçek sonucun virgülden sonrası kesilir diyebiliriz.

Acaba eşitliğin sol tarafında integer değil de float tipinde bir değişken olsaydı sonuç olarak virgülden sonrası döner miydi? Eğer az önce belirtmeye çalıştığım durum anlaşıldıysa ve "eşitliğin sağ tarafındaki" ile "işleme tabi tutulan" kelimelerini neden kalın puntolarla yazdığımı farkettiyseniz bu soru size kolay gelmiştir.
Hadi deneyelim ve sonucu görelim.
Bir önceki işlemi gerçel sayılar için kullanılan float veri tipine uygulayalım.
//...
//Önceki durum: tam1=17- tam2=23 - tam3=2 - tam4=3

float ondalik1, ondalik2, ondalik3, ondalik4, ondalik5, ondalik6;

ondalik1=9/4;       // =2,00  " 9/4=2  -  2,25 değil !
ondalik2=tam1/tam4; // =5,00 " 17/3=5 -  5,67 değil !
//...
Not: Virgülden sonraki sıfırları gerçel sayı olduğunu belirtmek için yazdım. Çıktı aldığınızda da aksini belirtmediğiniz sürece 0'lar gözükecektir. Dersin sonundaki çıktıları inceleyebilirsiniz. 

Gördüğünüz gibi sonuca virgülden sonra 0'ların eklenmesinden başka birşey değişmedi.

Peki neden float bir değişkene atama yapmamıza rağmen virgülden sonrası dikkate alınmadı?
Bunun çok basit bir cevabı var.

Eşitliğin sağ tarafı, sol tarafa tam sayı bir değer gönderiyor. Dolayısıyla sol taraf ondalıklı bir sayı kabul etmesine rağmen tam sayıyla yetinmek zorunda kalıyor. O da kendine gelen tam sayıya virgülden sonra 0'lar ekleyerek gerçel sayı yapıyor. O zaman şunu sormamız gerekiyor.Ne yapmalıyız ki sağ taraftaki işlemin sonucu ondalık bir değer çıksın. Böylelikle sol tarafa virgüllü bir değer göndersin.

Bunun için işleme giren sayılardan sadece birini gerçel sayıya dönüştürmemiz yeterli. Bunu yaparsak C bizim gerçel sayılarla işlem yaptığımızı anlar ve diğer değişkenleri otomatik dönüştürür. Ve sonuç olarak kayıp vermeden bir gerçel sayı elde etmiş oluruz.
O halde tip dönüşümü nasıl yapılır gösterelim:

  • (hedef tip)değişkenIsmi 
Örnek:
(float)tamSayi1;     (Float tipine dönüştürür.)
(int)ondalik1;         (Tam sayı tipine dönüştürür.)

 Şimdi uygulamamıza bakalım.
//...
//Önceki durum: tam2=23 - tam3=2 - ondalik1=2,00 - ondalik2=5,00

ondalik3=(float)tam2/tam3;  // =11,5  " 23,00/2 (tam2 dönüştürüldü)
ondalik4=tam2/(float)tam3;  // =11.5  " 23/2,00 (tam3 dönüştürüldü)
ondalik5=5.00/2;            // =2,5  " 5 sayısı float tipte yazıldı
ondalik6=ondalik2/tam3;     // =2,5   " ondalik2 float old. için dönüştürmeye gerek yok.
//...
Dönüştürme örneklerinde dikkat ettiyseniz sadece bir değişkene dönüştürme uyguladık. İsterseniz ikisine de uygulayabilirsiniz, bir şey farketmediğini, aynı sonucu verdiğini göreceksiniz.

Son olarak sonuçları ekrana yazdıralım ve doğruluğunu kontrol edelim. Yaptığımız tüm işlemlere çıktı şu şekilde olmalı:

  • tam1=17
  • tam2=23
  • tam3=2
  • tam4=3
  • ondalik1=2,00
  • ondalik2=5,00
  • ondalik3=11,5
  • ondalik4=11,5
  • ondalik5=2,5
  • ondalik6=2,5
//...
printf("Degisken Adi - Degeri\n");
printf("tam1=          %d\n",tam1);
printf("tam2=          %d\n",tam2);
printf("tam3=          %d\n",tam3);
printf("tam4=          %d\n",tam4);
printf("ondalik1=      %f\n",ondalik1);
printf("ondalik2=      %f\n",ondalik2);
printf("ondalik3=      %f\n",ondalik3);
printf("ondalik4=      %f\n",ondalik4);
printf("ondalik5=      %f\n",ondalik5);
printf("ondalik6=      %f\n",ondalik6);
//...

Çıktıda float tiplerin sonundaki fazladan 0'lar dikkatinizi çekmiştir. Bunları yok etmek veya azaltmak gerekebilir. Belirteçler üzerinde yapacağımız ufak dokunuşlarla bu mümkün.

Aşağıdaki çıkış ifadesinde %f'lerin aralarına yazılan .0 ve .2 lere dikkat ediniz.
//...
printf("\nVirgulden Sonrasiz Float Yazdirmak\n");
printf("ondalik1=      %.0f\n",ondalik1);
printf("ondalik2=      %.0f\n",ondalik2);
printf("ondalik3=      %.0f\n",ondalik3);
printf("ondalik4=      %.0f\n",ondalik4);
printf("ondalik5=      %.0f\n",ondalik5);
printf("ondalik6=      %.0f\n",ondalik6);

printf("\nVirgulden Sonra 2 Rakamli Float Yazdirmak\n");
printf("ondalik1=      %.2f\n",ondalik1);
printf("ondalik2=      %.2f\n",ondalik2);
printf("ondalik3=      %.2f\n",ondalik3);
printf("ondalik4=      %.2f\n",ondalik4);
printf("ondalik5=      %.2f\n",ondalik5);
printf("ondalik6=      %.2f\n",ondalik6);

Bu dersimizi de burada sonlandıralım. Bir daha ki dersimizde kullanıcı tarafından programa veri girilmesini sağlayan scanf() fonksiyonunu anlatacağız. 

23 Nisan 2015 Perşembe

C Programlama Ders 2 - Veri Tipleri ve Değişkenler

Tıpkı matematik bilimindeki sembolik ifadeler gibi programlama dillerinde de sayı veya metin gibi verileri sembolik bir adlandırmayla tutarız. Bu sembolik adlandırmalara değişken denir. Her değişken bellekte işletim sistemine ve derleyiciye bağlı olarak 1 ile 16 bayt arasında belirli bir alan işgal eder ve işgal ettiği bu alanın adresi ile çağrılır ve kullanılır. Her bir değişken; metin, tamsayı, gerçel sayı gibi farklı veri tiplerinden sadece birini tutabilir. Bu yüzden değişkene değer atamadan önce onun veri tipini tanımlamak gerekir.

C programlama dili, veri tipi bakımından oldukça zengin bir dildir. Dört temel veri tipi bulunmaktadır. Bunlar;

  • char - Tek karakter veya küçük tamsayı
  • int - Tam sayı
  • float - Tek duyarlı gerçel sayı (7 basamak)
  • double - Çift duyarlı gerçel sayı (15 basamak)
Ek olarak bu veri tiplerinin önüne gelerek onların türevlerini oluşturan niteleyiciler vardır. Bunlar da;

  • short (kısa) 
  • long (uzun) 
  • unsigned (işaretsiz) 
Niteleyicilere ihtiyaç duyulmasının sebebi her veri tipinin sınırlarının olmasıdır. short bir veri tipinin sınırlarını daraltırken, long ise veri tipinin sınırlarını genişletir. Unsigned ise negatif tarafı yok edip bunu pozitif tarafa ekler. Dolayısıyla alt sınır 0 olurken pozitif sınır 2 katına çıkar. Burada dikkat etmemiz gereken nokta sınırlar genişledikçe bellekte kaplayacağı alanın da doğal olarak artıyor olmasıdır.

Farklı işletim sistemleri ve derleyicilerde veri tipinin kapladığı alan değişkenlik gösterir. Buna bağlı olarak veri tipinin sınırları da değişir. Bunun hesaplanmasında standart kütüphanedeki sizeof() fonksiyonundan yararlanılır. Bu fonksiyonu ayrı bir bölümde anlattık merak edenler fonksiyon isminin üzerine tıklayıp inceleyebilir fakat kullanımını anlayabilmek için bu dersi tamamlayıp, belirteçleri öğrenmiş olmak gerekli ve yeterlidir.

Değişken Tanımlama ve Değer Atama

C programlama dilinde değişkenlerin kullanabilmesi için önceden tanımlanması gerekir. Böylelikle değişkene bellekte bir adres tayin edilir ve o adres değişkenin kimliği olur. Değişken tanımlama(declare) şu şekilde yapılır:

  • degiskenTipi degiskenAdi;

Değişken adını belirlemede sınırlayıcı kurallar vardır. Bu kurallar;

  • Değişken adları İngilizce karakterler (A-Z) veya (a-z) yada rakamlar (0-9) ile yazılmalıdır. Türkçe karakterler, özel karakterler veya boşluk karakteri kullanılamaz. (Alt tire ( _ ) kullanılabilir.) 
  • Değişken adları rakamla başlayamaz. İlk karakter bir harf olmalıdır. Sonrasında rakam kullanılabilir.
  • C 'nin anahtar kelimeleri (Key Words) değişken ismi olarak kullanılamaz. Bu anahtar kelimeler;
autodoubleintstruct
breakelselongswitch
caseenumregistertypedef
charexternreturnunion
constfloatshortunsigned
continueforsignedvoid
defaultgotosizeofvolatile
doifstaticwhile

Aşağıdaki tanımlamaları inceleyiniz.
#include <stdio.h>

void main()
{
 //Bu kodlar belirttiğimiz hatalardan dolayı derlenmez.
 
 char karakter1,harf6;  // GEÇERLİ
 int tamSayi,tam2,sayi;  // GEÇERLİ
 float ondalik1;    // GEÇERLİ
 double ondalik2;   // GEÇERLİ
 int tam_sayi;    // GEÇERLİ (Alt tire (_) serbest)
 
 int ondalik1;  // HATA (ondalik1 önceden tanımlandı.) 
 int sayı;   // HATA (Türkçe karakter kullanılamaz.)
 int 1tamSayi;  // HATA (Rakamla başlayamaz.)
 int tam sayi;  // HATA (Boşluk kullanılamaz.)
 int tam-sayi;  // HATA (Özel karakter kullanılamaz.)
 int double;   // HATA (Anahtar kelimeler kullanılamaz.)
}

Tanımlanan değişkenlere, türüne uygun herhangi bir değer atayabiliriz. Şimdi bir uygulama yapalım.
#include <stdio.h>

void main()
{
 char krk1,krk2,krk3,krk4;
 int tam1,tam2,tam3,tam4,tam5,tam6;
 float float1;
 double double1; 

 krk1='Z';
 tam1=1453;
 float1=987.123;
 double1=1234.9876;
 
 tam2=310.95; // Geçerlidir Fakat virgülden sonrasını keser.
 tam3=tam4=409; // Geçerlidir iki değişken de 409'a eşitlenir.
 krk2='4';  // Geçerlidir değer olarak 4'ü tutar.
 krk3='MA';  // Geçerlidir Fakat değer olarak ilk harfi tutar.
 krk4=18;  // Geçerlidir Fakat değer olarak rakam tutmaz..
     // ..ACCII tabloda o rakama düşen karakteri tutar.
 
 printf("Degisken Adi  Degeri\n");
 printf("krk1          %c\n",krk1);
 printf("krk2          %c\n",krk2);
 printf("krk3          %c\n",krk3);
 printf("krk4          %c\n",krk4);
 printf("tam1          %d\n",tam1);
 printf("tam2          %d\n",tam2);
 printf("tam3          %d\n",tam3);
 printf("tam4          %d\n",tam4);
 printf("float1        %f\n",float1);
 printf("double1       %lf\n",double1);
}

Yukarıdaki örnekte printf fonksiyonlarını incelediğimiz zaman, derslerimizde daha önce karşılaşmadığımız bir takım işaretler görüyoruz. %c, %d, %f, %lf gibi. Bunlara belirteç adı veriliyor. Değişkenleri bu belirteçler yardımıyla okuyabiliyor ve sonraki dersimizde göstereceğim şekilde veri girişi yapabiliyoruz. Derleyici herhangi bir belirteç yakaladığı an orayı atlıyor ve sırası geldiğinde bu belirtecin olduğu yere ilgili değişkenin değerini gönderiyor. 1'den fazla belirteç olduğu durumlarda değişken isimlerini girerken sıraya dikkat etmek gerekir.

Veri tipleri için kullanılan belirteçleri aşağıdaki tablodan görebilirsiniz. Kutu içine aldıklarım temel veri tipleri, diğerleri ise bunların türevleridir.
C How To Program adlı kitaptan alınmıştır.

Belirteçlerin nerde ve nasıl kullanıldıklarını anlamak için bir önceki örneği tekrar dikkatli bir şekilde inceleyebilirsiniz. Sonraki derslerimizde bunları bolca kullanarak pekiştirmiş olacağız. Biz bu dersimizi burada noktalarken merak edenler, veri tiplerinin boyutlarını öğrenmek için kullanılan sizeof() fonksiyonunu üzerine tıklayarak inceleyebilir.

sizeof() Fonksiyonu

Her veri tipi bellekte 1 ile 16 byte arası bir alan kaplar. Kapladıkları bu alan işletim sistemine ve derleyiciye göre farklı boyutlarda olabilir. Bu nedenle C Standart Kütüphanesinde bunun hesabını yapan bir fonksiyon bulunur. Bu fonksiyon sizeof() fonksiyonudur.

Kullanımı:

  • sizeof(veriTipi)
Geriye değer olarak bir tamsayı döndürür. Dolayısıyla belirteç olarak tamsayıyı ifade eden %d kullanılır.

#include <stdio.h>

void main()
{
 printf( "Veri Tipi        Boyut  \n");
 printf( "========================\n");
   printf( "char           : %d bayt\n", sizeof(char));
   printf( "short          : %d bayt\n", sizeof(short));
   printf( "int            : %d bayt\n", sizeof(int));
   printf( "long           : %d bayt\n", sizeof(long));
   printf( "unsigned char  : %d bayt\n", sizeof(unsigned char));
   printf( "unsigned short : %d bayt\n", sizeof(unsigned short));
   printf( "unsigned int   : %d bayt\n", sizeof(unsigned int));
   printf( "unsigned long  : %d bayt\n", sizeof(unsigned long));
   printf( "float          : %d bayt\n", sizeof(float));
   printf( "double         : %d bayt\n", sizeof(double));
   printf( "long double    : %d bayt\n", sizeof(long double));
}


Eğer sizin de bilgisayarınız 64bit işletim sistemine sahipse ve derleyici olarak TDM-GCC kullanıyorsanız bu programı çalıştırdığınızda aynı çıktıyı üretecektir.


Uyarı: DevC++ bir derleyici değildir. Tümleşik geliştirme ortamı, yani IDE'dir (Integrated development environment). İçinde derleyici, yorumlayıcı, hata ayıklayıcı, kod yazım editörü ve programcıya kolaylık sağlayan çeşitli araçlar barındıran bileşik bir yazılımdır. 5 ve üstü sürümlerinde derleyici olarak TDM-GCC kullanmaktadır.