İçeriğe geç →

C Programlama Dersi – 3

Selam,

En son kaldığımız yerden devam edelim. Bu derste geçen derste öğrendiklerimi biraz daha detaylıca öğrenmeye çalışacağım.

Önemli bir konu daha var aslında: “Okunabilir Kod Yazmak“. Henüz yolun başındayken belirli standartları öğrenip, alışkanlık haline getirmek önemli. Bunu ayrı bir konu başlığı olarak ele almayı düşünüyorum.

IDE olarak Netbeans’e geçiş yaptım bu arada. Bu gereksiz bilgiden sonra devam ediyorum.

 printf()

Buraya kadar printf() ile hep düz metinler yazdım. Arada bir değişken de yazdırdım ama printf()‘in hakkını tam vermedim. printf()‘in sonundaki “f” formatlı çıktıyı belirtiyor. Bugün de biraz formatlı çıktılar yapalım.

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char** argv) {
    int x=3, y=5;
    printf("%d", x+y); // x ve y değişkenlerini toplayıp sonucu yazar. Yani 8
    return 0;
}

Yeni satıra geçmek için n kullanıyorduk. n aslında “kaçış karakter”lerinden (escape sequence) sadece birisi. “Ne kaçması ne karakteri?” dersen şöyle bir örnekle açıklayayım:

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
    printf(" " ");
    return 0;
}

Yukarıda ekrana yazdırmaya çalışıyorum. Bakalım kod çalışınca ne olacak?

main.c: In function 'main':
main.c:7:16: warning: missing terminating " character [enabled by default]
 printf(" " ");
 ^
main.c:7:5: error: missing terminating " character
 printf(" " ");
 ^
main.c:8:5: error: expected ')' before 'return'
 return 0;
 ^
main.c:9:1: error: expected ';' before '}' token
 }
 ^

 

nasıll?!

Neye niyet neye kısmet? Güzel bir hata mesajı aldık. Aslında her şeyi doğru yazmıştım. printf() ile yazdırmak için ” “ arasında metni girmem yeterliydi.

printf(" " ") yakından bakarsak, ilk 2 çift tırnak zaten metni almak için hazır. Sonradan gelen 3. çift tırnak ise programın kafasında deli sorular oluşmasına sebep oluyor. Bunu engellemek için programa ortadaki çift tırnağın, farklı olduğunu anlatmamız gerek. İşte şöyle:

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
    printf(" " ");
    return 0;
}

Çıktı:

"

Görüldüğü üzere görev başarıyla sonuçlandı. Aynı şekilde  yazdırmak için \ yazmamız gerekirdi. gantep.edu‘dan aldığım tabloda diğer kaçış karakterli mevcut.

Karakter Anlamı
a Ses üretir (alert)
b imleci bir sola kaydır (backspace)
f Sayfa atla. Bir sonraki sayfanın başına geç (formfeed)
n Bir alt satıra geç (newline)
r Satır başı yap (carriage return)
t Yatay TAB (horizontal TAB)
v Dikey TAB (vertical TAB)
" Çift tırnak karakterini ekrana yaz
' Tek tırnak karakterini ekrana yaz
\ karakterini ekrana yaz
%% % karakterini ekrana yaz

printf()‘in marifetleri bu kadar değil. Şimdi de biraz veri tiplerini formatlayalım.

İlk önce int, float ve double veri tipinde sayıları yazdırıyorum:

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
    int intSayi = 35;
    float floatSayi = 12;
    double doubleSayi = 1;
    
    printf("int: %dn", intSayi);
    printf("float: %fn", floatSayi);
    printf("double: %lfn", doubleSayi);
    
    return 0;
}

Çıktı:

int: 35
float: 12.000000
double: 1.000000

float ve double tanımladığım sayılara otomatik olarak 6 basamak ondalık ekledi. Çünkü float ve double ondalıklı değerleri tutuyor. Peki, bana ondalıklı sayı lazım ama 6 tane ondalığa gerek yok. 2 tane ondalık yeter. Bu durumda ne öreceğiz?

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
    int intSayi = 35;
    float floatSayi = 12;
    double doubleSayi = 1;
    
    printf("float:%.2fn", floatSayi); //ondalık alan için 2 basamak göster
    printf("double:%.4lfn", doubleSayi); //ondalık alan için 4 basamak göster
    
    return 0;
}

Çıktı:

float:12.00
double:1.0000

.2” yazarak, floatSayi değişkeninin ondalık alanı için 2 değer gösterilmesini istediğimi söyledim. doubleSayi için ise “.4” diyerek ondalık alan için 4 değer göstermesini sağladım.

Biraz daha farklı durumlara bakalım.

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
    int intSayi = 35;
    float floatSayi = 12.53;
    double doubleSayi = 13.1789;
    
    printf("float:%5.2fn", floatSayi); 
    printf("double:%8.5lfn", doubleSayi); 
    
    return 0;
}

Çıktı:

float:12.53
double:13.17890

floatSayi için 5 basamaklı bir sayı olacağını ve ondalık alan için 2 basamak gösterilmesi gerektiğini belirttim. “.” yı saymayı ihmal etmiyoruz. Yani şöyle; 12 . 53 , toplamda 5 basamak sayılıyor.

doubleSayi için ise, 8 basamaklı bir sayı dedim. Ondalık alan için de 5 basamak yer istedim. Lakin doubleSayi‘nın değeri 13.1789 olduğu için ondalık alanda boş kalan değerleri 0 ile dolduruyor.

Yukarıda sayıları yazdırırken gerektiği kadar hatta fazla fazla yazdırdım. Peki 8 basamaklı sayıyı daha düşük basamaklı yazdırırsam ne olur? Test edip görelim.

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
    printf("%5.2fn",12.346);
    printf("%5.3f",12.346);
    printf("%7.3f",12.346);
    return 0;
}

İlk printf() de 5 basamaklı bir sayı olacağını ve virgülden sonra 2 basamak yazmasını istedim.

İkinci printf() de ise  5 basamaklı bir sayı olacağını ve virgülden sonra 3 basamak yazması gerektiğini belirttim. Ama 12.346 sayısı bizim için “.” da sayıldığı için 6 basamaklı.

Üçüncü printf() ise ondalık alanı 3 basamak olacak şekilde 7 basamaklı bir sayı yazacak.

Bakalım çıktılar nasıl olacak?

12.35
12.346
 12.346

İlk printf() de virgülden sonra 3 basamak olmasına rağmen 2 basamak istediğim için sayıyı benim için yuvarladı. 12.346 sayısında olduğu gibi 0.5 ve üstü değerler bir üst değere yuvarlanıyor.

İkinci printf() ise virgülden sonra 3 basamak yazıyor. Daha sonra bakıyor ki sayı 5 basamaklı olacak denilmiş ama yazması gereken 3 basamak daha var. Yani toplamda 6 basamak ediyor. Bu durumda otomatik olarak genişliyor ve sayıyı tam olarak yazıyor.

Üçüncü printf() ise 6 basamaklı bir sayı yazacak olmasına rağmen bakıyor ki 7 basamaklıkmış gibi yazdırılması istenmiş. Virgülden sonra 3 basamak yazıyor ve geriye yazması gereken 4 basamak kalıyor. “12.” yazdıktan sonra hala yazması gereken bir basamak daha var. “Ne yapayım ne edeyim” deyip sayının önüne bir boşluk atarak uzaklaşıyor.

 

güzell!

Değişkenlerin Duyarlılığı

Geçtiğimiz derste değişkenlerin farklı veri tipleri tuttuğunu öğrenmiştim. Her değişken farklı aralıklarda değerleri tutabiliyordu. gantep.edu‘daki şu tabloya bir göz atalım:

Veri Tipi Açıklama Bellekte işgal ettiği boyut (bayt) Alt sınır Üst sınır
char Tek bir karakter veya
küçük tamsayı için
1 -128 127
unsigned char 0 255
short int Kısa tamsayı için 2 -32,768 32,767
unsigned short int 0 65,535
int Tamsayı için 4 -2,147,483,648 2,147,483,647
unsigned int 0 4,294,967,295
long int Uzun tamsayı için 8  -9,223,372,036,854,775,808 9,223,372,036,854,775,807
unsigned long int 0  18,446,744,073,709,551,615
float Tek duyarlı gerçel sayı için (7 basamak) 4 -3.4e +/- 38 +3.4e +/- 38
double Çift duyarlı gerçel sayı için (15 basamak) 8 -1.7e +/- 308 +1.7e +/- 308

Her değişkenin sınırları farklı olduğu gibi kapladıkları alanda farklı. “Beyin bedava, at beyine” demiştim ama değişkenlerin bilgiyi attığı ramler bedava değil. Ekonomik kullanmak zorundayız. Böylece yazdığımız programlar daha stabil ve performanslı çalışacaktır. “Hocam, bana 1 baytın hesabını mı yapıyorsun? Ram benim, değişken benim. double basıp geçicem ben!” diye düşünebilirim. Üstelik günümüzdeki bilgisayarlarının ramlerinin de Maşallah’ı var hani. Ama hazırladağımız programı aynı anda binlerce, milyonlarca kişi kullanırsa ne olacak? 1 x 1.000.000 bayt ya da 8 x 1.000.000. Binlerce kişi kullanmasa bile 1 bayt alan için neden 8 bayt harcayıp israf yapalım? Neden bilgisayarı 8 kat hızlı çalıştıracakken yavaşlatalım? Son sözü halka bırakıyorum.

Şimdi gelelim kullandığımız veri tipine göre nasıl sonuçlar alıyoruz? Değişkenlerin sahip olduğu duyarlılığı daha iyi görebilmek için bazı matematiksel işlemler yapacağız. Daha duyarlı demek daha doğru sonuçlar demek.

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
    int intSonuc = 22 / 7;
    float floatSonuc = 22.0 / 7.0;
    double doubleSonuc = 22.0 / 7.0;
    long double longDoubleSonuc = 22.0 / 7.0;
    
    printf("Standart Duyarlılıkta Sonuçlarn");
    printf("int: %dn", intSonuc);
    printf("float: %fn", floatSonuc);
    printf("double: %lfn", doubleSonuc);
    printf("longdouble: %Lfn", longDoubleSonuc);
    
    printf("Ondalık Alan için 10 basamaklı Sonuçlarn");
    printf("int: %.10dn", intSonuc);
    printf("float: %.10fn", floatSonuc);
    printf("double: %.10lfn", doubleSonuc);
    printf("longdouble: %.10Lfn", longDoubleSonuc);
    
    printf("Ondalık Alan için 20 basamaklı Sonuçlarn");
    printf("float: %.20fn", floatSonuc);
    printf("double: %.20lfn", doubleSonuc);
    printf("longdouble: %.20Lfn", longDoubleSonuc);
    
    printf("Ondalık Alan için 30 basamaklı Sonuçlarn");
    printf("float: %.30fn", floatSonuc);
    printf("double: %.30lfn", doubleSonuc);
    printf("longdouble: %.30Lfn", longDoubleSonuc);
    
    printf("Ondalık Alan için 40 basamaklı Sonuçlarn");
    printf("double: %.40lfn", doubleSonuc);
    printf("longdouble: %.40Lfn", longDoubleSonuc);
}

Biraz uzun oldu ama değişkenlerin ne kadar duyarlı olduğunu şimdi çok daha iyi görebilirim. Çıktıyı alalım:

Standart Duyarlılıkta Sonuçlar
int: 3
float: 3.142857
double: 3.142857
longdouble: 3.142857

Ondalık Alan için 10 basamaklı Sonuçlar
int: 0000000003
float: 3.1428570747
double: 3.1428571429
longdouble: 3.1428571429

Ondalık Alan için 20 basamaklı Sonuçlar
float: 3.14285707473754882812
double: 3.14285714285714279370
longdouble: 3.14285714285714279370

Ondalık Alan için 30 basamaklı Sonuçlar
float: 3.142857074737548828125000000000
double: 3.142857142857142793701541449991
longdouble: 3.142857142857142793701541449991

Ondalık Alan için 40 basamaklı Sonuçlar
double: 3.1428571428571427937015414499910548329353
longdouble: 3.1428571428571427937015414499910548329353

Varsayılan olarak değişkenleri yazdırdığımızda ilk olarak int‘in sadece 3 yazdırdığını görüyoruz. E, çokta tabii değil mi Allah aşkına? Çünkü int tam sayı değerleri tutmak için. Ondalık değerlerle işi yok.

Duyarlılığı 10 basamak arttırdığımızda, ayıp olmasın diye bir kez daha int’i de yazdırdım, float‘ın diğerlerinden koptuğunu görüyoruz.

20 basamak olarak hesap yaptığımızda float iyice kopmuş durumda fakat double ve long double aynı hassasiyette hesaba devam ediyorlar. Bakalım kim daha duyarlı? Çok heyecanlı. Gerçi sonucu biliyorum ama olsun 🙂

30 basamak olduğunda float pes ediyor. double ve long double hala baş başa.

40 basamak için baktığımızda double ve long double arasında yine fark olmadığını görüyoruz.

Görüldüğü üzere double veri tipi int ve float‘a göre daha fazla duyarlılığa sahip. Aradaki hesaplama farklılıkları nereden geliyor diyorsanız, veri tipinin algoritmasıyla alakalı bir durum. Detayları bende tam bilmiyorum ama aldığım istihbarata göre buradaki ve buradaki sayfalarda detaylı bilgi fazlasıyla mevcut. Gönül isterdi ki bunları çevirip şuraya bir özet çıkarayım ama şimdilik usulca diğer konuya geçiyorum.

Sabitler

Değişkenlerin tuttuğu verilerin program akışında değişebileceğini hatırlarsın. Ama değişkenlerin değişmesini engelleyebiliriz. Sabit bir değerde tanımlayabiliriz. Nasıl mı?

2 seçeneğimiz var: const ve #define

İki komut sabit tanımlamaya yarasa da  aralarında ciddi farklar bulunuyor öğrendiğim kadarıyla. Bu farklara az sonra değinirim. Şimdi nasıl sabit tanımlayacağımıza bakalım:

#include <stdio.h>
#include <stdlib.h>

const int HEDEF = 50; // const ile sabit tanımlama
#define PI 3.14 // #define ile sabit tanımlama
#define YAZDIR printf // #define'ın önemli farklarından biri

int main(int argc, char** argv) {
    //#define ile sabit kullanımına örnek
    float alan, r=2.7;
    printf("#define ile sabit kullanımına örnekn");
    alan = r*r*PI;
    YAZDIR("Alan: %.2fnn",alan);
    
    //const kullanımına örnek
    int simdi=13, kalan;
    printf("const kullanımına örnekn");
    kalan = HEDEF - simdi;
    printf("Hedefe %d adım kaldı.", kalan);
}

Yukarıda kodda ilk bakışta #define ile const arasındaki açık farklar belli oluyor.  const ile normal bir değişken tanımlarmış gibi davranıyorum. Tek yapmam gereken değişkenin sabit olduğu belirtmek için başına const eklemek.

#define ise tüm ezberleri bozuyor. const ile sabit tanımlamaktan çok farklı. Ayrıca 6. satırdaki tanımlamanın 13. satırda nasıl kullanıldığına bakar mısınız efenim? Çok garip değil mi? “YAZDIR” gördüğü zaman “printf” yazması gerektiğini anlıyor.

#define‘ın marifetleri bu kadar değil. Yeri gelince daha fazla değinirim ama şunu belirtmekte fayda var. #define ön işlemci komutlarından birisi ve bunları kullanırken oldukça dikkatli olmak gerekir. Birçok fayda sağlasada hata yapma ihtimalini de arttırır.

Mesela 13. satırdaki YAZDIR tanımlaması kötü bir sabit tanımlamasıdır. C dilinde zaten standartı olan bu fonksiyonu kendimize göre tanımlayarak, bizden sonra gelen kişilerin kodu okumasını ve anlamasını zorlaştırırız.

Önemli bir diğer nokta ise sabitlere isim verirken büyük harf kullanmak. Böylece kodları okurken bunun sabit olduğunu anlayabiliriz. Program içinde sabit değerler değiştirilemeyeceği için, diğer değişkenlerle karışmaması adına böyle bir standart oluşmuş sanırım.

Yeri geldikçe bu konulara daha sık değinirim. Yukarıdaki kodun çıktısını vererek devam edelim:

#define ile sabit kullanımına örnek
Alan: 22.89

const kullanımına örnek
Hedefe 37 adım kaldı.

 scanf()

Veri girişi için kullandığımız scanf() ile ilgili birkaç önemli nokta var.

  • scanf(), enter’a basılana kadar veri alır.
  • tek scanf() fonksiyonu ile birden fazla veri girişi yapılabilir. Ayrıca verilerin tipi farklı olabilir.
#include <stdio.h>
#include <stdlib.h>
int main(){
    int s1, s2;
    float s3;
    
    scanf("%d%d", &s1, &s2);
    printf("s1: %d, s2: %d", s1, s2);

return 0;
}

Yukarıdaki kod için şu değerleri giriyorum:

  • 1 ↵ (enter) 7 ↵
  • (boşluk) 1 ◊ 7 ◊ ↵
  • 1◊7↵

Hepsi için çıktı ortak:

s1: 1, s2: 7

Veri tipine uygun değer girmezsek sonuç ne olur?

#include <stdio.h>
#include <stdlib.h>
int main(){
    int s1, s2;
    float s3;
    
    scanf("%f%d", &s3, &s1);
    printf("s1: %d, s3: %f", s1, s3);
return 0;
}

Yukarıdaki kod için 1 ve 7.3 değerlerini girersem çıktı:

s1: 7, s3: 1.000000

float için girdiğim sayıya otomatik olarak ondalık ekledi ve int için girdiğim ondalıklı sayının sadece tam kısmını aldı.

Önemli bir nokta ise placeholder’a uygun veri tipi yazılmazsa ne olur? Yani şöyle:

#include <stdio.h>
#include <stdlib.h>
int main(){
    int s1, s2;
    float s3;
    
    scanf("%f%d", &s1, &s3);
    printf("s1: %d, s3: %f", s1, s3);
return 0;
}

s1 değişkeni int veri tipinde ama scanf() içindeki s1’in placeholder’ı %f yani float veri tipinde. s3 değişkeni de float veri tipinde olmasına rağmen scanf() içindeki placeholder’ı %d yani int veri tipinde.

Şimdi 7 ve 1.2 değerlerini giriyorum:

s1: 1088421888, s3: 0.000000

 

Böyle bir mantık hatasında düzgün bir sonuç beklemiyordun herhalde. lynda.com‘dan bir eğitim seti izlerken “garbage in, garbage out” demişti anlatan kişi. Bizdeki “ne ekersen onu biçersin” deyiminin karşılığı sanırım. Günümüzdeki birçok popüler dili yazarken anlık olarak hatalarımızı ide‘ler yakalıyor ama C’de bu durum söz konusu değil. O yüzden kodları yazarken dikkat etmek gerek.

Şimdi çok ilginç bir noktaya daha değinmek istiyorum. Bunu önce örnekle açıklamak daha iyi olur:

#include <stdio.h>
#include <stdlib.h>
int main(){
    int s1;
    char karakter;
    
    scanf("%d%c", &s1, &karakter);
    printf("s1: %d, s3: %c", s1, karakter);
return 0;
}

Sırasıyla klavyeden şuları giriyorum: 9 ↵ y

Çıktı:

s1: 9, s3: 

 

Böyle olmaması lazımdı

y karakteri kayıp! Nereye gitti, ne oldu? Aslında her şeyin çok basit bir açıklaması var. Biraz zamanı geriye sarıp, girdiğimiz verilere bakalım:

scanf("%d%c", &s1, &karakter);
  1. 9
  2. y
  1. 9 sayısını girdim ve enter’a (↵) bastım. %d 9 sayısını aldı.
  2. şimdi scanf() benden bir karakter bekliyor. Ama o da ne? Zaten elimizde hazır bir karakter varmış:
  3. enter(↵) %c tarafından alınıyor ve scanf() görevini yapmanın verdiği haklı gururla uzaklaşıyor. Ama orada “y” varmış yokmuş umrunda değil artık.

Evet efenim, ↵ ‘da Allah’ın bir karakteri. 9 yazıp ↵’a bastığım zaman, girdi yolunda bekliyormuş bu ↵. Ne zaman ben bir karakter girmeye kalksam zaten ↵ hazırda beklediği için gelip benim değişkenime konuyor. Peki, yok mu bunun bir hal çaresi ya Rabbim?

İsviçreli bilim adamlarının kullandığı bir tekniği görüyoruz önce:

#include <stdio.h>
#include <stdlib.h>
int main(){
    int s1;
    char karakter, enterYakala;
    
    scanf("%d", &s1); //int değerini alıyorum
    scanf("%c", &enterYakala); // hazırda bekleyen enter'ı bu değişkene aldım
    scanf("%c", &karakter); // şimdi yeni karakter alabilirim
    printf("%d %c", s1, karakter);
return 0;
}

Yine 9  ↵ y değerlerini giriyorum ve çıktıya bakıyorum:

9 y

İşte her şey olması gerektiği gibi. Neydi efenim: “garbage in, garbage out

Çaresizim çaresiz

Bu konu biraz kafa karıştırıcı olabilir. Programlamaya yeni başlayan birisi bu kısmı atlayabilir.

Ve bugünlük değinmek istediğim son bir konu var. Kullanıcıdan bir sayı beklerken metin girerse ne olacak? Bunu engelleyebilir miyim?

#include <stdio.h>
#include <stdlib.h>
int main(){
    int s1;
    
    scanf("%d", &s1);
    printf("%d", s1);
return 0;
}

Yukarıdaki kod bizden bir tam sayı bekliyor. Eğer “abc” yazarsam alacağım çıktı:

0

Görüldüğü üzere  bu terslikte bir iş var. Ya da şöyle bir terslikte olabilir; her veri tipinin belirli aralıkta değerler tuttuğunu öğrenmiştim. Kullanıcıdan tam sayı beklerken ya tam sayı sınırının üstünde değer girerse? Yani int maksimum 2147483647 değerine kadar değer tutabiliyor. Kullanıcı 2147483647’den fazla bir değer girerse ne olacak?

Bu durumların çözümünü bulmak için biraz araştırma yaptım. Öncelikle anladığım, bu durumlar scanf()‘in fıtratında var.   scanf()  in günahını almışım efenim. Bu duruma “owerflow” deniliyor. Bu linkte benzer bir soruya verilen cevaplar mevcut. Anladığım kadarıyla çevirmeye çalışayım:

scanf("%d", &val);

Kullanıcıdan bir tam sayı girmesini bekliyoruz. Kullanıcı {‘n’, ‘t’, ‘ ‘, ‘1’, ‘2’, ‘3’, ‘n’} girerse scanf() boşluk karakterlerini atlıyor ve enter’ı görene kadar veriyi alıyor. Değerimiz: 123

Kullanıcı “12w4”  girerse, sen zannediyorsun ki scanf()bu sayı değil ki” deyip veriyi almayacak. Çok beklersin o zaman. Çünkü scanf() 12’yi alacak ve “w4″ü girişte bekletecek.

Son olarak, en son benimde bahsettiğim gibi kullanıcı çok pis uzunlukta bir sayı girdi: “1234567890123456789012345678901234567890” gibi. Eğer scanf()‘in bu sayıyı red edeceğini düşünüyorsan yine çok beklersin. scanf() ne yapıp ne edip o sayıyı alır, evirip çevirip ortaya bir sayı çıkarır. Bu durumunda basit bir izahı yazilimsozlukte  8. yorumda gizli.

Gelelim çözüme. Eğer bu tarz durumlarla adam akıllı baş etmek istiyorsan farklı bir araç kullanmak gerekecek: fgets() ve strol(). Bunların bize sağladığı avantajlar:

  • “12w4” gibi saçma girdileri önlemek,
  • “1234567890123456789012345678901234567890” gibi aşırı pis uzunluktaki sayıları önlemek,
  • Veri girişinde çöp bırakmamak.

Minik bir de dezavantajı var: Birazcık daha fazla uğraşman gerekecek.

Bu konuyla ilgili olarak ekstra bir kaynak daha paylaşayım. Secure Coding Guide: Avoiding Integer Overflows and Underflows.Gerçi bu döküman biraz daha fazla teknik bilgi gerektiyor. yazilimsozluk‘te anlatılan durum da burada detaylıca anlatılmış.

Özet geçmem gerekirse, bilgisayar verileri 2lik sistemde (0 ve 1) saklıyor ve buna göre işlem yapıyor. int olarak  2147483647 sayısının bir fazlası bilgisayar için 2lik sistemde – 2147483648 demek.

İşte böyle, öğrenilecek daha çok şey var. Henüz yolun başındayken oldukça ağır gelebilir bazı bilgiler. Şimdilik akışına bırakıp, zamanı gelince bu derin konulara yine el atarım. Buraya kadar belki bazı şeyleri yanlış öğrendim ve yanlış aktardım. Eğer yanlış ya da düzeltilmesi gereken bir nokta farkettiyseniz, lütfen bana bildirin.

Yalnız şunu da tekrar anlamış oldum ki, İngilizce şart!

Özet:

  • printf() ile formatlı çıktı almak için %f yerine %x.yf yazabilirim.
  • ile kaçış karakterleri yazdırılır.  yazmak için \, ” yazmak için ” gibi.
  • Gereğinden fazla veri harcama. Kullanıcının gireceği sayı en fazla 10000 int yerine short kullanabilirim mesela.
  • Sabit tanımlarken hepsi büyük harfle olması adettendir. Ayrıca sabitleri kullanırken ayrıca dikkat, #define kullanırken ayrı ayrıca dikkat.
  • scanf() ile veri girilirken placeholer, veri tipi ve & önemli. Sık yapılan hatalar arasında.
  • scanf() için enter’da bir karakter. Dolayısıyla çoğu zaman veri giriş yolunda bir enter bekliyor olabilir. Yeni karakter girişi yapılmadan önce dikkat etmek lazım.
  • Dizi izlerken artık Türkçe altyazı kullanma.

Çalışma Sorusu

Senaryo1: Kullanıcı gideceği mesafeyi ve ortalama hızını programa girecek. Program girilen verilere göre ortalama seyahat süresini hesaplayacak. Mesafe km, hız km/saat olduğunu varsayalım.

Senaryo2: 3 basamaklı bir sayının birler, onlar ve yüzler basamağını bulan 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) {
    double distance, speed, travelTime;
    
    puts("Please, input distance (km):"); //mesafeyi soruyoruz
    scanf("%lf", &distance);
    
    puts("Please, input your average speed (km/h):"); //ortalama hızını soruyoruz
    scanf("%lf", &speed);
    
    travelTime = distance / speed; //zaman = yol / hız formülüne göre hesap yapıyoruz
    printf("I think your travel may take %.2lf hour(s)", travelTime);

    return (EXIT_SUCCESS);
}

 Senaryo2

#include <stdio.h>
#include <stdlib.h>


int main(int argc, char** argv) {

    int number, hundred, ten, one;
    
    puts("Please, input 3-digit number:");
    scanf("%d", &number);
    
    hundred = (number % 1000) / 100;
    ten = (number % 100) / 10;
    one = (number % 10);
    
    printf("%d, %d, %d", hundred, ten, one);
    return (EXIT_SUCCESS);
}

 

Kategori: C

Yorumlar

Siz de düşüncelerinizi paylaşın

Bu site, istenmeyenleri azaltmak için Akismet kullanıyor. Yorum verilerinizin nasıl işlendiği hakkında daha fazla bilgi edinin.