Professional Documents
Culture Documents
Ileri Progralama
Ileri Progralama
C Programlama Dersleri
Bu yazda renecekleriniz:
Merhaba;
Sanrm, C ve C++ adn bilgisayarla az ok har neir olan herkes en az bir kez duymutur. Sizde
bu isimleri duyanlardansanz ve nedir, ne deildir, nasl kullanlr gibi birok soruya yant
aryorsanz, doru yerdesiniz. nk bu yazyla balayarak C ve C++ ile programlamaya gireceiz.
nce C ile yolumuza koyulup, belli bir olgunlua ulatktan sonra C++ ile devam edeceiz.
Okuyucularmzn genelini dnerek, konuyu en temelden almay daha doru buldum. Yani
hedefimiz, programlamay hi bilmeyen bir insann burada okuduklaryla belli bir yerlere ulamas.
leri derece de olanlarsa sklmamak iin biraz beklemeli. Laf fazla uzatmadan balayalm.
Makine dilinden sonra Assembler Dili gelir. Makine dilini kullanmann zorluu ve karmaas
zerine gelitirilen Assembler, daha basit bir yapdadr. Ama yine de C ile mukayese ederseniz ok
daha zordur ve kullandnz bilgisayarn donanmna dair hlen bilgiye gereksinim duyarsnz.
Assembler aadaki gibi karmak bir yapdadr.
C Programlama Dili
Temel Giri/k lemleri (BASIC I/O):
C ile ilgili olarak bu ve nmzdeki yazlarda birok komut/fonksiyon greceiz. Ama hep
kullanacamz ve ilk renmemiz gerekenler temel giri k fonksiyonlardr. C de klavyeden bir
deer alabilmek iin scanf(); fonksiyonunu kullanrz. Ekrana herhangi bir ey yazdrmak iinse
printf(); fonksiyonu kullanlr.
Bir rnekle grelim;
#include<stdio.h>
int main( void )
{
printf("Hello World");
}
Eer bunu derleyicinizde yazp derlerseniz ve sonrasnda altrrsanz ekrana Hello World
yazlacaktr. #include<stdio.h>, standart giri k balk dosyasn, programa dahil et gibi bir
anlam tar. C'de (ve hemen hemen btn dier programlama dillerinde) bir ktphaneyi dahil
etmek son derece rutin bir itir. Aksi halde giri-k fonksiyonlarn dahi her seferinde bizim
batan tanmlamamz gerekirdi.
main( ), bir programdaki ana fonksyiondur. Ondan sonra gelen ayra standarttr. Bir blou temsil
eder. ki ayra iareti arasndaki alan main fonksiyonuna ait bir blou oluturur. printf ise
yazdmz metini, ekrana bastrmaya yarayan, standart bir fonksiyonudur. ift trnak iaretleri
iersine yazdnz herey printf sayesinde ekrana baslr.
Dikkat ettiyseniz, her satr sonuna noktal virgl koyduk. Aslnda her satr deil, her komutan sonra
noktal virgl koyduumuzu sylemek daha doru olacak. nk noktal virgl C dilinde komut
ayrac anlamna gelir.
imdi yukarda yazdmz basit program, biraz daha gelitirelim:
#include<stdio.h>
int main( void )
{
printf("Hello World\n");
printf("Merhaba Dnya");
return 0;
}
Birka yeni satr gryorsunuz. Srayla ne olduklarn aklayalm. Az evvel yazdmz "Hello
World" yazsnn sonuna "\n" ekledik. "\n" bir alt satra ge anlamna geliyor. Eer "\n" yazmazsak,
ekranda "Hello WorldMerhaba Dnya" eklinde bir yaz kar. "\n" kullanrsak, "Hello World"
yazldktan sonra, bir alt satra geilir ve ikinci satrda "Merhaba Dnya" yazdrlr. En altta "return
0;" adnda yeni bir komut fark etmisinizdir. Bunu eklemezseniz, program yine alr; ancak uyar
verir. nk main fonksiyonu, geriye bir tam saynn dnmesini beklemektedir. Yazm olduumuz
return ifadesiyle bu uyarlardan kurtulabilirsiniz. Detayna girmek iin henz erken, return
konusuna ileride deineceiz.
Yukarda ki programn aynsn yle de yazabilirdik:
#include<stdio.h>
int main( void )
{
printf("Hello World");
printf("\nMerhaba Dnya");
return 0;
Bir nce ve imdi yazdmz programlarn ekran kts ayndr. Bu rnekle anlatmak istediim,
printf() fonksiyonunda '\n' konulan yerden sonrasnn bir alt satra deceidir.
#include<stdio.h>
int main( void )
{
printf("Hello World\nMerhaba Dnya");
return 0;
}
Tek bir printf(); fonksiyonu kullanlmtr. Ancak alt alta yazarak, metini tek seferde grlebilir hle
getirdik. Program derleyip altrrsanz, alt alta satr yazlmaz. Cmle btn olarak gsterilir
ve bir nceki rnekle tamamen ayndr. (Satrlarn alt alta grnmesini isteseydik; daha nce
bahsettiimiz gibi '\n' koymamz gerekirdi.)
Ekrana, Ali: "Naber, naslsn?" dedi. eklinde bir yaz yazdrmamz gerekiyor diyelim. Bu konuda
ufak bir problem yaayacaz. nk printf(); fonksiyonu grd ilk iki ift trnak zerinden ilem
yapar. Byle bir eyi ekrana yazdrmak iin aadaki gibi bir program yazmamz gerekir:
#include<stdio.h>
int main( void )
{
printf("Ali: \"Naber, naslsn?\" dedi.\n");
return 0;
}
printf(); fonksiyonunu kullanmay sanrm iyice anladnz. printf( yazp, sonra ift trnak ayor,
yazmak istediklerimizi yazyor, ift trna sonra da parantezi kapatyor, sonuna noktal virgl
ekliyoruz. Alt satra gemek iinse, yazdklarmzn sonuna '\n' ekliyoruz. ift trnakl bir ey
kullanmak iinse \ ... \ kullanyoruz. Hepsi bu!
scanf(); fonksiyonuna gelince, bu banda bahsettiimiz gibi bizim giri (Input) fonksiyonumuzdur.
Ancak yazm burada noktalyorum. nk deikenler iin iine girmekte ve onlar anlatmam uzun
srecek. Gelecek haftaki yazmda kaldmz yerden devam edeceiz. Yazdklarmla ilgili neri,
eletiri veya sorunuz varsa, bana ulaabilirsiniz.
C Programlama Dersi - II
Bu yazda renecekleriniz:
Bloodshed Dev-C++'in kullanm
Deikenler ve deiken tanmlamalar
Deiken tipleri ve maksimum-minimum alabilecei deerler
scanf() fonksiyonunun kullanm
Aritmetik operatrler
lemlerde ncelik sras
Geen hafta bilgisayar ve programlamaya dair temel bilgileri ve printf( ); fonksiyonunu rendik.
Bu hafta, kaldmz yerden devam edeceiz. lk yazyla ilgili herhangi bir sorunuz varsa, bana
cagataycebi@gmail.com adresinden ulaabilirsiniz. Bu ufak bilgiden sonra, kaldmz yerden
devam edelim.
Bloodshed Dev-C++
Okuyucularmzn bir ksm, Bloodshed Dev-C++'in kullanmyla ilgili eitli sorunlar yaam.
Program nasl kullanabileceinize dair ufak bir aklamayla yazmza balamak yerinde olacaktr.
( Bu blm C derleyicisi olmayanlara yardmc olmak iin yazlmtr. Eer hli hazrda bir
derleyiciniz varsa ve sorunsuz kullanyorsanz, "Deiken nedir? Tanm nasl yaplr?"
blmnden devam edebilirsiniz. )
Dev-C++ kullanm olduka basit bir program. Bloodshed Dev-C++ web sitesinin Download
ksmndan Dev-C++'i indirebilirsiniz. Dilerseniz bu balantya tklayarak yklemeniz de mmkn.
( Zaman iinde balant adresi almayabilir. ) Program baaryla indirip kurarsanz, geriye
yapacak fazla bir ey kalmyor.
Program menlerinden, File -> New-> Source File yaparak yeni bir kaynak dosyas an. ( Ctrl + N
ile de ayn ilemi yapabilirsiniz. ) Aadaki kodu deneme amacyla, atnz dosyaya yazn:
#include<stdio.h>
int main( void )
{
// Hello World yazar.
printf( "Hello World" );
// Sizden herhangi bir giri bekler.
// Bylece program alp, kapanmaz.
getchar( );
return 0;
}
File -> Save As sekmesiyle, yazdnz dosyay kaydedin. ( Ctrl + S ile de kaydedebilirsiniz. )
Dosyann adn verdikten sonra sonuna .c yazn. rnein deneme.c gibi...
Execute -> Compile sekmesine tklayn. ( Ksayol olarak Ctrl + F9'u kullanabilirsiniz. ) Artk
programnz derlendi ve almaya hazr. Execute -> Run ile programnz altrn. ( Ctrl + F10'u
da deneyebilirsiniz. ) Ekrana "Hello World" yazacaktr.
Eer yazdnz kodu tek seferde derleyip, altrmak isterseniz, Execute -> Compile & Run
yolunu izleyin. ( Bu ilemin ksayol tuu, F9'dur. )
Yazdnz kodu nereye kaydederseniz, orada sonu .exe ile biten altrlabilir program dosyas
oluacaktr. rnein C:\Belgelerim klasrne deneme.c eklinde bir dosya kaydedip, F9'a
bastnzda, deneme.c'nin bulunduu klasrde deneme.exe diye bir dosya oluur. Oluan bu dosyay
istediiniz yere tayabilir, dilediiniz gibi altrabilirsiniz.
Deiken nedir? Tanm nasl yaplr?
Deikenler, girdiimiz deerleri alan veya programn almasyla baz deerlerin atand, veri
tutuculardr. Deiken tanmlamaysa, gelecek veya girilecek verilerin ne olduuna bal olarak,
deiken tipinin belirlenmesidir. Yani a isimli bir deikeniniz varsa ve buna tamsay bir deer
atamak istiyorsanz, a deikenini tamsay olarak tantmanz gerekir. Keza, a'ya girilecek deer eer
bir karakter veya virgll say olsayd, deiken tipinizin ona gre olmas gerekirdi. Sanrm bir
rnekle aklamak daha iyi olacaktr.
#include<stdio.h>
int main( void )
{
int a;
a = 25;
printf("a says %d",a);
return 0;
}
imdi yukardaki program anlamaya alalm. En ba satra, int a -int, ngilizce de integer'n
ksaltmasdr- dedik. Bunun anlam, tamsay tipinde, a isimli bir deikenim var demektir. a=25 ise,
a deikenine 25 deerini ata anlamna geliyor. Yani, a artk 25 saysn iinde tamaktadr. Onu bir
yerlerde kullandnz zaman program, a'nn deeri olan 25'i ileme alacaktr. printf();
fonksiyonunun iersine yazdmz %d ise, ekranda tamsay bir deiken deeri gzkecek
anlamndadr. ift trnaktan sonra koyacamz a deeri ise, grntlenecek deikenin a olduunu
belirtir. Yalnz dikkat etmeniz gereken, ift trnaktan sonra, virgl koyup sonra deikenin adn
yazdmzdr. Daha gelimi bir rnek yaparsak;
#include<stdio.h>
int main( void )
{
int a;
int b;
int toplam;
a = 25;
b = 18;
toplam = a + b;
printf("a says %d ve b says %d, Toplam %d.\n", a, b, toplam);
return 0;
}
Bu programn ekran kts yle olur; a says 25 ve b says 18, Toplam 43. Yazdmz bu
programda, a, sonra b, nc olarakta toplam ismiyle 3 adet tamsay deiken tanttk. Daha sonra
a'ya 25, b'ye 18 deerlerini atadk. Sonraki satrdaysa, a ile b'nin deerlerini toplayarak, toplam
ismindeki deikenimizin iersine atadk. Ekrana yazdrma ksm ise yle oldu: tane %d koyduk
ve ift trna kapattktan sonra, ekranda gzkme srasna gre, deikenlerimizin adn yazdk.
printf(); fonksiyonu iersinde kullanlan %d'nin anlam, bir tamsay deikenin ekranda
grntleneceidir. Deikenlerin yazlma srasndaki olaya gelince, hangisini nce grmek
istiyorsak onu baa koyar sonra virgl koyup, dier deikenleri yazarz. Yani nce a deerinin
gzkmesini istediimiz iin a, sonra b deerinin gzkmesi iin b, ve en sonda toplam deerinin
gzkmesi iin toplam yazdk.
Bu arada belirtmekte fayda var, elimizdeki 3 tamsay deikeni, her seferinde int yazp, belirtmek
zorunda deiliz. int a,b,toplam; yazarsakta ayn ilemi tek satrda yapabiliriz.
imdi, elimizdeki program bir adm teye tayalm:
#include<stdio.h>
int main( void )
{
int saat;
float ucret, toplam_ucret;
char bas_harf;
printf("alann ba harfini giriniz> ");
scanf("%c",&bas_harf);
printf("alma saatini giriniz> ");
scanf("%d",&saat);
printf("Saat cretini giriniz> ");
scanf("%f",&ucret);
toplam_ucret = saat * ucret;
printf("%c baharfli alann, alaca cret:
%f\n",bas_harf,toplam_ucret);
return 0;
}
Bu yazdmz program basit bir arpm ilemini yerine getirerek sonucu ekrana yazdryor.
Yazlanlarn hepsini bir anda anlamaya almayn, nk adm adm hepsinin zerinde duracaz.
Program incelemeye balarsak; deiken tanmn programmzn banda yapyoruz. Grdnz
gibi bu sefer farkl tiplerde deikenler kullandk. Biri int, dier ikisi float ve sonuncusunu da char.
int'n tamsay anlamna geldiini az evvel grdk. float ise 2.54667 gibi virgll saylar iin
kullanlr. char tipindeki deikenler, a,H,q,... eklinde tek bir karakter saklarlar. Konu biraz
karmak gzkse de, deiken tanmnda btn yapmanz gereken, deikeninizin tayaca veriye
gre programn banda onun tipini belirtmektir. Bunun iin de tpk yukardaki programda olduu
gibi, nce tipi belirtir, sonra da adn yazarsnz.
Programmza dnersek, alma saati bir tamsay olacandan, onu saat isminde bir int olarak
tanttk. cret virgll bir say olabilirdi. O nedenle onu float (yani virgll say) olarak bildirdik.
Adn da saatucret koyduk. Farkettiiniz gibi, toplamucret isimli deikenimiz de bir float. nk
bir tamsay (int) ile virgll saynn (float) arpm virgll bir say olmaktadr. Tabii 3.5x2=7 gibi
tam say olduu durumlarda olabilir. Ancak hatadan saknmak iin toplamucret isimli deikenimizi
bir float olarak belirtmek daha dorudur.
steki programmzda olmasna karn, uana kadar scanf(); fonksiyonunun kullanmna
deinmedik. scanf(); geen haftaki yazmzdan da rendiimiz gibi bir giri fonksiyonudur. Peki
nasl kullanlr, tam olarak ne ie yarar? scanf(); kabaca klavyeden girdiiniz sayy veya karakteri
almaya yarar. Kullanm ise yledir: nce scanf yazar, sonra parantez ve ardndan ift trnak aar,
daha sonra alnacak deikene gre, %d, %f veya %c yazlr. %d int, %f float, %c char tipindeki
deikenler iin kullanlr. Bundan sonra ift trna kapatp, virgl koyarsnz. Hemen ardndan &
iareti ve atanacak deiken adn yazarsnz. Son olarak, parantezi kapatp noktal virgl
koyarsnz. Hepsi budur.
Yukardaki programda da scanf(); fonksiyonu grdnz gibi bu ekilde kullanlmtr. Sanrm
gereinden ok laf oldu ve konu basit olduu halde zor gibi gzkt. Yukardaki skntdan
kurtulmak iin ok basit bir program yazalm. Bu programn amac, klavyeden girilen bir sayy,
ekrana aynen bastrmak olsun.
#include<stdio.h>
int main( void )
{
int sayi;
printf("Deer giriniz> ");
scanf("%d",&sayi);
Grdnz gibi hibir zor taraf yok. Klavyeden girilecek bir tamsaynz varsa, yapmanz gereken
nce deikenin tipini ve adn belirtmek, sonra scanf( ); fonksiyonunu kullanmak. Bu fonksiyonu
kullanmaya gelince, scanf(" yazdktan sonra deiken tipine gre %d, %c, veya %f, yazp, ardndan
& iaretini kullanarak atanacak deikenin adn belirtmekten ibaret. Fark etmisinizdir, printf(); ve
scanf(); fonksiyonlarnn her ikisinde de %d koyduk. nk scanf( ); ve printf( ); fonksiyonlarn
deiken tipi simgeleri ayndr. Aadaki tablodan hangi deiken tipinin nasl deklare edileceini,
ka byte yer kapladn, maksimum/minimum alabilecei deerleri ve giri/k fonksiyonlaryla
nasl kullanlabileceini bulabilirsiniz. Tanmlamalar ve fonksiyon uygulamalar, degisken isimli bir
deiken iin yaplmtr.
TP
DEKLARASYON
Karakter
char degisken;
Ksa Tam
Say
short degisken;
Tamsay
int degisken;
Uzun
Tamsay
aretsiz
Tamsay
unsigned int
degisken;
aretsiz
Uzun
Tamsay
long unsigned
degisken;
Virgll
Say
float degisken;
Uzun
Virgll
Say
double degisken;
scanf( ); Minimum
printf( );
printf("% scanf("%c"
c",degisk ,°isken
-128
en);
);
printf("% scanf("%d
d",degisk ",°iske
-32768
en);
n);
printf("% scanf("%d
d",degisk ",°iske
-32768
en);
n);
printf("% scanf("%ld
ld",degisk ",°iske -2147483648
en);
n);
printf("% scanf("%u"
u",degisk ,°isken
0
en);
);
printf("% scanf("%lu
lu",degisk ",°iske
0
en);
n);
printf("% scanf("%f",
f",degiske °isken) 1,17549e-38
n);
;
printf("% scanf("%lf"
lf",degisk ,°isken 2,22504e-308
en);
);
Maksimum
Byte
127
32767
32767
2147483647
65535
4294967295
3,40282e+38
1,79769e+30
8
Verilen bu deerler; iletim sisteminden, iletim sistemine, farkllk gsterebilir. En doru deerleri
almak iin sizeof( ), fonksiyonunu kullanmak gerekir. Aada yazm olduum bir program
bulacaksnz. Kendi bilgisayarnzda derleyip, altrrsanz, size deikenlerin boyutunu ve
alabilecei maksimum-minimum deerleri verecektir:
#include<stdio.h>
#include<limits.h>
#include<float.h>
int main( void )
{
printf( "\nTIP\t\t
");
printf("==============================================================\n
Program inceleyip, detaylara girmeyin. Sadece altrp, sonular grmeniz yeterli. rnein,
Ubuntu ykl x86 tabanl bir bilgisayarda, karnza yle bir ekran gelecektir:
TIP
BOYUT
MIN
MAX
==============================================================
char
: 1 byte(s)
-128
127
short
: 2 byte(s)
-32768
32767
int
: 4 byte(s)
-2147483648
2147483647
unsigned int
: 4 byte(s)
4294967295
long
: 4 byte(s)
-2147483648
2147483647
float
: 4 byte(s)
1.175494e-38
3.402823e+38
double
: 8 byte(s)
2.225074e-308
1.797693e+308
Sanrm hi istemediim bir ey yaparak, kafanz kartrdm. Dilerseniz, burada keselim ve bunlar
ileriye dnk olarak bir kenarda dursunlar. Yine de daha fazla bilgi isterseniz, Teach Yourself C in
21 Days yazsna gz atabilirsiniz. Ama dediim gibi bunlarn sonraya braklmas, uygun olacaktr.
u ana kadar rendiklerimizle girilen herhangi iki saysnn ortalamasn hesaplayan bir program
yazalm. Balamadan nce, deikenlerimizin ka tane ve nasl olacan dnelim. uras kesin
ki, alacamz iki say iin 2 farkl deikenimiz olmal. Bir de ortalamay hesapladmzda
bulduumuz deeri ona atayabileceimiz bir baka deikene ihtiyacmz var. Peki
deikenlerimizin tipleri ne olacak? Banda belirttiimiz gibi yazmamz gereken program herhangi
iki say iin kullanlabilmeli. Sadece tamsay demiyoruz, yani virgll bir say da girilebilir. O
halde, girilecek iki saynn deiken tipi float olmal. Bunu double da yapabilirsiniz, fakat
bykl asndan gereksiz olacaktr. Ortalamalarn atanaca nc deikene gelince, o da bir
float olmal. ki virgll saynn ortalamasnn tamsay kmas dnlemez. Oluturduumuz bu
nbilgilerle programmz artk yazabiliriz.
#include<stdio.h>
int main( void )
{
float sayi1,sayi2,ortalama;
printf("ki say giriniz> ");
scanf("%f%f",&sayi1,&sayi2);
ortalama = ( sayi1 + sayi2 ) / 2;
printf("Ortalama sonucu: %f'dir",ortalama);
return 0;
}
Yukarda yazl programda, bilmediimiz hibir ey yok. Gayet basit ekilde izah edersek, 2 say
alnp, bunlar toplanyor ve ikiye blnyor. Bulunan deerde ortalama isminde bir baka deikene
Grld gibi bu iin yle aman aman bir taraf yok. Fonksiyonlarn kullanmlar zaten birbirine
benziyor. Tek yapmanz gereken biraz pratik ve el alkanl.
Aritmetik Operatr ve fadeleri
ste yazdmz programlarn hemen hemen hepsinde aritmetik bir ilem kullandk. Ama aritmetik
ilemleri tam olarak anlatmadk. Ksaca;
( + ) : Art
( - ) : Eksi
( / ) : Blme
( * ) : arpma
( % ) : Modl
Burada bilinmeyen olsa olsa modl ilemidir. Modl kalanlar bulmaya yarar. Yani diyelim ki 15'in
6'ya olan blmnden kalann bulmak istiyorsunuz. O halde 15%6 = 3 demektir. Veya, 7'nin 3'e
blmnden kalan bulacaksanz, o zamanda 7%3 = 1 elde edilir. Bu C'de ska kullanacamz bir
aritmetik operatr olacak.
lem srasna gelince, o da yle olur. En nce yaplan ilem parantez ( ) iidir. Sonra * / % gelir.
arpma, blme ve modl iin, soldan saa hangisi daha nce geliyorsa o yaplr. En son
yaplanlarsa art ve eksidir. Keza, bu ikisi arasnda, nce olan solda bulunandr.
Blme ilemine dair, bir iki ufak olay daha var. 4/5 normalde 0.8 etmektedir. Ancak C iin 4/5 sfr
eder. nk program, iki tamsaynn blnmesiyle, sonucu tamsay elde etmeyi bekler. leride
tipleri birbiri arasnda deitirmeye deineceiz. Ama imdilik bu konuda bir-iki rnek yapalm:
*
*
*
*
*
Bu aritmetik ifadeleri henz bir C program iin denemedik. Ancak burada keselim. Bunu yapmay
dier yazmza saklayalm. Eer uramak isterseniz klavyeden alnacak 3 saynn ortalamasn
bulan bir program yazabilirsiniz. Yada girilecek 2 tamsay arasnda btn aritmetik ilemleri -ikisin
arpmn, toplamn, birbirine blmn ve farkn- bulan ve sonular ekrana yazdran bir program
da yazmanz mmkn. Herhangi bir yerde taklr ve bana ulamak isterseniz mail adresime
yazmanz kafi. Haftaya grrz.
Cast Operator
Cast operator'un Trke karl olacak bir kelime aklma gelmedi. Ancak cast operatoru u ekilde
aklayabiliriz. Bir deiken tipini rnein (Tam say-int), bir baka tipe (virgll say-float) gibi
dntrmek isterseniz, o zaman cast operator kullanrz.
Aadaki kodu yazp derleyin.
#include<stdio.h>
int main( void )
{
int bolunen = 12, bolen = 8;
float bolum;
bolum = bolunen / bolen;
printf("Sonuc: %f\n",bolum);
return 0;
}
rendiimiz zere, bunun da sonucu 0.5 yerine, 0 olarak gzkecektir. Sonucu doru yazdrmak
iin (float)2/4 eklinde yazmanz yeterlidir. Ancak dahi basit bir yntem olarak 2/4.0 veya 2.0/4
yazarsanz yine ayn sonucu elde edersiniz.nk bu durumda saylardan bir tanesi float olmaktadr.
Kullanlan deiken tiplerinden hangisi bykse, sonu o deikenin tipinde dner. Yksek
deiken bellekte daha fazla yer kaplamaktadr. Bunun doal bir sonucu olarakta, domine eden
o'dur. Deikenlerin bykln daha nceki dersimizde vermitik. Ancak hatrlamak asndan,
aaya bakabilirsiniz.
(DK) char <-> int <-> long <-> float <-> double (YKSEK)
kan sonucu, daha dk bir deiken tipine atamaya kalkarsanz, o zaman veri kayb yaanr. Ve
rnein float 1.5 olan sonucu int deikene 1.0 olarak kaydedilir.
rendiklerinizin pekimesi iin bir program yazalm. Bu programda, klavyeden girilen, bir
virgll saynn, yuvarlanp, tam say olmas gsterilsin:
#include<stdio.h>
int main( void )
{
float girilen_sayi;
printf("Ltfen bir say giriniz> ");
scanf("%f",&girilen_sayi);
printf("Saynn yuvarlanm hali: %d\n", (int)(girilen_sayi+0.5));
return 0;
}
Eer if'in altnda birden ok komut varsa, ayra iareti (veya kme parantezi) koymamz gerekir.
ayet if'ten sonra, tek komut bulunuyorsa, ayra koyup-koymamak size kalmtr. Zorunluluu
yoktur.
rnek bir program yazalm. Bu programda kullancnn klavyeden, bir tam say girsin. Ve bizde
girilen say, 100'den bykse, ekrana yazdralm:
#include<stdio.h>
int main( void )
{
int girilen_sayi;
printf("Ltfen bir tam say giriniz> ");
scanf("%d",&girilen_sayi);
if( girilen_sayi > 100 )
printf("Girilen say 100'den byktr\n");
return 0;
}
if-else
Baz durumlarda, bir koulun doruluuna gre sonu yazdrmak yetmez. Aksi durumda da ne
yapacamz belirtmek isteriz. Bunun iin if-else yapsn kullanrz.
if-else yaps u ekildedir:
if( koul ) {
komut(lar)
}
else {
komut(lar)
}
rnekte grdnz gibi, bir koulun doruluunu program kontrol ediyor ve buna doru olursa,
baz ilemler yapyor. ayet verilen koul yanlsa, o zaman daha baka bir ilem yapyor. Ancak
ikisini de yapmas gibi bir durum sz konusu deil.Aadaki ak diyagramlarnda (flowchart) her
iki durumu da grebilirsiniz.
if Yaps:
if-else Yaps:
Kktr
>
Byktr
==
Eittir
<=
Kk eittir
>=
Byk eittir
!=
Eit deildir
and
ve
||
or
veya
not
tersi
p&&q
p||q
!p
rnek Sorular
Soru 1: Klavyeden alnacak bir deerin, 18 ile 65 arasnda olup olmadn kontrol eden bir
program yaznz:
Soru 2: Kendisine verilen iki tam sayy, blecek ve sonucu virgll say olarak gsterecek bir
blme ilemini program hazrlaynz. (ayet blen 0 olarak verilirse, blme ilemi yaplmamaldr.)
Not: Yukarda verilmi zmler, daha efektif olabilirdi. Ancak verdiim cevaplarn herkes
tarafndan anlalmasn istediimden, ii biraz uzatm olabilirim. Sizin vereceiniz cevaplarn
gidi yollar elbette ki farkl olabilir.
Cevap1:
/*
Girilen yan, 18 ile 65 arasnda
olup olmadn belirler.
*/
#include<stdio.h>
int main( void )
{
int girilen_yas;
printf("Ltfen yanz giriniz> ");
scanf("%d",&girilen_yas);
if( girilen_yas >= 18 && girilen_yas <= 65 )
printf("Girilen ya, 18 ile 65 arasndadr.\n");
//Girilen ya 18 ile 65 arasnda deilse, aadaki else
//blou alr.
else {
//Girilen ya 18'den kkse
if( girilen_yas < 18 )
printf("Girilen ya, 18'den kktr.\n");
//Girilen ya 65'ten bykse
else
printf("Girilen ya, 65'ten byktr.\n");
}
}
Cevap2:
/*
Kendisine verilen iki tam sayyla
blme ilemi yapan program.
*/
#include<stdio.h>
int main( void )
{
int bolunen, bolen;
float sonuc;
printf("Blnecek sayy giriniz> ");
scanf("%d",&bolunen);
printf("Blen sayy giriniz> ");
scanf("%d",&bolen);
//Bolen, 0 ise, bir say sfra blnemeyeceinden,
//program sorun kartacaktr. Bu yzden,
//bolenin 0 olmamas kontrol ediliyor.
if( bolen != 0 ) {
sonuc = (float)bolunen / bolen;
//.2f, virglden sonra 2 basamak gsterilmesi
//iindir.
printf("Sonuc: %.2f\n",sonuc);
}
else
printf("Hata: Say 0'a blnemez!\n");
}
C Programlama Dersi - IV
Bu yazda renecekleriniz:
ie gemi (Nested) koullu ifadeler
if - else if merdiveni
switch - case ifadesi
Arttrma (Increment) ve azaltma (Decrement) ilemleri
Gelimi atama (Advanced Assignment) yntemleri
Conditional Operator ( ? )
Konuyla ilgili rnek sorular
kontrol ediyor ve doruysa, buna gre ilemler yapyorduk. Bir de if - else yaps vard. if - else
yapsnda da, koulu gene kontrol ediyor, doruysa if blounun altnda kalanlar yapyorduk;
yanlsa, else blounda olan kodlar ileme alnyordu. Son derece basit bir mantk zerine kurulmu
bu yapyla, yaplamayacak kontrol yoktur. Ancak yle durumlar vardr ki, if - else yaps yeterli
verimlilii sunamaz.
Diyelim ki, birden fazla kontrol yapmanz gereken bir durum olutu. Hatta rnek vererek konuyu
daha da somutlatralm. stenilen bir programda, klavyeden size ya bilgisi veriliyor. Siz de bu
bilgiye gre, ayet ya 18'den kkse ocuk; 18-30 ya arasnda gen; 30-50 ya arasnda ortaya
diye bir mesaj bastryorsunuz. Basit bir program.
imdi bunu sadece if yapsyla kuruyor olsaydk, her seferinde yan uygun aralklara dp
dmediini kontrol eder ve ona gre sonucu ekrana bastrrdk. Ama bu son derece verimsiz bir
yntem olurdu. nk zaten ya bilgisinin gen olduuna dair bir karar vermisek, sonrasnda tutup
bunun yal olup olmadn kontrol etmenin bir esprisi olmayacaktr. Verilebilecek en kt cevab
aada bulabilirsiniz:
/*
Sorulan soruya verilebilecek en
kt cevap.
*/
#include<stdio.h>
int main( void )
{
int girilen_yas;
printf("Ltfen yanz giriniz> ");
scanf("%d",&girilen_yas);
if( girilen_yas < 18 )
printf("Daha ocuk yatasnz, hayatn bandasnz.\n");
if( girilen_yas >= 18 && girilen_yas <= 30 )
printf("Genliin, gzellii bambaka!\n");
if( girilen_yas > 30 && girilen_yas <= 50 )
printf("Hepsini boverin, olgunluk ortayata balar!\n");
return 0;
}
Yukardaki program daha efektif bir yap sunmu olmasna ramen, eer kontrol ettiimiz aralklarn
says ok fazla olsayd, tam bir babelas olacakt! nk if - else iinde, bir baka if - else blou
ve onun iinde bir bakas... bu byle srp gidecekti. Ksacas performans olarak ok bir ey
deimese de, kodu yazan ve/veya okuyacak olan iin tam bir eziyete dnecekti. te bu
nedenlerle daha efektif yaplara ihtiya duyuyoruz.
if - else if Merdiveni
if - else if merdiveni yukarda verdiimiz rnekler iin biilmi kaftandr. if - else if merdiveni,
doru bir ey bulduu zaman kontrolu orada keser ve dier koullar kontrol etmeden blok
sonlandrlr.
Aada if - else if yapsn ve ak diyagramn bulabilirsiniz:
if - else if Yaps
if( koul 1 ) {
komut(lar)
}
else if( koul 2 )
komut(lar)
}
.
.
.
else if( koul n )
komut(lar)
}
else {
komut(lar)
}
if - else if Ak Diyagram
1
{
2
{
n
n
if - else if ile sylenebilecek son bir ey sonunda ki else'tir. else koymak zorunlu deildir. Ancak
hibir koula uymayan bir durumla karlatnzda, else devreye girer. rnein yukarda anlatp,
kodunu vermi olduumuz programda, belirtilen ya aralklarnda deer girilmezse, hibir ey
ekrana bastrlmayacaktr. nk programa tannmayan ya aralnda ne yaplaca
retilmemitir. imdi bu durumu da ierecek ekilde, programammz if - else if yapsyla tekrar
yazalm:
#include<stdio.h>
int main( void )
{
int girilen_yas;
printf("Ltfen yanz giriniz> ");
scanf("%d",&girilen_yas);
if( girilen_yas < 18 )
printf("Daha ocuk yatasnz, hayatn bandasnz.\n");
else if( girilen_yas >= 18 && girilen_yas <= 30 )
printf("Genliin, gzellii bambaka!\n");
else if( girilen_yas > 30 && girilen_yas <= 50 )
printf("Hepsini boverin, olgunluk ortayata
balar!\n");
else
return 0;
switch( degisken ) {
case sabit1:
komut(lar)
[break]
case sabit2:
komut(lar)
[break]
.
.
.
case sabitN:
komut(lar)
[break]
default:
komut(lar);
}
Sanrm gznze biraz farkl gzkt. Yap olarak imdiye kadar grm olduunuz if else gibi
gzkmese de, bir rnekten sonra arasnda pek bir fark olmadn greceksiniz. Her komut
sonunda koyduum break komutu, zorunlu deildir ve o nedenle keli parantezle belirtilmitir.
break koyduuz takdirde, uygun koul salandktan sonra, daha fazla kontrol yaplmayacak ve
aynen if - else if yapsnda olduu gibi program orada kesilecektir. Ama break koymazsanz, altnda
kalan btn ilemler -bir daha ki break'e kadar- yaplacaktr.
Kodun sonunda grdnz default komutu, if - else if yapsnda ki sonuncu else gibidir. Uygun
hibir art bulunamazsa, default komutu alr.
rendiimiz bilginin pekimesi iin biraz pratik yapalm. Bir not deerlendirme sistemi olsun. 100
- 90 aras A, 89 - 80 aras B, 79 - 70 aras C, 69 - 60 aras D, 59 ve altysa F olsun. Eer 100'den
byk veya negatif bir say girilirse, o zaman program hatal bir giri yapldn konusunda bizleri
uyarsn. Bunu imdiye kadar rendiiniz bilgilerle, if - else if yapsn kullanarak rahatlkla
yantlayabilirsiniz. Ama u an konumuz switch case olduundan, cevabn yle verelim:
#include<stdio.h>
int main( void )
{
int not;
printf("Ltfen notu giriniz> ");
scanf("%d",¬);
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 deer girdiniz!\n");
}
return 0;
Algoritmaya bakalm: nce sayy alyor ve 10'a blyoruz. Yani girilen not, 57 ise 5.7 sonucunu
elde ediyoruz. Ancak iki tam saynn sonucu bir virgll say veremez, tpk ileme giren
deikenler gibi tam say olarak dner. Dolaysyla bilgisayarn elde edecei sonu, 5.7 deil,
sadece 5'tir. switch case yapsnda koullar yukardan balayarak kontrol ediliyor. case 5'e
gelindiinde eitlik salanyor. Ama break konmad iin, switch case'ten klmyor. Ve altnda
kalan ilemlerde yaplyor. Altnda herhangi bir ilem veya break olmadndan case 0'a kadar bu
byle sryor. Ve case 0'da ekrana bir kt alp switch case yaps break ile sonlandrlmaktadr.
switch case, if - else if yapsnn sunduu esneklie sahip deildir. Daha ok men olarak sunulacak
ilerde kullanlr. rnein Unix'in nl listeleme komutu ls iersinde, verilen parametrelerin
kontrol switch case kullanlarak salanmtr. Open Solaris, FreeBSD veya Linux kodlarn
incelerseniz bunun gibi yzlerce rnek bulabilirsiniz.
Tip
sim
Aklama
i++
postfix
post-increment
++i
prefix
pre-increment
i--
postfix
post-decrement
--i
prefix
pre-decrement
Conditional Operator ( ? )
Trke karlk bulamadm bir baka C kavram da, Conditional Operator. Aslnda mot a mot
eviri yaparsam, koullu operatr anlamna geliyor. Ama u ana kadar grdmz birok yapy da
bu ekilde tanmlamak mmknken, koullu operatr ifadesini kullanmay pek tercih etmiyorum.
Neyse laf uzatmayalm...
Conditional Operator, if-else ile tamamen ayn yapdadr. Hibir fark yoktur. Tek fark koda
bakldnda anlalmasnn biraz daha zor oluudur. Bir de if - else gibi yazyla ifade edilmez.
Onun yerine soru iareti (?) ve iki nokta st ste ( : ) kullanarak yazarz. Aadaki tabloda if else
yapsyla karlatrlmal olarak, Conditional Operator verilmitir:
if-else Yaps
if( koul ) {
if_komut(lar)
}
else {
else_komut(lar)
}
imdi de ayn program, hem if-else, hem de conditional operator kullanarak yazalm:
/*
Girilen tam saynn
10'dan byk olup
olmadn gsteren
program
*/
#include<stdio.h>
int main( void )
{
int sayi;
printf("Ltfen bir say giriniz> ");
scanf("%d",&sayi);
if( sayi > 10 )
printf("Say 10'dan byktr\n");
else
printf("Say 10'dan kktr veya 10'a eittir\n");
return 0;
}
return 0;
Cevap2:
#include<stdio.h>
int main( void )
{
int sayi_1, sayi_2;
char operator_simgesi;
printf("Ltfen ilem simgesi giriniz> ");
scanf("%c",&operator_simgesi);
printf("Ltfen birinci sayy giriniz> ");
scanf("%d",&sayi_1);
printf("Ltfen ikinci sayy giriniz> ");
scanf("%d",&sayi_2);
switch( operator_simgesi ) {
case '+':
printf("%d %c %d = %d\n",sayi_1,operator_simgesi,
sayi_2, sayi_1 + sayi_2); break;
case '-':
printf("%d %c %d = %d\n",sayi_1,operator_simgesi,
sayi_2, sayi_1 - sayi_2); break;
case '%':
printf("%d %c %d = %d\n",sayi_1,operator_simgesi,
sayi_2, sayi_1 % sayi_2); break;
case '*':
printf("%d %c %d = %d\n",sayi_1,operator_simgesi,
sayi_2, sayi_1 * sayi_2); break;
case '/':
printf("%d %c %d = %.2f\n",sayi_1,operator_simgesi,
sayi_2, (float)sayi_1 / sayi_2);break;
default:
printf("HATA: Tanmsz bir operatr girdiniz!\n");
}
return 0;
Cevap3:
#include<stdio.h>
int main( void )
{
int sayi_1, sayi_2, sayi_3;
printf(" say giriniz> ");
scanf("%d %d %d", &sayi_1, &sayi_2, &sayi_3);
if( sayi_1 >= sayi_2 && sayi_1 > sayi_3 )
printf("%d en byk saydr!\n", sayi_1);
else if( sayi_2 >= sayi_1 && sayi_2 >= sayi_3 )
printf("%d en byk saydr!\n", sayi_2);
else if( sayi_3 >= sayi_1 && sayi_3 >= sayi_1 )
printf("%d en byk saydr!\n", sayi_3);
return 0;
}
Dng Kavram
Programlama konusunda -hangi dil olursa olsun- en kritik yaplardan biri dnglerdir. Dngler, bir
ii, belirlediiniz sayda yapan kod bloklar olarak dnlebilir. Ekrana 10 kere "Merhaba Dnya"
yazan bir programda, "Merhaba Dnya" yazdran kodu aslnda tek bir defa yazarsnz, dng
burada devreye girip, sizin iin bu kodu istediiniz sayda tekrarlar.
Dngleri bu kadar kritik yapan unsur; iyi yazlp, optimize edilmedii takdirde, bilgisayarnzn
ilem gcn gereksiz yere tketmesi ve harcanan zaman arttrmasdr. Benzer ekilde, iyi yazlm
bir dng, programnz hzl altracaktr.
Btn dngler temelde iki aamayla zetlenebilir. Aamalardan biri, dngnn devam edip
etmeyeceine karar verilen mantksal sorgu ksmdr. rnein, ekrana 10 kere "Merhaba Dnya"
yazdracaksanz, kanc seferde olduunu, koul ksmnda kontrol edersiniz. Dier aama,
dngnn ne yapacan yazdnz ksmdr. Yani ekrana "Merhaba Dnya" yazlmas dngnn
yapaca itir.
Dngnn devam edip etmeyeceine karar verilen aamada, hatal bir mantk snamas koyarsanz,
ya programnz hi almaz ya da sonsuza kadar alabilir.
C programlama diline ait baz dngler; while, do while, for yaplardr. Bunlar dnda, goto dng
eleman olmasna ramen, kullanlmas pek tavsiye edilmemektedir.
while Dngs
while dngs, en temel dng tipimizdir. Bir kontrol ifadesiyle dngnn devam edilip
edilmeyecei kontrol edilirken, scope iinde ( yani ayra iaretleri arasnda ) kalan btn alan
ileme sokulur. leme sokulan kod ksm dng yaplacak adet kadar tekrar eder.
while dngsnn genel yapsn ve ak emasn aada grebilirsiniz:
while Yaps
while Ak Diyagram
while( koul ) {
komut(lar)
}
Yukarda 10 kere ekrana "Merhaba Dnya" yazan programdan bahsettik. Gelin bir anlama yapalm
ve dnglerle alakal btn ilk rneklerimiz bu programn nasl yazlacan gstersin.
while dngs kullanarak, ekrana 10 kere "Merhaba Dnya" yazan program aadaki gibidir:
/*
Ekrana 10 kere "Merhaba Dnya"
yazan program
*/
#include<stdio.h>
int main( void )
{
//i deikenine bir balang deeri atyoruz.
//i'ye ilk deger atanmazsa, dngmz yanl alr.
int i = 0;
//i'nin degeri kontrol ileminden
//sonra 1 artar.
while( i++ < 10 ) {
//2d bir tam saynn yazdrlaca
//ancak bu say tek rakamdan olusa da
//2 rakamlk yer ayrlmasn belirtir.
printf("%2d: Merhaba Dnya\n",i);
}
return 0;
}
Yukardaki program aslnda son derece basit. i deikenine ilk deer olarak 0 atyoruz. Daha sonra,
while dngsne balyoruz. fadenin doruluu ( yani i'nin 10'dan kk olup olmad) kontrol
ediliyor. Eer doruysa, dng iindeki kodlarn almas balatlyor. Elbette kodlarn
balamasndan bir nceki admda, i deikeni arttrlyor. Bu yap toplamda 10 kere tekrar ediyor ve
en sonunda i'nin degeri 10'a eit olunca, dng sonlandrlyor.
Yandaki ilem basit bir toplama ifadesidir. Yanda grdmz ifade de, n deerini
kullancdan alacamz dnerek bir program yazalm. Bu program, alaca n
deerine gre, kendisine kadar olan saylarn karelerinin toplamn gsterecektir. Bu
program yazarsak:
#include<stdio.h>
int main( void )
{
int i = 0, toplam_deger = 0;
int n;
printf("Ltfen n deerini giriniz> ");
scanf("%d",&n);
while( i <= n ) {
toplam_deger += i*i;
i++;
}
printf("Sonu: %d\n",toplam_deger);
return 0;
do while Dngs
Greceimiz ikinci dng eidi, do while dngsdr. Yapt i, while ile hemen hemen ayndr;
verilen ii, dng koulu bozulana kadar srdrr. Ancak while'a gre nemli bir fark vardr.
while dnglerinde, dng iersindeki ilem yaplmadan nce, sunulan koul kontrol edilir. ayet
koul salanmyorsa, o while dngsnn hi almama ihtimali de bulunmaktadr. do while
dnglerindeyse, durum byle deildir. lk almada koul kontrol yaplmaz. Dolaysyla, her ne
artta olursa olsun, dngnz -en azndan bir kere- alacaktr.
Baz durumlarda, dng blou iersindeki kodlarn en azndan bir kere almas gerektiinden, do
while yaps kullanlr. do while ile ilgili genel yapy ve ak emasn aada bulabilirsiniz:
do while Yaps
do while Ak Diyagram
do {
komut(lar)
} while( koul );
Grdnz gibi, bir nceki rneimize olduka benzer bir yapda, yazld. Tek fark i'nin deeri
0'da olsa, 1000'de olsa, en azndan bir kez Merhaba Dnya'nn yazlacak olmasdr. Ancak while'de
kontrol nce yapld iin, hibir ey ekrana yazlmaz.
imdi do while'in kullanlmasnn daha mantkl olaca bir program yapalm. Kullancdan iki say
alnsn. Bu iki say toplandktan sonra, sonucu ekrana yazdrlsn. Yazdrma sonunda "Devam etmek
istiyor musunuz?" sorusu sorulsun ve klavyeden 'E' veya 'e' karakterlerinden birisi girilirse, program
devam etsin. Yok farkl birey girilirse, program sonlandrlsn. rnek programmz aada
bulabilirsiniz:
#include<stdio.h>
int main( void )
{
int sayi_1, sayi_2;
char devam_mi;
do {
printf("Birinci sayy giriniz> ");
scanf("%d",&sayi_1);
printf("kinci sayy giriniz> ");
scanf("%d",&sayi_2);
printf("%d + %d = %d\n", sayi_1, sayi_2, sayi_1 + sayi_2);
printf("Devam etmek ister misiniz? ");
//C'de tek karakter okuma ilemi biraz skntl
//olduundan, burada da bir do while kullandk.
do {
scanf("%c",&devam_mi);
}while( devam_mi == '\n' );
printf("\n");
} while( devam_mi == 'E' || devam_mi == 'e' );
}
return 0;
Program, kullancdan iki say alp, toplamn ekrana bastktan sonra, yeniden ilem yapp yapmak
istemediimizi sormaktadr. Bu program while ile de yazabilirdik. Ancak while ile yazabilmek iin,
devam_mi deikenine nceden 'E' deerini atamamz gerekmekteydi. do while dngsndeyse, bu
zorunlulua gerek kalmamtr.
Not: Yukardaki programda, farketmi olduunuz gibi karakter okumay biraz farkl yaptk.
Normalde, scanf( ) fonksiyonunu kullanmak yeterliyken, burada, iin iine bir de, do while girdi.
Aklayacak olursak, C'de karakter okumalar, biraz skntldr. Eer giri tampon belleinde
(Buffer) veri bulunuyorsa, bu direkt karaktere atanr. Bundan kurtulmak iin birok yntem olduu
gibi, uygulanabilecek bir yntem de, yukarda yazlm olan dng eklinde deer almaktr. nk
siz daha bir ey girmeden, ilk deer '\n' geleceinden, dngnn ikinci almasnda, doru deer
atanacaktr. lerki konularda, daha detayl ele alacamz bir problem olarak imdilik
nemsemeyelim. Sadece karakter okuyacanz zaman problem karsa, yukardaki gibi bir yntem
uygulanabileceini bilmeniz -imdilik- yeterli.
for Dngs
while ve do while dnda, nc bir dng tipi olarak, for yaps bulunmaktadr. Dier iki
dngden farkl olarak, for yaps, yenilemeli-tekrarlamal (ngilizce iterative) yaplarda kullanma
daha uygundur. Bunu performans anlamnda sylemiyorum. Demek istediim yazm teknii olarak,
for dngsnn daha kullanl olmasdr. rnein birbirini, srekli tekrar eden ilemlerin yapld
Nmerik Analiz gibi alanlar, for dngs iin iyi bir rnek olabilir. Ancak bu dediklerim sizi
yanltmasn; for dngs sadece soyut alanlarda alsn diye yaratlm bir ey deildir.
Programlarda, dier iki dngden ok daha fazla for kullanrsnz. nk for sadece matematiksel
hesaplama ilemlerinde deil, diziler ( array ) gibi konularda srekli kullanlan bir yapdr. Yazm
dierlerine nazaran daha sade olduundan, iteratif ilemlerde kullanlmas elbette ki tesadf olarak
dnlemez.
Aada for dngsnn genel yazmn ve ak diyagramn greceksiniz:
for Yaps
for Ak Diyagram
lk atacamz adm; elbette ki ekrana 10 kere "Merhaba Dnya" yazdrmak olacak. ( Umarm bu
Merhaba Dnya'larla sizi fazla skp, programlama iinden vazgeirmemiimdir. Programlama
mantn kaptktan sonra, dnyay daha farkl grmeye balayacak ve Merhaba Dnyalar'n
sebebini daha iyi anlayacaksnz. Ve inann btn bu eziyete deer... ) Buyrun programmz:
#include<stdio.h>
int main( void )
{
int i;
for( i = 0 ; i < 10; i++ ) {
printf("%2d: Merhaba Dnya\n",(i+1));
}
return 0;
}
Grdnz gibi ok daha sade ve ak gzkr bir kod oldu. for altnda tek satr komut
olduundan, kme parantezleri koymamz opsiyoneldi ama ne yaptnz kartrmamak iin, her
zaman koymanz neririm.
for dngleriyle ilgili baz zel durumlarda vardr. for dngs iersine yazdnz ilk deer atama,
kontrol ve arttrma ilemlerini tanmlama esnasnda yapmanz gerekmez. Aada verilen kod,
yukardakiyle tamamen ayn ii yapar. Fark, i'nin daha nce tanmlanm olmas ve arttrma/azaltma
iinin dng iinde yaplmasdr.
#include<stdio.h>
int main( void )
{
int i;
i = 0;
for( ; i < 10; ) {
printf("%2d: Merhaba Dnya\n",(i+1));
i = i + 1;
}
return 0;
}
break Komutu
Baz durumlarda, dngy aniden sonlandrmak isteriz. Bunun iin 'break' komutunu kullanrz.
Dngy aniden sonlandrmak veya dngy krmak ilemini, zaten daha nce switch case'lerde
kullanmtk. Bahsetmediimiz ey, bunun her dng iersinde kullanlabileceiydi.
Aadaki program inceleyelim:
/*
0 ile 99 arasnda tesadfi saylar reten
bir programn, kanc seferde 61 saysn
bulacan yazan program aadadr.
*/
#include<stdio.h>
int main( void )
{
int i,tesadufi_sayi;
int deneme_sayisi = 0;
//while iinde 1 olduundan sonsuza kadar dng alr.
while( 1 ){
//tesadufi_sayi deikenine, 0 ile 99 arasnda
//her seferinde farkl bir say atanr.
//rand( ) fonksiyonu tesadfi say atamaya yarar.
//mod 100 ilemiyse, atanacak saynn 0 ile 99
//arasnda olmasn garantiler.
tesadufi_sayi = rand() % 100;
//Dngnn ka defa altn deneme_sayisi
//deikeniyle buluruz.
deneme_sayisi++;
//Eer tesadufi say 61'e eit olursa,
//dng krlp, sonlandrlr.
if( tesadufi_sayi == 61 ) break;
}
printf("Toplam deneme says: %d\n",deneme_sayisi);
return 0;
}
Program iin koyulmu aklamalar ( comment ) zaten neyin n'olduunu aklyor. Ksaca bir eyler
eklemek gerekirse, bitiinin nerede olacan bilmediimiz bir dngy ancak, break komutuyla
sonlandrabiliriz. artlar salandnda, break komutu devreye girer ve dng sonlandrlr. Bunun
gibi bir ok rnek yaratmak mmkndr.
continue Komutu
break komutunun, dngy krmak iin olduundan bahsetmitik. Bunun dnda ilem yapmadan
dngy devam ettirmek gibi durumlara da ihtiyacmz vardr. Bunun iinde continue ( Trke:
devam ) komutunu kullanrz.
/*
Sadece tek saylar yazdran bir
program
*/
#include<stdio.h>
int main( void )
{
int i;
for( i = 0; i < 10; i++ ) {
//i deikeninin 2'ye gre modu
//0 sonucunu veriyorsa, bu onun
//bir ift say olduunu gsterir.
//Bu durumda ekrana yazdrlmamas
//iin dng bir sonraki adma geer.
0 ile 10 arasndaki tek saylar gsteren program rneini yukarda grebilirsiniz. Elbette ki bu ii
daha farkl ve daha iyi yapan bir program yazabilirdik. Ama imdilik continue komutunun nasl
kullanldn inceleyelim.
Program bir for dngs altrmaktadr. Her defasnda i deikenin 2'ye gre modu alnr. Eer
sonu 0'sa, bu saynn ift olduunu gsterir. Dolaysyla, bunun ekrana yazdrlmamas gerekir. Bu
yzden, dng iersindeki ilemleri srdrmek yerine, altta kalan kodlar atlarz. Burada continue
komutu kullanlr ve kullanld noktadan itibaren olan ilemler yaplmaz. Dng baa dner, ayn
ilemleri yapar. Bu sefer i tek say olacandan continue komutu almaz ve sayy ekrana
bastrrz.
goto Yaps
C programlama dilinde bulunan bir baka yap, goto deyimidir. Koyacanz etiketler sayesinde,
programn bir noktasndan bir baka noktasna atlamanz salar. goto, bir dng deildir ancak
dng olarak kullanlabilir.
goto, alabilmek iin etiketlere ihtiya duyar. Etiketler, vereceiniz herhangi bir isme sahip
olabilir. Etiket oluturmak iin btn yapmanz gereken; etiket adn belirleyip, sonuna iki nokta st
ste eklemek ( : ) ve programn herhangi bir yerine bunu yazmaktr. goto deyimi kullanarak bu
etiketleri arrsanz, etiketin altnda bulunan kodlardan devam edilir. goto ve etiketlere dair genel
yapy, ak diyagramyla birlikte aada bulabilirsiniz:
goto Yaps
goto Ak Diyagram
label_name:
.
.
.
if( kosul ) {
goto label_name
}
.
.
.
NOT: goto deyimi tek bana da kullanlabilir. Fakat mantksal bir snama olmadan, goto yapsn
kullanmanz, sonsuz dngye neden olacaktr.
imdi goto ifadesiyle basit bir dng rnei oluturalm. nceki seferlerde olduu gibi ekrana 10
defa "Merhaba Dnya" yazdralm:
#include<stdio.h>
int main( void )
{
int i = 0;
// baslangic_noktasi adinda bir etiket koyuyoruz.
// i degiskeni 10 degerine ulasmadigi surece,
stediiniz sayda etiket koyup, goto kullanarak, programn herhangi bir noktasna ulaabilirsiniz.
Programnz, etiket altnda kalan ksmdan itibaren alr. goto yapsyla gelen esneklik, ilk bakta
olduka gzel grnyor. Ancak goto iin birok kaynak, "ya hi kullanmayn ya da olabildiince
az kullann" demektedir.
Okunup, anlalmas zor ve zerinde allmas g bir koddan, herkesin uzak durmas gerekir.
ngilizce'de, karman orman koda, "spagetti kod" ad verilmitir. goto deyimi, kodunuzun spagetti
koda dnmesine neden olur. nk program aknn takibini zorlatrp, kodun okunabilirliini
azaltr. Diliyorsanz, goto deyimini kullanabilirsiniz. Ama zorunlu kalmadka kanmak en iyisi...
Say Tabanlar
Bilgisayar programlamayla, matematik arasnda ok gl bir iliki vardr. Gemie bakarsanz,
bilgisayar alannda nemli admlarn, hep matematik kkenli insanlar tarafndan atldn
grrsnz. Bir bilgisayar programcs iin, matematikten uzak durmak dnlemez.
Bugn ki dersimizde, biraz matematik iersine gireceiz ve say sistemleriyle, Boole Cebiri
(Boolean Algebra) konularn ele alacaz.
Genel kabul grm say sistemleri vardr ve ilerinde en yaygn, hepimizin gndelik hayatta
kulland 10'luk say sistemidir. Yazmas, okunmas ve ilem yapmas son derece kolay olduundan
bunu daha ocuk yata renir ve bu ekilde srdrrz. Ancak bilgisayarlar bizim gibi ilem
yapabilme yetisine sahip deildir. Onlar iin iki ihtimal vardr. Bir ey ya 1'dir ya da 0. Bunu ikilik
say sistemi olarak adlandrrz. Yani bizim yazdmz btn saylar, btn harfler ve aklnza
gelen-gelmeyen btn iaretler, bilgisayar iin 0 ve 1'in kombinasyonlarndan ibarettir. te bu
yzden bizlerin, ikilik say sistemine hakim olmas gerekir.
Say sistemlerini genel olarak aadaki gibi ifade edebiliriz:
Burada, N say tabanna gstermektedir. k saynn hangi hanesinde olduumuzu ifade ederken, dk
ise, ilgili saydaki rakam temsil eder. imdi basit bir rnek yapalm ve ikilik tabandaki 10011
saysnn, 10 tabanndaki e deerini bulalm:
( d4d3d2d1d0 )2 = ( d0 . 20 ) + ( d1 . 21 ) + ( d2 . 22 ) + ( d3 . 23 ) + ( d4 . 24
)
( 10011 )2 = ( 1 . 20 ) + ( 1 . 21 ) + ( 0 . 22 ) + ( 0 . 23 ) + ( 1 . 24 ) = 19
ikilik say sistemi dnda, 16'lk (Hexadecimal) say sistemi de olduka nemli bir baka tabandr.
16'lk say sisteminde, rakamlar ifade etmek iin 16 adet sembole gereksinim duyarz. Bu yzden 0
ile 9 arasnda olan 10 rakam kullandktan sonra, A, B, C, D, E ve F harflerini de rakam olarak
deerlendiririz.
Decimal
Hexadecimal
: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
: 0 1 2 3 4 5 6 7 8 9 A B C D E
15
F
16'lk say sisteminin dier bir ismi Hexadecimal olduundan, baz yerlerde, bunu ifade etmek iin
16 yerine 'H' harfi de kullanlabilir:
( BA3 )16 = ( BA3 )H ; ( A1E )16 = ( A1E )H gibi...
Tabanlar arasnda dntrme ilemi, zerinde duracamz bir baka konudur. Elinizde 16'lk say
sisteminde bir say varsa ve bunu 2'lik say sistemiyle yazmak isterseniz nce 10'luk say sistemine
evirip daha sonra 2'lik say sistemine dntrebilirsiniz. Ancak 16'lk ve 2'lik say sistemlerini ok
daha kolay birbirine dntrmeniz mmkndr. Aadaki tabloda 16'lk say sistemindeki
rakamlar ve bunun 2'lik say sistemindeki karl verilmitir:
Hexadecimal
Binary
( kilik )
: 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 11
1
0001
16'lk tabandaki her rakamn, 2'lik tabandaki karln koyduumuzda yukardaki eitlii elde
ediyoruz ve buna gre ( A3F1 ) = ( 1010 0011 1111 0001 )2 eitliini kurabiliyoruz. (2'lik tabandaki
sayya ait boluklar, saynn daha rahat okunmas iin braklmtr.) Bu tarz dnmler, 2 ve 2'nin
katnda olan say tabanlarnda rahatlkla yaplabilir.
Hatrlarsanz, deiken tiplerinde, iaretli ve iaretsiz deiken tanmlamalarndan bahsetmitik.
imdi olayn biraz daha derinine inelim. Bir char, 1 byte alan kaplar ve 1 byte, 8 bit'ten oluur.
Aadaki kutularn her birini bir bit ve kutularn oluturduu btn bir byte olarak dnn:
a7
a6
a5
a4
a3
a2
a1
a0
Yukardaki kutularn toplam olan bir byte, char deikeninin kaplad alan temsil etmektedir.
Pozitif saylar ifade etmeyi zaten renmitik. Saynn karln, 2'lik tabanda yazarak, gerekli
sonuca ularz. Ancak saymz Negatif deerliyse, iler biraz farkllar. Burada devreye iaret biti
(sign bit) devreye girer. Yukardaki ekilde, dier kutulardan farkl renkte olan a7 iaret bitidir.
zetle, a7 0 ise, say pozitiftir. Eer a7 1 ise, say negatiftir.
kilik tabandaki iaretli bir saynn, 10'luk tabandaki karln u ekilde bulabiliriz:
( a7a6a5a4a3a2a1a0 )2 = ( a7 . -27 ) + ( a6 . 26 ) + ... + ( a1 . 21 ) + ( a0 .
20 )
kilik tabanda yazlm ( 10000011 )2 says, iaretsiz olarak dnlrse, 131'e eittir. Ancak
iaretli bir say olduu dnlrse, karl, -125 olacaktr. Konunun pekimesi asndan
aadaki rneklere gz atabilirsiniz:
* (
(
* (
(
* (
(
1011
1011
1100
1100
0110
0110
1011
1011
1101
1101
1101
1101
)2
)2
)2
)2
)2
)2
=
=
=
=
=
=
-69
187
-51
205
109
109
(Say
(Say
(Say
(Say
(Say
(Say
iaretliyse)
iaretsizse)
iaretliyse)
iaretsizse)
iaretliyse)
iaretsizse)
Negatif bir saynn 2'lik tabandaki karln bulmak iin, nce (i) sayy pozitif olarak ikilik
tabanda yazarz. Daha sonra, (ii) ikilik tabanda yazlm saynn 1 yazan rakamlar 0, 0 yazan
rakamlar 1'e evrilir. Son olarak (iii) kan sayya, 1 eklenir. Bu size istediiniz saynn ikilik
tabanndaki eini verecektir. imdi bir uygulama yapalm ve -7 sayn ikilik tabana evirmeye
alalm:
i ) -7 ==> ( 7 )10 = ( 0000 0111 )2
ii ) ( 0000 0111 ) ==> ( 1111 1000 )
iii ) ( 1111 1000 ) + 1 = ( 1111 1001 ) ==> ( -7 )10 = ( 1111 1001 )2
p&q
OR ( | ) Operatr
ki deikenden herhangi biri 1 ieriyorsa, geriye 1 dner. Eer her ikisi de 0 ieriyorsa, geriye 0
dnmektedir.
p
p|q
NEML NOT: Bit baznda kullanlan, AND( & ) ve OR ( | ) operatrleri, koullu ifadelerde
kullanlan, AND( && ) ve OR ( || ) ifadelerinden farkldr. ayet, & veya | bir koullu ifade gibi
kullanmaya kalkarsanz, ilem yine yaplacaktr. Ancak bunu yapmanz tavsiye edilmez. lerki
konularmzda neden uygun olmad, short-circuit ile ilgili bilgi verilirken aklanacaktr.
NOT ( ~ ) Operatr
NOT ( ~ ) Operatr, kendisine verilen sayya ait bit'leri tam tersine evirir. Yani 0 grd yeri 1;
1 grd yeri 0 yapar.
p
~p
~
---------------------------230 ==> ( 1110 0110 )2
XOR ( ^ ) Operatr
XOR ( Exclusive OR ) Operatr, sadece ve sadece karlatrma yaplan bitlerden biri, 1 deerine
sahipse, geriye 1 dndrr. Eer karlatrma yaplan bit'lerden her ikisi de 0 veya 1'se, o zaman
sonu 0 olarak kar.
p^q
~x
Operatr ncelikleri
Hatrlarsanz, aritmetik ilemlerde nceliklerin olduunu ve rnein arpmann, toplamadan daha
nce yaplacan anlatmtk. Benzer bir durum, operatrler iinde geerlidir. Altta bulunan
tabloda, hangi operatrn daha nce ileme alndn bulabilirsiniz:
DK
&
YKSEK
DK
||
&&
== !=
YKSEK
Yukardaki tablolarda, ayn hcrede olan operatrlerin ilem ncelikleri ayndr. nce hangisi
yazlmsa, ilk olarak o dikkate alnr. Ama bunun dnda tannan bir ilem ncelii
bulunmamaktadr.
Aadaki rnek, operatr nceliklerini pekitirmek asndan incelenebilir:
7 & 13 ^ 11 % 4 * 2 << 14 / 4
==> 7 & 13 ^ 6 << 3
==> 5 ^ 48 = 53
rnek Sorular
imdiye kadar ilemi olduumuz dersleri pekitirmek iin, bu yazda rnek sorular zeceiz.
Sorularn hazrlanmasnda, arkadam Sunay SNMEZ'in byk emei gemitir. Kendisine
teekkr ederim.
Soru 1.a: Aadaki programn kts nedir?
#include<stdio.h>
int main( void )
{
int i = 0;
for( ; i < 12; i++ ) {
if( ( i++ + 1 ) == 5 )
printf( "%d\n",i );
else
if( i % 2 == 0 ) break;
else if( i % 3 == 0)
continue;
else
printf("%d\n", i );
}
return 0;
}
#include<stdio.h>
int main( void )
{
int sum;
float average;
int weight_1, weight_2;
printf( "1.agirlik> " );
scanf( "%d", &weight_1 );
sum += weight_1;
printf( "2.agirlik> " );
scanf( "%d", weight_2 );
sum += weight_2;
average = sum / 2;
printf( "Ortalama: %.2f\n", a
return 0;
}
#include<stdio.h>
int main( void )
{
int sum = 0;
float average;
int weight_1, weight_2;
printf( "1.agirlik> " );
scanf( "%d", &weight_1 );
sum += weight_1;
printf( "2.agirlik> " );
5
7
11
scanf( "%d",&weight_2 );
sum += weight_2;
average = sum / 2.0;
printf( "Ortalama: %.2f\n", a
return 0;
Soru 2: Bir gende, iki kenarn toplam uzunluu, nc kenardan az olamaz. Ayrca iki kenarn
birbirinden farknn mutlak deeri, nc kenardan byk olmamaldr. Bu bilgileri kullanarak,
verilen kenar uzunluuna gre bir gen izilip izilmeyeceini gsteren program yaznz.
Girilecek kenar uzunluklar tam say olacaktr.
Cevap 2:
/* Girilen 3 tamsayinin bir ucgenin kenari olup olmadigi kontrol edilir */
#include<stdio.h>
int main( void )
{
int a, b, c;
int temp;
printf("Birinci kenar uzunlugu> ");
scanf("%d", &a);
printf("Ikinci kenar uzunlugu> ");
scanf("%d", &b);
printf("Ucuncu kenar uzunlugu> ");
scanf("%d", &c);
/* a ile b den buyuk olan a ya kucuk olan b ye atanir */
if(a < b) {
temp = a;
a = b;
b = temp;
}
if( ((a + b) < c) || ((a - b) > c) )
printf("Bu kenar uzunluklarina sahip bir ucgen olamaz.\n");
else
printf("Bu kenar uzunluklarina sahip bir ucgen cizilebilir.\n");
}
return 0;
Soru 3: Klavyeden girilecek bir saynn asal say olup olmadn ekrana basan bir program yaznz.
Cevap 3:
/*
Bir saynn asal olup olmadn bulmak iin eitli metodlar
vardr. Aada bu metodlardan basit bir tanesi yazlmtr.
Eer saynn yarsna kadar kontrol etmek yerine, karekkne
kadar olan saylar test ederseniz, yine ayn sonu kacaktr.
Ancak anlalma konusunda sorun olmamas iin soru bu ekilde
zlmtr.
*/
#include<stdio.h>
int main( void )
int sayi, i;
//Sayy ilk bata asal kabul ediyoruz.
//asal_mi deikeni 1 ise, sayi asaldir.
int asal_mi = 1;
//Klavyeden, test edilmek zere bir say alnyor.
printf( "Bir say giriniz> " );
scanf("%d",&sayi);
//Girilen saynn, baka saylara gre srayla modunu
//alyoruz. Bir saynn modunu aldnzda, kalan 0 ise
//bu saynn blnebildiine ve dolaysyla
//asal olmadna dair bilgi verir. Bu ilemi yapabilmek
//iin 2'den balayarak, saynn yarsna kadar olan
//btn deerler deneniyor.
for( i = 2; i <= sayi/2; i++ ) {
if( sayi%i == 0 ) {
//Say i deikenine kalansz blnmektedir.
//Dolaysyla, say asal deildir ve dngy
//srdrmeye gerek yoktur.
asal_mi = 0;
break;
}
}
//Saynn asal olup olmama durumuna gre, kt yazdrlyor.
if( asal_mi == 1 )
printf( "%d says asaldr.\n", sayi );
else
printf( "%d says asal deildir.\n", sayi );
return 0;
Soru 4: Klavyeden girilecek 0 ile 999 arasnda bir tam saynn, yazyla ifade eden ( rnein 49,
'krkdokuz' gibi ) bir program oluturunuz.
Cevap 4:
/*
Girilen saynn, nasl okunduunu ekrana yazdran programdr.
Fonksiyon kullanmyla daha efektif olarak yazlabilir.
Ancak henz ilenmeyen bir konu olduundan, basit bir ekilde
yazlmtr.
*/
#include<stdio.h>
int main( void )
{
int sayi;
//Klavyeden girilecek sayinin 0 ile 999 snrlarnda
//olup olmad kontrol ediliyor. Eer deilse,
//uyar verilip, yeni bir say isteniyor. Bu ilem
//doru bir deer girilene kadar devam ediyor.
do {
printf( "Sayy giriniz> " );
scanf("%d",&sayi);
if( sayi>999 || sayi<0 )
printf("Girdiiniz say uygun deildir.\n"
"0 ile 999 arasnda olmaldr.\n");
else
break;
}while( 1 );
printf( "%d says, '",sayi );
//Verilen sayy, yazyla ifade edebilmemiz iin,
//yzler, onlar ve birler basamaklarna ayrmamz
//gerekmektedir.
//Saynn yzler basama ayrtrlyor.
//Bunun iin sayy, 100'e blmek yeterli.
//YZLER BASAMAI:
switch( sayi/100 ) {
case 9: printf(
case 8: printf(
case 7: printf(
case 6: printf(
case 5: printf(
case 4: printf(
case 3: printf(
case 2: printf(
case 1: printf(
}
"dokuzyz" );
"sekizyz" );
"yediyz" );
"altyz" );
"beyz" );
"drtyz" );
"yz" );
"ikiyz" );
"yz" );
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
"dokuz" );
"sekiz" );
"yedi" );
"alt" );
"be" );
"drt" );
"" );
"iki" );
"bir" );
break;
break;
break;
break;
break;
break;
break;
break;
break;
Soru 5: Drt basamakl bir saynn rakamlar ters yazlp, 4 ile arplrsa, kan sonu, kendisiyle
ayndr. Drt basamakl bu sayy bulunuz.
Cevap 5:
/*
Drt basamakl bir saynn rakamlar, ters yazlp, 4 ile
arplrsa, saynn kendisine eit olmaktadr. Bu program,
bahsedilen drt basamakl bu sayy bulmaktadr.
*/
#include<stdio.h>
int main( void )
{
//Drt basamakl bir saynn tersinin drt katna
//eit olmasn hesaplamamz gerektiinden, her
//basama ayr ayr dnmemiz gerekmektedir.
//Bilinmeyen bu sayy, abcd olarak dnebiliriz.
int a,b,c,d;
int sayi, sayinin_tersi;
for( a = 0; a < 10; a++ )
for( b = 0; b < 10; b++ )
for( c = 0; c < 10; c++ )
for( d = 0; d < 10; d++ ) {
//Burada sayinin degeri bulunmaktadir.
sayi = a * 1000 + b * 100 + c * 10 + d;
//Burada da sayinin tersi
hesaplanmaktadir.
10 + a;
0 ) {
sayi, sayinin_tersi );
//return ifadesi programin daha
fazla devam
kullanilmistir.
burada kesilir.
sonlandirir.
}
}
return 0;
Soru 6: Fibonacci serisinin ilk iki eleman 0 ve 1'dir. Bundan sonra gelen saylar, kendisinden
nceki iki saynn toplamyla bulunur. Yani seri elemanlar 0 1 1 2 3 5 8 13 21 ... eklinde
gitmektedir. Verilecek adm saysna gre, Fibonnaci serisinin elemanlarn gsterecek bir program
yaznz.
Cevap 6:
/* Fibonacci sayilarini ekrana yazar */
#include<stdio.h>int main( void )
{
int a = 0; /* a[n]
*/
int b = 1; /* a[n+1] */
int c;
/* a[n+2] */
int n;
int i;
printf("Fibonacci serisi kacinci elemana kadar yazilsin> ");
scanf("%d", &n);
for( i = 1; i <= n ; i++ ) {
printf( "%4d. Eleman: %d\n", i, a );
c = a + b;
a = b;
b = c;
}
}
return 0;
Soru 7: Verilecek kenar uzunluuna gre, yldz (*) iareti kullanarak kare izen, bir program
yaznz.
Cevap 7:
/* '*'ler kullanarak kenar uzunlugu verilen kareyi cizer */
#include<stdio.h>
int main( void )
{
int kenar;
int i;
int j;
printf("Karenin kenar uzunlugu: ");
scanf("%d", &kenar);
/* Gecerli bir deger mi */
while((kenar < 0) || (kenar > 20)) {
/* karenin cizilmesi */
for(i = 1; i <= kenar; i++) {
if(kenar == 0)
break;
/* alt ve st kenarlarin cizimi */
if((i == 1) || (i == kenar)) {
for(j = 1; j <= kenar; j++)
printf("*");
printf("\n");
continue;
} /* if sonu */
/* sag ve sol kenarlarin cizimi */
for(j = 1; j <= kenar; j++)
if((j == 1) || (j == kenar))
printf("*");
else
printf(" ");
printf("\n");
} /* for sonu */
}
return 0;
Cevap 8:
/* '*'ler yardimiyla eskenar dortgen cizer */
#include<stdio.h>
int main( void )
{
int i, j;
for(i = 1; i <= 5; i++) {
for(j = 1; j <= 9; j++)
if((j <= (9 - (2*i - 1))/2) || (j > (i + 4)))
printf(" ");
else
printf("*");
printf("\n");
}
for(i = 4; i >= 1; i--){
for(j = 1; j <= 9; j++)
if((j <= (9 - (2*i - 1))/2) || (j > (i + 4)))
printf(" ");
else
printf("*");
printf("\n");
return 0;
}
Soru 9: Hipotenus'u 500 birime kadar olan dik genlerin, kenar uzunluklarn gsteren bir
program yaznz. Kenar uzunluklar, sadece tam say olacaktr.
Cevap 9:
/* Hipotenusu 500'e kadar olan pisagor uclulerini ekrana yazar. */
#include<stdio.h>
int main( void )
{
int a; /* birinci dik kenar */
int b; /* ikinci dik kenar */
int hipotenus;
& Operatr
#include<stdio.h>
int main( void )
{
int
i =
j =
if(
i, j;
0;
5;
i == 1 && j++ ) {
printf( "if iersine girdi\n" );
}
else {
int
i =
j =
if(
}
else {
}
return 0;
if iersine girmedi
i: 0, j: 5
i, j;
0;
5;
i == 1 & j++ ) {
printf( "if iersine g
}
return 0;
if iersine girmedi
i: 0, j: 6
Grdnz gibi, program ktlar birbirinden farkldr. Bunun sebebi, ilk rnekte, i == 1 koulu
yanl olduu iin, && operatrnn ifadenin sa tarafna bakmamasdr. kinci rnekteyse, &
operatr, koulun her iki tarafna da bakar. Bu yzden, j deikenine ait deer deiir. Benzer bir
uygulamay, OR iin || ve | kullanarak yapabilirsiniz.
NEML NOT: zetle ilemlerinizi hzlandrmak istiyorsanz; AND kullanacanz zaman, &&
operatryle aln ve yanl olmas muhtemel olan koulu sol tarafa koyun. Eer OR operatr
kullanacaksanz, doru olma ihtimali fazla olan koulu, ifadenin soluna koyun ve operatr olarak
|| ile aln. Bu ekillde yazlan bir program, ksa devre operatrleri sayesinde, gereksiz kontrolden
kanarak ilemlerinizi hzlandracaktr.
Elbette & veya | operatrlerinin kullanlmas gereken durumlarda olabilir. Her n'olursa olsun,
koulun iki tarafnnda almasn istiyorsanz, o zaman & ve | operatrlerini kullanmanz
gerekmektedir.
nilemci Komutlar
Bir program yazdnz dnn... Bu programda, PI deerini birok yerde kullanmanz gerekiyor.
Siz de PI deeri olmas gereken her yere, 3.14 yazyorsunuz. Olduka skc bir i. leride PI'yi,
3.141592653 olarak deitirmek isterseniz daha da skc hle dnebilir. Veya cannz istedi,
printf( ) fonksiyonu yerine ekrana_yazdir( ) kullanmaya niyetlendiniz... te bu gibi durumlarda,
nilemci Komutlarn ( Preprocessor ) kullanrz. nilemci komutlarnn amac, bir eyi baka bir
ekilde ifade etmektir.
Konuya devam etmeden nce ufak bir uyar da bulunmakta yarar var. nilemci komutlarn,
deikenler veya fonksiyonlarla kartrmamak gerekiyor. Deikenlerin ve fonksiyonlarn daha
dinamik ve esnek bir yaplar varken, nilemci komutlar statiktir. Programnza direkt bir kod
yazdnz dnn. Bu kod herhangi bir ey (sembol, program paras, say, karakter vs...) olabilir.
rnein, her yerde PI'nin karl olarak 3.14 girmek yerine, PI diye bir sembol tanmlarz ve
bunun grld her yere 3.14' koyulmasn isteriz. nilemci komutlar bu gibi ilerde, biilmi
kaftandr.
#include<stdio.h>
#define PI 3.14
int main( void )
{
int yaricap;
float alan;
printf( "emberin yar apn giriniz> " );
scanf( "%d", &yaricap );
alan = PI * yaricap * yaricap;
printf( "ember alan: %.2f\n", alan );
return 0;
}
Grdnz gibi, PI bir deiken olarak tanmlanmamtr. Ancak #define komutu sayesinde, PI'nin
aslnda 3.14 olduu derleyici (compiler) tarafndan kabul edilmitir. Sadece #define komutunu
kullanarak baka eylerde yapmak mmkndr. rnein, daha nce dediimizi yapalm ve printf
yerine, ekrana_yazdir; scanf yerine de, deger_al isimlerini kullanalm:
/* Yarapa gre daire alan hesaplar */
#include<stdio.h>
#define PI
3.14
#define ekrana_yazdir
printf
#define deger_al
scanf
int main( void )
{
int yaricap;
float alan;
ekrana_yazdir( "emberin yar apn giriniz> " );
deger_al( "%d", &yaricap );
alan = PI * yaricap * yaricap;
ekrana_yazdir( "ember alan: %.2f\n", alan );
return 0;
}
return 0;
Yukardaki rnee bakacak olursak, nce PI deeri tanmlanyor ve sonrasnda tanm kaldrlyor.
Biz de srprizlerle karlamak istemediimizden, PI deerinin tanm durumunu kontrol ediyoruz.
Tek bana alan biri iin gereksiz bir ayrnt gibi gzkse de, ekip almalarnda, baz eylerin
kontrol edilmesi ve istenmeyen durumlarda, ne yaplaca belirlenmelidir. Yukarda ki program
yle de yazabilirdik:
#include<stdio.h>
int main( void )
{
int yaricap;
float alan;
printf( "emberin yar apn giriniz> " );
scanf( "%d", &yaricap );
// u noktaya kadar tanml bir PI deeri bulunmuyor.
// #ifndef opertr bu durumu kontrol ediyor.
// Eer tanmszsa, PI'nin tanmlanmas salanyor.
#ifndef PI
#define PI 3.14
#endif
alan = PI * yaricap * yaricap;
printf( "ember alan: %.2f\n", alan );
return 0;
}
1
2
n-1
n
#if ( HASSASLIK_DERECESI == 0 )
alan = 3 * yaricap * yaricap;
#elif ( HASSASLIK_DERECESI == 1 )
alan = 3.1 * yaricap * yaricap;
#elif ( HASSASLIK_DERECESI == 2 )
alan = 3.14 * yaricap * yaricap;
#else
alan = -1;
#endif
nemli Noktalar...
Konuyu noktalarken, sylemek istediim baz eyler bulunuyor. Olabildiince, nilemci
komutlarndan - #include komutu hari - uzak durun. nk bu komutlar, esnek bir yapya sahip
deiller ve bu durum, bir noktadan sonra banz artacaktr. nilemci komutlaryla yazlm
kodlar takip etmek olduka zordur ve debug edilemezler. Java gibi gelimi dillerde, #define
komutu bulunmaz. Modern dillerde, bu yapdan uzaklalmaya balanmtr.
Yukarda saydklarma ramen, baz durumlarda, nilemci komutlarn kullanmak uygun olabilir.
Kald ki bu komutlarn kullanld birok yer bulunuyor ve biz kullanmasak bile, bilmeye mecbur
durumdayz. Szn z; bu konuyu es gemek uygun deil. Ancak zerine dmek olduka
gereksiz.
Fonksiyonlar
C gibi prosedrel dillerin nemli konularndan birisi fonksiyonlardr. Java veya C# gibi dillerde
metot (method) ismini alrlar. Ad n'olursa olsun, grevi ayndr. Bir ilemi birden ok yaptnz
dnn. Her seferinde ayn ilemi yapan kodu yazmak olduka zahmetli olurdu. Fonksiyonlar, bu
soruna ynelik yaratlmtr. Sadece bir kereye mahsus yaplacak ilem tanmlanr. Ardndan
dilediiniz kadar, bu fonksiyonu arrsnz. stelik fonksiyonlarn yarar bununla da snrl
deildir.
Fonksiyonlar, modlerlik salar. Saynn asalln test eden bir fonksiyon yazp, bunun yanl
olduunu farkederseniz, btn program deitirmeniz gerekmez. Yanl fonksiyonu dzeltirsiniz ve
artk programnz doru alacaktr. stelik yazdnz fonksiyonlara ait kodu, baka programlara
tamanz olduka basittir.
Fonksiyonlar, almay kolaylatrr. Diskten veri okuyup, ileyen; ardndan kullancya
gsterilmek zere sonular grafik hline dntren; ve ilem sonucunu diske yazan bir program
batan aa yazarsanz, okumas ok g olur. Yorum koyarak kodun anlalabilirliini,
artrabilirsiniz. Ancak yine de yeterli deildir. zlenecek en iyi yntem, program fonksiyon
paralarna blmektir. rnein, diskten okuma ilemini disten_oku( ) isimli bir fonksiyon
yaparken; grafik izdirme iini grafik_ciz( ) fonksiyonu ve diske yazdrma grevini de
diske_yaz( ) fonksiyonu yapabilir. Yarn br gn, yazdnz kodu birileri incelediinde, sadece
ilgilendii yapya gz atarak, aradn ok daha rahat bulabilir. Binlerce satr iinde almaktansa,
paralara ayrlm bir yap herkesin iine gelecektir.
main( ) Fonksiyonu
imdiye kadar yazdmz btn kodlarda, main( ) eklinde bir notasyon kullandk. Bu
kullandmz ifade, aslnda main( ) fonksiyonudur. C programlama dilinde, bir kodun almas
main( ) fonksiyonun iersinde olup olmamasna baldr. Bir nevi balang noktas olarak
dnebiliriz. Her programda sadece bir tane main( ) fonksiyonu bulunur. Baka fonksiyonlarn,
ktphanelerin, kod paralarnn altrlmas main( ) iersinde direkt veya dolayl refere
edilmesiyle alakaldr.
main( ) fonksiyonuna dair bilgimizi pekitirmek iin bir program yazalm. Aadaki izimi
inceleyip, C programlama diliyle bunu izen program oluturalm.
/\
\
/
\
---------|
|
|
|
|
|
----------
);
);
);
);
);
);
);
);
);
return 0;
Programn zel bir yan yok. '\' simgesi zel olduu iin bundan iki tane yazmamz gerekti. Bunu
nceki derslerimizde ilemitik. Bunun dnda kodun herhangi bir zorluu olmad iin
aklamaya girmiyorum. Dikkat etmeniz gereken tek ey, kodun main( ) fonksiyonuyla almas.
Bilgilerimizi zetleyecek olursak; main( ) fonksiyonu zel bir yapdr. Hazrladmz program,
main( ) fonksiyonuyla almaya balar. main( ) fonksiyonu iersinde yer almayan kodlar
almaz.
Fonksiyon Oluturma
Kendinize ait fonksiyonlar oluturabilirsiniz. Oluturacanz fonksiyonlar, vereceiniz ilemi
yapmakla grevlidir ve arldka tekrar tekrar alr.
Yukardaki ev rneine geri dnelim. Her eyi main( ) iinde, tek bir yerde yazacamza, aty
izen ayr, kat izen ayr birer fonksiyon yazsaydk daha rahat olmaz myd? Ya da birden ok kat
izmemiz gerekirse, tek tek kat izmekle uramaktansa, fonksiyon adn armak daha akllca
deil mi? Bu sorularn yant, bizi fonksiyon kullanmaya gtryor. imdi yukarda yazdmz
return 0;
Yazdmz bu kod, ilk bata elde ettiimiz ktnn aynsn verir. Ama nemli bir fark ierir:. Bu
programla birlikte ilk defa fonksiyon kullanm olduk!
Fonksiyon kullanmann, ayn eyleri batan yazma zahmetinden kurtaracandan bahsetmitik.
Diyelim ki bize birden ok kat gerekiyor. O zaman kat_ciz( ) fonksiyonunu gereken sayda
armamz yeterlidir.
/* Ev sekli cizen program */
#include<stdio.h>
// Evin catisini cizen fonksiyon.
void catiyi_ciz( void )
{
printf( "
/\\
\n" );
printf( "
/ \\ \n" );
printf( " /
\\ \n" );
printf( " /
\\\n" );
printf( "----------\n" );
}
// Evin katini cizen fonksiyon.
void kat_ciz( void )
{
printf( "|
|\n" );
printf( "|
|\n" );
printf( "|
|\n" );
printf( "----------\n" );
}
// Programin calismasini saglayan
// ana fonksiyon.
int main( void )
catiyi_ciz( );
// 3 adet kat ciziliyor.
kat_ciz( );
kat_ciz( );
kat_ciz( );
return 0;
Yukarda yazl kod, bir stekinden pek farkl durmasa bile, bu sefer katl bir evin ktsn elde
etmi olacaksnz.
Yaptmz rneklerde, kullanlan void ifadesi dikkatinizi ekmi olabilir. ngilizce bir kelime olan
void, bo/geersiz anlamndadr. C programlama dilinde de buna benzer bir anlam tar. kat_ciz( );
fonksiyonuna bakalm. Yapaca i iin herhangi bir deer almas gerekmiyor. rnein verilen
saynn asalln test eden bir fonksiyon yazsaydk, bir deiken almamz gerekirdi. Ancak bu
rnekte grdmz kat_ciz( ); fonksiyonu, dardan bir deere gerek duymaz. Eer bir fonksiyon,
almak iin dardan gelecek bir deere ihtiya duymuyorsa, fonksiyon adn yazdktan sonra
parantez iini bo brakabiliriz. Ya da void yazarak, fonksiyonun bir deer almayacan belirtiriz.
( Srekli olarak main( ) fonksiyonuna void koymamzn sebebi de bundandr; fonksiyon argman
almaz. ) kinci yntem daha uygun olmakla birlikte, birinci yntemi kullanmann bir mahsuru yok.
Aada bulunan iki fonksiyon ayn ekilde alr:
// Evin katini cizen fonksiyon.
// void var
void kat_ciz( )
{
printf(
printf(
printf(
printf(
}
);
);
);
);
"|
|\n"
"|
|\n"
"|
|\n"
"----------\n"
);
);
);
);
void ifadesinin, deer alnmayacan gstermek iin kullanldn grdnz. Bir de fonksiyonun
deer dndrme durumu vardr. Yazdnz fonksiyon yapaca ilemler sonucunda, arld
noktaya bir deer gnderebilir. Deer dndrme konusunu, daha sonra ileyeceiz. imdilik deer
dndrmeme durumuna bakalm.
Yukarda kullanlan fonksiyonlar, geriye bir deer dndrmemektedir. Bir fonksiyonun geriye deer
dndrmeyeceini belirtmek iin, void ifadesini fonksiyon adndan nce yazarz. Byleyece geriye
bir deer dnmeyecei belirtilir.
Argman Aktarm
Daha nce ki rneklerimiz de, fonksiyonlar dardan deer almyordu. Bu yzden parantez ilerini
bo brakmay ya da void ifadesini kullanmay grmtk. Her zaman byle olmas gerekmez;
fonksiyonlar dardan deer alabilirler.
Fonksiyonu tanmlarken, fonksiyona nasl bir deerin gnderileceini belirtiriz. Gnderilecek
deerin hangi deiken tipinde olduunu ve deiken adn yazarz. Fonksiyonu tanmlarken,
yazdmz bu deikenlere 'parametre' (parameter) denir. Argman (argument) ise, parametrelere
deer atamasnda kullandmz deerlerdir. Biraz karmak m geldi? O zaman bir rnekle
aklayalm.
Daha nce izdiimiz ev rneini biraz gelitirelim. Bu sefer, evin duvarlar dz izgi olmasn;
kullanc istedii karakterlerle, evin duvarlarn izdirsin.
return 0;
imdi de baka bir rnek yapalm ve verilen herhangi bir saynn tek mi yoksa ift mi olduuna
karar veren bir fonksiyon oluturalm:
Kod arasna konulan yorumlarda grebileceiniz gibi, deikenler lokal olarak tanmlanmasa, a'nin
deeri farkl olurdu. Saynn karesini bulduktan sonra, kpn yanl hesaplardk. Deikenler lokal
olduu iin, her aamada farkl bir deiken tanmland ve sorun kartacak bir durum olmad.
Benzer bir program global deikenler iin inceleyelim:
#include<stdio.h>
int sonuc = 0;
// Verilen sayinin karesini hesaplayip,
// global 'sonuc' degiskenine yazar.
void kare_hesapla( int sayi )
{
sonuc = sayi * sayi;
}
int main( void )
{
// main( ) fonksiyonunda
// a degiskeni tanimliyoruz.
int a;
printf( "Say giriniz> ");
scanf( "%d",&a );
printf( "Girdiiniz say\t: %d\n", a );
kare_hesapla( a );
printf("Saynn karesi\t: %d\n", sonuc );
return 0;
}
Grdnz gibi, sonuc isimli deiken her iki fonksiyonun dnda bir alanda, programn en
banda tanmlanyor. Bu sayede, fonksiyon bamsz bir deiken elde ediyoruz.
Global deikenlerle ilgili dikkat etmemiz gereken bir iki ufak nokta bulunuyor: Global bir
deikeni fonksiyonlarn dnda bir alanda tanmlarz. Tanmladmz noktann altnda kalan btn
fonksiyonlar, bu deikeni tanr. Fakat tanmlanma noktasnn stnde kalan fonksiyonlar, deikeni
grmez. Bu yzden, btn programda geerli olacak gerek anlamda global bir deiken
istiyorsanz, #include ifadelerinin ardndan tanmlamay yapmanz gerekir. Ayn ismi tayan yerel
ve global deikenleri ayn anda kullanyorsak, i birazck farkllar.
Bir fonksiyon iersinde, Global deikenle ayn isimde, yerel bir deiken bulunduruyorsanz, bu
durumda lokal deikenle ilem yaplr. Akcas, snrsz sayda deiken ismi vermek
mmknken, global deikenle ayn ad vermenin uygun olduunu dnmyorum. Program
akn takip etmeyi zorlatracandan, ortak isimlerden kanmak daha akllca.
Lokal ve global deikenlere dair son bir not; lokal deikenlerin sadece fonksiyona zg olmas
printf("i : %d\n",i);
degerini
*/
tasiyan
printf("i : %d\n",i);
return fadesi
Yazmzn st ksmlarnda fonksiyonlarn geriye deer dndrebileceinden bahsetmitik. Bir
fonksiyonun geriye deer dndrp dndrmemesi, o fonksiyonu genel yap iersinde nasl
kullanacanza baldr. Eer hazrlayacanz fonksiyonun, alp, retecei sonular baka
yerlerde kullanmayacaksanz, fonksiyondan geriye deer dnmesi gerekmez. Ancak fonksiyonun
rettii sonular, bir deikene atayp kullanacaksanz, o zaman fonksiyonun geriye deer
dndrmesi gerekir. Bunun iin 'return' ifadesini kullanrz.
Daha nce grdmz geriye deer dndrmeyen fonksiyonlar tanmlarken, bana void
koyuyorduk. Geriye deer dndren fonksiyonlar iinse, hangi tipte deer dnecekse, onu
fonksiyon adnn bana koyuyoruz. Diyelim ki fonksiyonumuz bir tamsay dndrecekse, int; bir
karakter dndrecekse char diye belirtiyoruz. Fonksiyon iersinden neyin dneceine gelince,
burada da return ifadesi devreye giriyor.
Fonksiyonun neresinde olduu farketmez, return sonu dndrmek zere kullanlr. Dndrecei
sonu, elle girilmi veya deikene ait bir deer olabilir. nemli olan dndrlecek deiken
tipiyle, dndrlmesi vaad edilen deiken tipinin birbirinden farkl olmamasdr. Yani
int kup_hesapla( ) eklinde bir tanmlama yaptysanz, double tipinde bir sonucu dndremezsiniz.
Daha dorusu dndrebilirsiniz ama program yanl alr. Tip uyumazl genel hatalardan biri
olduu iin, titiz davranmanz tlerim.
imdi return ifadesini kullanabileceimiz, bir program yapalm. Kullancdan bir say girilmesi
istensin; girilen say asal deilse, tekrar ve tekrar say girmesi gereksin:
#include<stdio.h>
// Verilen sayinin asal olup olmadigina
// bakar. Sayi asalsa, geriye 1 aksi hlde
// 0 degeri doner.
return 0;
Dikkat edilmesi gereken bir dier konu; return koyduunuz yerde, fonksiyonun derhl
sonlanmasdr. Fonksiyonun kalan ksm almaz. Geriye deer dndrmeye fonksiyonlar iin de
ayn durum geerlidir, onlarda da return ifadesini kullanabilirsiniz. Deer dndrsn, dndrmesin
yazdnz fonksiyonda herhangi bir yere 'return;' yazn. Fonksiyonun bu noktadan itibaren
almay kestiini farkedeceksiniz. Bu fonksiyonu altrmann uygun olmad artlarda,
kullanabileceiniz bir yntemdir. Bir kontrol ekrannda, kullanc ad ve/veya ifresini yanl
girildiinde, programn almasn annda kesmek isteyebilirsiniz. Byle bir durumda 'return;'
kullanlabilir.
Dersimizi burada tamamlayp rnek sorulara gemeden nce, fonksiyonlara ait genel yapy
incelemenizi neririm.
donus_tipi fonksiyon_adi( alacagi_arguman[lar] )
{
.
.
FONKSYON ER
( YAPILACAK LEMLER )
.
.
[return deger]
}
NOT: Keli parantez grdnz yerler opsiyoneldir. Her fonksiyonda yazlmas gerekmez.
Ancak oluturacanz fonksiyon yapsna bal olarak yazlmas artta olabilir. Mesela dn tipi
olarak void dnda bir deiken tipi belirlediyseniz, return koymanz gerekir.
return 0;
Yukarda bahsettiimiz hcrelerden oluan bellek yapsn, bu kod paras iin uygulayalm.
Deiken tiplerinden int'in 2 byte, float'un 4 byte ve char'n 1 byte yer kapladn kabul edelim. Her
bir hcre 1 byte'lk alan temsil etsin. Deikenler iin ayrlan hafza alan, 4300 adresinden
balasn. imdi bunlar temsili bir ekle dkelim:
Bir deiken tanmladmzda, bellekte gereken alan onun adna rezerve edilir. rnein 'int num1'
yazlmas, bellekte uygun bir yer bulunup, 2 byte'n, num1 deikeni adna tutulmasn salyor.
Daha sonra num1 deikenine deer atarsak, ayrlan hafza alanna 5 says yazlyor. Aslnda, num1
ile ilgili yapacanz btn ilemler, 4300 adresiyle 4302 adresi arasndaki bellek hcrelerinin
deimesiyle alakaldr. Deiken dediimiz; uygun bir bellek alannn, bir isme revize edilip,
kullanlmasndan ibarettir.
Bir parantez ap, kk bir uyar da bulunalm. eklimizin temsili olduunu unutmamak gerekiyor.
Deikenlerin bellekteki yerleimi bu kadar 'uniform' olmayabilir. Ayrca balang adresini 4300
olarak belirlememiz keyfiydi. Saylar ve tutulan alanlar deiebilir. Ancak bellein yapsnn, aa
yukar byle olduunu kabul edebilirsiniz.
Pointer Mekanizmas
Bir deikene deer atadmzda, aslnda bellek hcrelerini deitirdiimizi sylemitik. Bu doru
bir tanm ama eksik bir noktas var. Bellek hcrelerini deitermemize ramen, bunu direkt
yapamaz; deikenleri kullanrz. Bellek hcrelerine direkt mdahle Pointer'lar sayesinde
gerekleir.
Pointer, birok Trke kaynakta 'iareti' olarak geiyor. Direkt evirirseniz mantkl. Ancak
terimlerin znde olduu gibi renilmesinin daha yararl olduunu dnyorum ve ben Pointer
olarak anlatacam. Baz yerlerde iareti tanm grrseniz, bunun pointer ile ayn olduunu bilin.
imdi gelelim Pointer'in ne olduuna...
Deikenler bildiiniz gibi deer (say, karakter, vs...) tutar. Pointer'lar ise adres tutan
deikenlerdir. Bellekten bahsetmitik; kk hcrelerin oluturduu hafza blounun adreslere
ayrldn ve deikenlerin bellek hcrelerine yerletiini grdk. te pointer'lar bu bellek
adreslerini tutarlar.
Pointer tanmlamak olduka basittir. Sadece deiken adnn nne '*' iareti getiririz. Dikkat
edilmesi gereken tek nokta; pointer' iaret edecei deiken tipine uygun tanmlamaktr. Yani float
bir deikeni, int bir pointer ile iaretlemee almak yanltr! Aadaki rnee bakalm:
#include<stdio.h>
int main( void )
{
// int tipinde deiken
// tanmlyoruz:
int xyz = 10, k;
return 0;
Kod parasndaki yorumlar okuduunuzda, pointer ile ilgili fikriniz olacaktr. Pointer adres tutan
deikenlerdir. imdiye kadar grdmz deikeninlerin saklayabildii deerleri tutamazlar.
Sadece deikenleri iaret edebilirler. Herhangi bir deikenin adresini pointer iersine atamak
isterseniz, deiken adnn nne '&' getirmeniz gerekir. Bundan sonra o pointer, ilgili deikeni
iaret eder. Eer bahsettiimiz deikenin sahip olduu deeri pointer ile gstermek veya deiken
deerini deitirmek isterseniz, pointer bana '*' getirerek ilemlerinizi yapabilirsiniz. Pointer
bana '*' getirerek yapacanz her atama ilemi, deikeni de etkileyecektir. Daha kapsaml bir
rnek yapalm:
#include<stdio.h>
int main( void )
{
int x, y, z;
int *int_addr;
x = 41;
y = 12;
// int_addr x degiskenini
// isaret ediyor.
int_addr = &x;
// int_addr'in isaret ettigi
// degiskenin sakladigi deger
// aliniyor. (yani x'in degeri)
z = *int_addr;
printf( "z: %d\n", z );
// int_addr, artik y degiskenini
// isaret ediyor.
int_addr = &y;
// int_addr'in isaret ettigi
// degiskenin sakladigi deger
// aliniyor. (yani y'nin degeri)
z = *int_addr;
printf( "z: %d\n" ,z );
return 0;
}
Bir pointer'in iaret ettii deikeni program boyunca srekli deitirebilirsiniz. Yukardaki rnekte,
int_addr pointer'i, nce x'i ve ardndan y'yi iaret etmitir. Bu yzden, z deikenine int_addr
kullanarak yaptmz atamalar, her seferinde farkl sonular dourmutur. Pointer kullanarak,
deikenlerin saklad deerleri de deitirebiliriz. imdi bununla ilgili bir rnek inceleyelim:
#include<stdio.h>
int main( void )
{
int x, y;
int *int_addr;
x = 41;
y = 12;
// int_addr x degiskenini
// isaret ediyor
int_addr = &x;
// int_addr'in isaret ettigi
// degiskenin degerini
// degistiriyoruz
*int_addr = 479;
printf( "x: %d y: %d\n", x, y );
int_addr = &y;
return 0;
}
Kodu derleyip, altrdnzda, x'in deerinin deitiini greceksiniz. Pointer bana '*' getirip,
pointer'a bir deer atarsanz; aslnda iaret ettii deikene deer atam olursunuz. Pointer ise hi
deimeden, ayn adres bilgisini tutmaya devam edecektir.
return 0;
Yazm olduumuz kod iersinde kimin neyi gsterdiini grafikle daha iyi anlayabiliriz:
Birbirini gsteren Pointer'lar ilerki derslerimizde, zellikle dinamik bellek tahsis ederken ok
ihtiya duyacamz bir yap. O yzden iyice renmek gerekiyor.
return 0;
return 0;
Fonksiyon Prototipleri
Bildiiniz gibi fonksiyonlarmz, main( ) zerine yazyoruz. Tek ksa bir fonksiyon iin bu durum
rahatsz etmez; ama uzun uzun 20 adet fonksiyon olduunu dnn. main( ) fonksiyonu sayfalar
dolusu kodun altnda kalacak ve okunmas gleecektir. Fonksiyon prototipleri burada devreye
girer.
Bir stte yazdmz program tekrar yazalm. Ama bu sefer, fonksiyon prototipi yapsna uygun
olarak bunu yapalm:
#include<stdio.h>
int bolme_islemi( int, int, int * );
int main( void )
{
int bolunen, bolen;
int bolum, kalan;
bolunen = 13;
bolen = 4;
bolum = bolme_islemi( bolunen, bolen, &kalan );
printf( "Blm: %d Kalan: %d\n", bolum, kalan );
return 0;
}
int bolme_islemi( int bolunen, int bolen, int *kalan )
{
*kalan = bolunen % bolen;
return bolunen / bolen;
}
yazabilirdik ama buna gerek yok. ) Daha sonra main( ) fonksiyonu altna inip, fonksiyonu yazdk.
rendiklerimizi pekitirmek iin yeni bir program yazalm. Fonksiyonumuz, kendisine argman
olarak gnderilen bir pointer'i alp; bu pointer'in bellekteki adresini, iaret ettii deikenin deerini
ve bu deikenin adresini gstersin.
#include<stdio.h>
void pointer_detayi_goster( int * );
int main( void )
{
int sayi = 15;
int *pointer;
// Degisken isaret ediliyor.
pointer = &sayi;
// Zaten pointer oldugu icin '&'
// isaretine gerek yoktur. Eger
// bir degisken olsaydi, basina '&'
// koymamiz gerekirdi.
pointer_detayi_goster( pointer );
return 0;
}
void pointer_detayi_goster( int *p )
{
// %p, bellek adreslerini gostermek icindir.
// 16 tabaninda (Hexadecimal) sayilar icin kullanilir.
// %p yerine, %x kullanmaniz mumkundur.
printf( "Pointer adresi\t\t\t: %p\n", &p );
printf( "aret ettii deikenin adresi\t: %p\n", p );
printf( "aret ettii deikenin deeri\t: %d\n", *p );
}
Fonksiyon prototipi, "Function Prototype"dan geliyor. Bunun gzel bir eviri olduunu
dnmyorum. Ama aklma daha uygun bir ey gelmedi. neriniz varsa deitirebiliriz.
Rekrsif Fonksiyonlar
Bir fonksiyon iersinden, bir dierini arabiliriz. Rekrsif fonksiyonlar, fonksiyon iersinden
fonksiyon armann zel bir hlidir. Rekrsif fonksiyon bir baka fonksiyon yerine kendisini
arr ve artlar uygun olduu srece bu tekrarlanr. Rekrsif, Recursive kelimesinden geliyor ve
tekrarlamal, yinelemeli anlamn tayor. Kelimenin anlamyla, yapt i rtmekte.
Rekrsif fonksiyonlar aklmzdan kartp, bildiimiz yntemle 1, 5, 9, 13 serisini oluturan bir
fonksiyon yazalm:
#include<stdio.h>
void seri_olustur( int );
int main( void )
{
seri_olustur( 1 );
}
void seri_olustur( int sayi )
{
while( sayi <= 13 ) {
printf("%d ", sayi );
sayi += 4;
}
}
Bu fonksiyonu yazmak olduka basitti. imdi ayn ii yapan rekrsif bir fonksiyon yazalm:
#include<stdio.h>
Son yazdmz programla, bir nce yazdmz program ayn ktlar retir. Ama birbirlerinden
farkl alrlar. kinci programn farkn ak diyagramna bakarak sizler de grebilirsiniz. Rekrsif
kullanm, fonksiyonun tekrar tekrar arlmasn salamtr.
Daha nce faktriyel hesab yapan program yazmtk. imdi faktriyel hesaplayan fonksiyonu,
rekrsif olarak yazalm:
#include<stdio.h>
int faktoriyel( int );
int main( void )
{
printf( "%d\n", faktoriyel(5) );
}
int faktoriyel( int sayi )
{
if( sayi > 1 )
return sayi * faktoriyel( sayi-1 );
return 1;
}
Rekrsif yaplar, olduka karmak olabilir. Fakat kullanl olduklar kesin. rnein silme
komutlar rekrsif yaplardan yararlanr. Bir klasr altnda bulunan her eyle birlikte silmeniz
gerekiyorsa, rekrsif fonksiyon kanlmazdr. Ya da baz matematiksel ilemlerde veya arama
( search ) yntemlerinde yine rekrsif fonksiyonlara bavururuz. Bunlarn dnda rekrsif
fonksiyonlar, normal fonksiyonlara gre daha az kod kullanlarak yazlr. Bunlar rekrsif
fonksiyonlarn olumlu ynleri... Ancak hibir ey mkemmel deildir.
Rekrsif fonksiyon kullanmann bilgisayarnza binderecei yk daha fazladr. Faktoriyel rneine
bakn; tam 5 kez ayn fonksiyonu aryoruz ve bu srada btn deerler bellekte tutuluyor. Eer
ok sayda iterasyondan sz ediyorsak, belleiniz hzla tkenecektir. Rekrsif yaplar, bellekte
ekstra yer kaplad gibi, normal fonksiyonlara gre daha yavatr. stelik ksa kod yazmna
karn, rekrsif fonksiyonlarn daha karmak olduklarn syleyebiliriz. Anlamak zaman zaman
sorun olabiliyor. Ksacas bir programda gerekten rekrsif yapya ihtiyacnz olmad srece,
ondan kanmanz daha iyi!
rnek Sorular
Soru 1: Aadaki programa gre, a, b ve c'nin deerleri nedir?
#include<stdio.h>
int main( void )
{
float a, b, c;
float *p;
a = 15.4;
b = 48.6;
p = &a;
c = b = *p = 151.52;
printf( "a: %f, b: %f, c: %f\n", a, b, c );
return 0;
}
Cevap 1:
a: 151.52, b: 151.52, c: 151.52
Soru 2: Fibonnacci serisinde herhangi bir seri elemann deerini bulmak iin f( n ) = f( n - 1 ) +
f( n - 2 ) fonksiyonu kullanlr. Balang deeri olarak f( 0 ) = 0 ve f( 1 ) = 1'dir. Bu bilgiler
nda, verilen n saysna gre, seride karlk den deeri bulan fonksiyonu rekrsif olarak
yaznz.
Cevap 2:
#include<stdio.h>
int fibonacci( int );
int main( void )
int i;
// Fibonacci serisinin ilk 10 elemani
// yazilacaktir.
for( i = 0; i < 10; i++ ) {
printf( "f(%d)= %d\n", i, fibonacci( i ) );
}
return 0;
}
int fibonacci( int eleman_no )
{
if( eleman_no > 1 ) {
return fibonacci( eleman_no - 1 ) +
fibonacci( eleman_no - 2 ) ;
}
else if( eleman_no == 1 )
return 1;
else
return 0;
}
Diziler
Bir bilgisayar program yaptnz dnn. Kullancnn 100 deer girmesi isteniyor. Girilen btn
bu saylarn farkl aamalardan geeceini ve bu yzden hepsini ayr bir deikende tutmamz
gerektiini varsayalm. Bu durumda ne yapardnz? a0, a1, a2, ..., a99 eklinde 100 tane deiken
tanmlamak elbette mmkn; ama olduka zahmetli olurdu. Srf deikenleri tanmlarken
kaybedeceiniz zaman dnrseniz ne demek istediimi anlarsnz. Bunun iin alternatif bir
zmn gerektii mutlak!
ok sayda deikenin gerektii durumlarda, diziler imdadmza yetiir. (Dizi, ngilizce kaynaklarda
array olarak geer.) 100 deiken tanmlamamzn gerektii yukardaki rnee dnelim. Tek tek
a0, ..., a100 yaparak bunu nasl yazacanz zaten biliyorsunuz. imdi tek satrda dizi tanmlayarak,
bunu nasl yapacamz grelim:
int a[100];
Yukardaki tek satr, bellek blounda 100 adet int deiken yeri ayrr. Tek satr kod elbette aklayc
deil, o yzden bunu aadaki ekille aklayalm:
Her eyin banda dizideki elemanlarn deiken tipini yazyoruz; buradaki rneimizde tam say
gerektii iin 'int' yazdk. Daha sonra diziye 'a' yazarak bir isim veriyoruz. Deikenleri nasl
isimlendiriyorsak, ayn kurallar diziler iin de geerli... Son aamada bu dizinin ka eleman
iereceini belirtiyoruz. Keli parantezler ( [ ] ) iinde yazdmz 100 says, 100 adet int tipinde
deikenin oluturulmasn salyor.
Bir deikene ularken, onun adn yazarz. Dizilerde de aa yukar byle saylr. Fakat ufak
farklar vardr. Bir dizi, birden ok elemandan oluur. Bu yzden sadece dizi adn yazmaz, ulamak
rneimizi inceleyelim. En bata 12 elemanl aylar dizisini, "int aylar[12]" yazarak tanmlyoruz.
Her ay iin deer girilmesini gerekiyor. Klavyeden girilen saylarn okunmas iin elbette scanf( )
fonksiyonunu kullanacaz ama ufak bir farkla! Eer 'a' isimde bir deikene atama yapyor
olsaydk, hepinizin bilecei ekilde "scanf("%d", &a )" yazardk. Fakat dizi elemanlarna atama
yaplacandan komutu, "scanf( "%d", &aylar[ i ] )" eklinde yazmamz gerekiyor. Dng iindeki
i deikeni, 0'dan 11'e kadar srasyla artyor. Bu sayede, dngnn her admnda farkl bir dizi
elemanna deer atyabiliyoruz. ( i deikeni, bir nevi indis olarak dnlebilir. ) Klavyeden
okunan deerlerin dizi elemanlarna atanmasndan sonra, ikinci dng balyor. Bu dngde girmi
olduunuz deerler listelenip, ayn esnada toplam gneli gn says bulunuyor. Son aamada,
hesaplanan toplam deerini yazdrp, program bitiriyoruz.
Dikkat ederseniz, deerlerin alnmas veya okunmas gibi ilemler dngler araclyla yapld.
Bunlar dngler aracl ile yapmak zorunda deildik. Mesela "scanf("%d", &aylar[5] )" yazp,
6.ayn deerini; "scanf("%d", &aylar[9] )" yazp, 10.ayn deerini klavyeden alabilirdik. Ancak
byle yapmak, dng kullanmaktan daha zahmetlidir. Yanlgya dmemeniz iin dngleri
kullanmann kural olmadn, sadece ileri kolaylatrdn hatrlatmak istedim. Gerek tek tek,
gerekse rnekte yaptmz gibi dnglerle zm retebilirsiniz.
Baka bir rnek yapalm. Kullancmz, float tipinde 10 adet deer girsin. nce bu deerlerin
ortalamas bulunsun, ardndan ka adet elemann ortalamann altnda kald ve ka adet elemann
ortalamann stnde olduu gsterilsin.
#include<stdio.h>
return 0;
Program pek karmak deil. Dizi elemanlarn alyor, ortalamalarn hesaplyor, elemanlar
ortalamayla karlatrp, ortalamadan byk ve kk elemanlarn adedini veriyoruz. Anlalmas
g bir ey bulacanz sanmyorum. Tek karmak gelecek nokta, ikinci dngde neden bir else
olmad olabilir. Olduka geerli bir sebebi var ve if else-if yapsn iyice renenler byle
braklmasn anlayacaklardr. Bilmeyenlere gelince... her eyi ben sylersem, iin tad tuzu kalmaz;
eski konular gzden geirmelisiniz.
Kme parantezleri iinde grdnz her deer, srasyla bir elemana atanmtr. rnein dizi1'in
ilk eleman 4 olurken, son eleman 42'dir.
Yukardaki tanmlamalarda farkedeceiniz gibi dizi boyutlarn 6 ve 5 eklinde belirttik. lk deer
atamas yapacamz durumlarda, dizinin boyutunu belirtmeniz gerekmez; dizi boyutunu yazp
yazmamak size baldr. Dilerseniz dizi boyutunu belirtmeden aadaki gibi de yazabilirdiniz:
Derleyici, atanmak istenen deer saysna bakar ve dizi1 ile dizi2'nin boyutunu buna gre belirler.
dizi1 iin 6, dizi2 iin 5 tane deer belirtmiiz. Bu dizi1 dizisinin 6, dizi2 dizisinin 5 elemanl
olacan iaret eder.
Deer atamayla ilgili ufak bir bilgi daha aktarmak istiyorum. Aada iki farkl ilk deer atama
yntemi bulunuyor. Yazm fark olmasna ramen, ikisi de ayn ii yapar.
int dizi[ 7 ] = { 0, 0, 0, 0, 0, 0, 0 };
int dizi[ 7 ] = { 0 };
Bir diziyi tanmlayn ve hibir deer atamadan, dizinin elemanlarn printf( ) fonksiyonuyla
yazdrn. Ortaya anlamsz saylar ktn greceksiniz. Bir dizi tanmlandnda, hafzada gerekli
olan yer ayrlr. Fakat daha nce bu hafza alannda ne olup olmadyla ilgilenilmez. Ortaya kan
anlamsz saylar bundan kaynaklanr. nceden hafzada bulunan deerlerin yansmasn grrsnz.
Modern programlama dillerinin bir ounda, dizi tanmladnzda, dizinin btn elemanlar 0
deeriyle balar; sizin herhangi bir atama yapmanza gerek yoktur. C programlama dilindeyse,
kendiliinden bir balang deeri atanmaz. Bunu yapp yapmamak size kalmtr. Ksacas ilerin
daha kontrol gitmesini istiyorsanz, dizileri tanmlarken "dizi[ 7 ] = { 0 };" eklinde tanmlamalar
yapabilirsiniz.
lk deer atanmasyla ilgili bir rnek yapalm. 10 elemanl bir diziye atadmz ilk deerin
maksimum ve minimum deerleri gsterilsin:
#include<stdio.h>
int main( void )
{
// dizi'yi tanitirken, ilk deger
// atiyoruz
int dizi[ ] = { 15, 54, 1, 44, 55,
40, 60, 4, 77, 45 };
int i, max, min;
// Dizinin ilk elemanini, en kucuk
// ve en buyuk deger kabul ediyoruz.
// Bunun yanlis olmasi onemli degil;
// sadece bir noktadan kontrole baslamamiz
// gerektiginden boyle bir secim yaptik.
min = dizi[ 0 ];
max = dizi[ 0 ];
for( i = 1; i < 10; i++ ) {
// min'in degeri, dizi elemanindan
// buyukse, min'in degerini degistiririz.
// Kendisinden daha kucuk sayi oldugunu
// gosterir.
if( min > dizi[i] )
min = dizi[i];
// max'in degeri, dizi elemanindan
// kucukse, max'in degerini degistiririz.
// Kendisinden daha buyuk sayi oldugunu
// gosterir.
if( max < dizi[i] )
max = dizi[i];
}
printf( "En Kk Deer: %d\n", min );
return 0;
int i, max;
max = dizi[0];
for( i = 1; i < eleman_sayisi; i++ ) {
if( max < dizi[ i ] )
max = dizi[ i ];
}
return max;
}
/* Dizi icindeki minimum degeri bulur */
float minimum_bul( float dizi[ ], int eleman_sayisi )
{
int i, min;
min = dizi[ 0 ];
for( i = 1; i < eleman_sayisi; i++ ) {
if( min > dizi[ i ] ) {
min = dizi[ i ];
}
}
return min;
}
/* Dizi elemanlarinin ortalamasini bulur */
float ortalama_bul( float dizi[ ], int eleman_sayisi )
{
int i, ortalama = 0;
for( i = 0; i < eleman_sayisi; i++ )
ortalama += dizi[ i ];
}
Fonksiyonlara dikkatlice bakn. Geen sefer sadece dizi adn gnderirken, artk dizi adyla birlikte
boyutunu da yolluyoruz. Bylece dizinin boyutu n'olursa olsun, fark etmiyor. Yeni bir parametre
ap dizinin eleman saysn isterseniz, fonksiyon her dizi iin alabilir.
Grdnz gibi dizi, 6066 numaral hafza adresini iaret ediyor. ptr isimli pointer ise, dizi
zerinden 6066 numaral adresi gsteriyor. Ksacas ikisi de ayn noktay iaret ediyorlar. imdi
bunu koda dkelim:
#include<stdio.h>
int main( void )
{
int i;
// dizi'yi tanimliyoruz.
int dizi[ 6 ] = { 4, 8, 15, 16, 23, 42 };
// ptr adinda bir pointer tanimliyoruz.
int *ptr;
// ptr'nin dizi'yi isaret etmesini soyluyoruz.
ptr = dizi;
// ptr'in degerini artirip, dizi'nin butun
// elemanlarini yazdiriyoruz.
for( i = 0; i < 6; i++ )
printf( "%d\n", *( ptr + i ) );
return 0;
}
Pointer'lar farkl ekillerde kullanlabilir. Her defasnda, dizinin balang elemann atamanz
gerekmez. rnein, ptr = &dizi[ 2 ] eklinde bir komut kullanarak, dizinin 3.elemannn adresini
pointer'a atayabilirsiniz. Pointer'larin deiik kullanm eitlerini aada grebilirsiniz:
#include<stdio.h>
int main( void )
int
int
int
ptr
elm
ptr
ptr
elm
elm
ptr
elm
elm
elm;
month[ 12 ];
*ptr;
= month; // month[0] adresini atar
= ptr[ 3 ]; // elm = month[ 3 ] deerini atar
= month + 3; // month[ 3 ] adresini atar
= &month[ 3 ]; // month[ 3 ] adresini atar
= ( ptr+2 )[ 2 ]; // elm = ptr[ 4 ] ( = month[ 7 ] )deeri atanr.
= *( month + 3 );
= month;
= *( ptr + 2 ); // elm = month[ 2 ] deerini atar
= *( month + 1 ); // elm = month[ 1 ] deerini atar
return 0;
Grdnz gibi fonksiyon iersinde diziyle ilgili yaptmz deiikler, dizinin aslna da
yansmtr. Srada, fonksiyondan dizi dndrmek var.
Aslnda fonksiyondan dizi pek doru bir isimlendirme deil. Gerekte dndrdmz ey, dizinin
kendisi deil, sadece balang adresi oluyor. Dolaysyla bir dizi dndrdmz sylemek
yerine, Pointer dndrdmz syleyebiliriz. Basit bir fonksiyon hazrlayalm; bu fonksiyon
kendisine gnderilen iki diziyi birletirip, tek bir dizi hline getirsin.
#include<stdio.h>
/* Kendisine verilen iki diziyi birlestirip
sonuclari ucuncu bir diziye atar */
int *dizileri_birlestir( int [], int,
int [], int,
int []);
int main( void )
{
// liste_1, 5 elemanli bir dizidir.
int liste_1[5] = { 6, 7, 8, 9, 10 };
// liste_2, 7 elemanli bir dizidir.
int liste_2[7] = {13, 7, 12, 9, 7, 1, 14 };
// sonuclarin toplanacagi toplam_sonuc dizisi
int toplam_sonuc[13];
// sonucun dondurulmesi icin pointer tanimliyoruz
int *ptr;
int i;
// fonksiyonu calistiriyoruz.
ptr = dizileri_birlestir( liste_1, 5, liste_2, 7,
toplam_sonuc );
// pointer uzerinden sonuclari yazdiriyoruz.
for( i = 0; i < 12; i++ )
printf("%d ", *(ptr+i) );
printf("\n");
return 0;
}
int *dizileri_birlestir( int dizi_1[], int boyut_1,
int dizi_2[], int boyut_2,
int sonuc[] )
{
int i, k;
// Birinci dizinin degerleri ataniyor.
for( i = 0; i < boyut_1; i++ )
sonuc[i] = dizi_1[i];
// Ikinci dizinin degerleri ataniyor.
for( k = 0; k < boyut_2; i++, k++ ) {
sonuc[i] = dizi_2[k];
}
// Geriye sonuc dizisi gonderiliyor.
return sonuc;
}
sorabilirsiniz. lerki konumuzda, dinamik yer ayrma konusunu ileyeceiz. imdilik ok lzumlu
gzkmese de, n hazrlk olarak olarak bunlar renmeniz nemli!
Sralama
Sralama olduka nemli bir konudur. eit eit algoritmalar ( QuickSort, Insertion, Shell Sort,
vs... ) bulunmaktadr. Ben sizlere en basit sralama yntemlerinden biri olan, "Bubble Sort"
("Kabarck Sralamas") metodundan bahsedeceim.
Elinizde, {7, 3, 66, 3, -5, 22, -77, 2} elemanlarndan oluan bir dizi olduunu varsayn. Dizinin en
sonuna gidiyorsunuz ve 8.elemanla ( dizi[ 7 ] ), 7.eleman ( dizi[ 6 ] ) karlatryorsunuz. Eer
8.eleman, 7.elemandan kkse bu ikisi yer deitiriyor; deilse, bir deiiklik yapmyorsunuz.
Sonra 7.elemanla ( dizi[ 6 ] ) 6.eleman iin ayn ilemler yaplyor. Bu byle dizinin son elemanna
( dizi[ 0 ] ) kadar gidiyor. Buraya kadar yaptmz ilemlere birinci aama diyelim. kinci aamada
da tamamen ayn ilemleri yapyorsunuz. Sadece sre dizinin son elemanna ( dizi[ 0 ] ) kadar
deil, ondan bir nceki elemana kadar sryor. Ksacas her aamada, kontrol ettiiniz eleman
saysn bir azaltyorsunuz. Aama says da, dizi eleman saysnn bir eksii oluyor. Yani bu
rneimizde 7 aama gerekiyor
Konu biraz karmak; tek seferde anlalmayabilir. Bu dediklerimizi algoritmaya dkelim:
#include<stdio.h>
void dizi_goster( int [ ], int );
void kabarcik_siralamasi( int [ ], int );
int main( void )
{
int i, j;
int dizi[ 8 ] = { 7, 3, 66, 3,
-5, 22, -77, 2 };
// Siralama islemi icin fonksiyonu
// cagriyoruz.
kabarcik_siralamasi( dizi, 8 );
// Sonucu gostermesi icin dizi_gosteri
// calistiriyoruz.
dizi_goster( dizi, 8 );
return 0;
}
// Dizi elemanlarini gostermek icin yazilmis
// bir fonksiyondur.
void dizi_goster( int dizi[ ], int boyut )
{
int i;
for( i = 0; i < boyut; i++ ) {
printf("%d ",dizi[i]);
}
printf("\n");
}
// Bubble Sort algoritmasina gore, siralama islemi
// yapar.
void kabarcik_siralamasi( int dizi[ ], int boyut )
{
int i, j, temp;
// Ilk dongu asama sayisini temsil ediyor.
// Bu donguye gore, ornegin boyutu 8 olan
// bir dizi icin 7 asama gerceklesir.
for( i = 0; i < boyut-1; i++ ) {
// Ikinci dongu, her asamada yapilan
// islemi temsil eder. Dizinin elemanlari
// en sondan baslayarak kontrol edilir.
// Eger kendisinden once gelen elemandan
rnek Sorular
Soru 1: Kendisine parametre olarak gelen bir diziyi, yine parametre olarak bir baka diziye ters
evirip atayacak bir fonksiyon yaznz.
Cevap 1:
#include<stdio.h>
void diziyi_ters_cevir( int[], int[], int );
int main( void )
{
int i;
int liste_1[] = { 6, 7, 8, 9, 10 };
int liste_2[5];
diziyi_ters_cevir( liste_1, liste_2, 5 );
for( i = 0; i < 5; i++ ) {
printf("%d ", liste_2[i]);
}
printf("\n");
}
void diziyi_ters_cevir( int dizi_1[], int dizi_2[], int boyut )
{
int i, k;
for( i = 0, k = boyut - 1; i < boyut; i++, k-- )
dizi_2[k] = dizi_1[i];
}
Soru 2: Kendisine parametre olarak gelen bir dizinin btn elemanlarn, mutlak deeriyle
deitiren program yaznz.
Cevap 2:
#include<stdio.h>
void dizi_mutlak_deger( int[], int );
int main( void )
{
int i;
int liste[] = { -16, 71, -18, -4, 10, 0 };
dizi_mutlak_deger( liste, 6 );
for( i = 0; i < 6; i++ ) {
printf("%d ", liste[i]);
}
printf("\n");
}
void dizi_mutlak_deger( int dizi[], int boyut )
{
int i;
for( i = 0; i < boyut; i++ ) {
if( dizi[i] < 0 )
dizi[i] *= -1;
}
}
Soru 3: int *ptr = &month[ 3 ] eklinde bir atama yaplyor. Buna gre, aadakilerden hangileri
*ptr deerine eittir?
a)
b)
c)
d)
month;
ptr[ 0 ];
ptr[ 1 ];
*( month + 3 )
e) ( month + 3 )[ 0 ];
f) ( month + 1 )[ 2 ];
g) *( month + 3 )[ 0 ];
Cevap3:
b, d, e ve f klar, *ptr'ye eittir.
ok Boyutlu Diziler
nceki derslerimizde dizileri grmtk. Ksaca zetleyecek olursak, belirlediimiz sayda
deikeni bir sra iinde tutmamz, diziler sayesinde gerekleiyordu. Bu dersimizde, ok boyutlu
dizileri inceleyip, ardndan dinamik bellek konularna gireceiz.
imdiye kadar grdmz diziler, tek boyutluydu. Btn elemanlar tek boyutlu bir yapda
saklyorduk. Ancak dizilerin tek boyutlu olmas gerekmez; istediiniz boyutta tanmlayabilirsiniz.
rnein 3x4 bir matris iin 2 boyutlu bir dizi kullanrz. Ya da boyutlu klid uzayndaki x, y, z
noktalarn saklamak iin 3 boyutlu bir diziyi tercih ederiz.
Hemen bir baka rnek verelim. 5 kiilik bir renci grubu iin 8 adet test uygulansn. Bunlarn
sonularn saklamak iin 2 boyutlu bir dizi kullanalm:
#include<stdio.h>
int main( void )
{
// 5 adet ogrenci icin 8 adet sinavi
// temsil etmesi icin bir ogrenci tablosu
// olusturuyoruz. Bunun icin 5x8 bir matris
// yaratilmasi gerekiyor.
int ogrenci_tablosu[ 5 ][ 8 ];
int i, j;
for( i = 0; i < 5; i++ ) {
for( j = 0; j < 8; j++ ) {
printf( "%d no.'lu ogrencinin ", ( i + 1 ) );
printf( "%d no.'lu snav> ", ( j + 1 ) );
// Tek boyutlu dizilerdeki gibi deger
// atiyoruz
scanf( "%d", &ogrenci_tablosu[ i ][ j ] );
}
}
return 0;
}
Bu program altrp, rencilere eitli deerler atadmz dnelim. Bunu grsel bir ekle
sokarsak, aadaki gibi bir izelge oluur:
Tabloya bakarsak, 1.renci snavlardan, 80, 76, 58, 90, 27, 60, 85 ve 95 puan alm gzkyor. Ya
da 5.rencinin, 6.snavndan 67 aldn anlyoruz. Benzer ekilde dier hcrelere gerekli deerler
atanp, ilgili rencinin snav notlar hafzada tutuluyor.
Diziyi tanmlarken, yukardaki gibi bir ilk deer atama yaparsanz, elemanlarn deeri aadaki gibi
olur:
Satr 0
16
52
Satr 1
15
27
Satr 2 : 14 25
2
10
ok boyutlu dizilerde ilk deer atama, tek boyutlu dizilerdekiyle ayndr. Girdiiniz deerler
srasyla hcrelere atanr. Bunun nedeni de basittir. Bilgisayar, ok boyutlu dizileri sizin gibi
dnmez; dizi elemanlarn hafzada arka arkaya gelen bellek hcreleri olarak deerlendirir.
ok boyutlu dizilerde ilk deer atama yapacaksanz, deerleri kmelendirmek iyi bir yntemdir;
karmakl nler. rnein yukarda yazm olduumuz ilk deer atama kodunu, aadaki gibi de
yazabiliriz:
int tablo[3][4] = { {8, 16, 9, 52}, {3, 15, 27, 6}, {14, 25, 2, 10} };
Farkedeceiniz gibi elemanlar drderli gruba ayrdk. Bilgisayar asndan bir ey deimemi
olsa da, kodu okuyacak kii asndan daha yararl oldu. Peki ya drt adet olmas gereken grubun
elemanlarn, adet yazsaydk ya da bir-iki grubu hi yazmasaydk n'olurdu? Deneyelim...
int tablo[3][4] = { {8, 16}, {3, 15, 27} };
Tek boyutlu dizilerde ilk deer atamas yaparken, eleman saysndan az deer girerseniz, kalan
deerler 0 olarak kabul edilir. Ayn ey ok boyutlu diziler iin de geerlidir; olmas gerektii sayda
eleman ya da grup girilmezse, bu deerlerin hepsi 0 olarak kabul edilir. Yani stte yazdmz kodun
yarataca sonu, yle olacaktr:
Satr 0
16
Satr 1
15
27
Satr 2 : 0
0
0
0
Belirtmediimiz btn elemanlar 0 deerini almtr. Satr 2'ninse btn elemanlar direkt 0
olmutur; nk grup tanm hi yaplmamtr.
Kod iersinde bulunan yorumlar, iki boyutlu dizilerin fonksiyonlara nasl aktarldn gstermeye
yetecektir. Yine de bir kez daha tekrar edelim... Fonksiyonu tanmlarken, ok boyutlu dizinin ilk
boyutunu yazmak zorunda deilsiniz. Bizim rneimizde int dizi[ ][ 4 ] eklinde belirtmemiz
bundan kaynaklanyor. ayet 7 x 6 x 4 boyutlarnda dizilerin kullanlaca bir fonksiyon yazsaydk
tanmlamamz int dizi[ ][ 6 ][ 4 ] olarak deitirmemiz gerekirdi. Ksacas fonksiyonu tanmlarken
dizi boyutlarna dair ilk deeri yazmamakta serbestsiniz; ancak dier boyutlarn yazlmas zorunlu!
Bunun yararn merak ederseniz, stun says 4 olan her trl matrisi bu fonksiyona
gnderebileceinizi hatrlatmak isterim. Yani fonksiyon her boyutta matrisi alabilir, tabii stun
Grld gibi elemanlarn hepsi srayla yerletirilmitir. Bir satrn bittii noktada ikinci satrn
elemanlar devreye girer. Kapsaml bir rnekle hafza yerleimini ele alalm:
#include<stdio.h>
void satir_goster( int satir[ ] );
int main( void )
{
int tablo[5][4] = {
{4, 3, 2, 1},
{1, 2, 3, 4},
{5, 6, 7, 8},
{2, 5, 7, 9},
{0, 5, 9, 0} };
int i, j;
// Dizinin baslangic adresini yazdiriyoruz
printf( "2 boyutlu tablo %p adresinden balar\n\n", tablo );
// Tablo icersinde bulunan dizi elemanlarinin adreslerini
// ve degerlerini yazdiriyoruz.
printf( "Tablo elemanlar ve hafza adresleri:\n");
for( i = 0; i < 5; i++ ) {
for( j = 0; j < 4; j++ ) {
printf( "%d (%p) ", tablo[i][j], &tablo[i][j] );
}
printf( "\n" );
}
// Cok boyutlu diziler birden fazla dizinin toplami olarak
rnekle ilgili en ok dikkat edilmesi gereken nokta, ok boyutlu dizilerin esasnda, tek boyutlu
dizilerden olumu bir btn olduudur. Tablo isimli 2 boyutlu dizimiz 5 adet satrdan oluur ve bu
satrlarn her biri kendi bana bir dizidir. Eer tablo[2] derseniz bu nc satr temsil eden bir
diziyi ifade eder. satir_goster( ) fonksiyonunu ele alalm. Esasnda fonksiyon iersinde satr diye
bir kavramn olmadn syleyebiliriz. Btn olan biten fonksiyona tek boyutlu bir dizi
gnderilmesidir ve fonksiyon bu dizinin elemanlarn yazar.
Dizi elemanlarnn hafzadaki ardk yerleimi bize baka imkanlar da sunar. ki boyutlu bir diziyi
bir hamlede, tek boyutlu bir diziye dntrmek bunlardan biridir.
#include<stdio.h>
int main( void )
{
int i;
int tablo[5][4] = {
{4,
{1,
{5,
{2,
{0,
3,
2,
6,
5,
5,
2,
3,
7,
7,
9,
1},
4},
8},
9},
0} };
return 0;
Daha nce sralama konusunu ilemitik. Ancak bunu iki boyutlu dizilerde nasl yapacamz
henz grmedik. Aslnda grmemize de gerek yok! ki boyutlu bir diziyi yukardaki gibi tek boyuta
indirin ve sonrasnda sralayn. ok boyutlu dizileri, tek boyuta indirmemizin ufak bir faydas...
Pointer Dizileri
ok boyutlu dizilerin tek boyutlu dizilerin bir bileimi olduundan bahsetmitik. imdi
anlatacamz konuda ok farkl deil. Dizilerin, adresi gstermeye yarayan Pointer'lardan pek
farkl olmadn zaten biliyorsunuz. imdi de pointer dizilerini greceiz. Yani adres gsteren
iareti saklayan dizileri...
#include<stdio.h>
int main( void )
{
int i, j;
// Dizi isimleri keyfi secilmistir.
// alfa, beta, gama gibi baska isimler de
// verebilirdik.
int Kanada[8];
int ABD[8];
int Meksika[8];
int Rusya[8];
int Japonya[8];
// Bir pointer dizisi tanimliyoruz.
int *tablo[5];
// Yukarda tanimlanan dizilerin adreslerini
// tablo'ya aktiriyoruz.
tablo[0] = Kanada;
tablo[1] = ABD;
tablo[2] = Meksika;
tablo[3] = Rusya;
tablo[4] = Japonya;
lke isimlerini verdiimiz 5 adet dizi tanmladk. Bu dizileri daha sonra tabloya srayla atadk.
Artk her diziyle tek tek uramak yerine tek bir diziden btn lkelere ulamak mmkn hle
gelmitir. ki boyutlu tablo isimli matrise atamasn yaptmz ey deer veya bir eleman deildir;
dizilerin balang adresleridir. Bu yzden tablo dizisi iersinde yapacamz herhangi bir deiiklik
orijinal diziyi de (rnein Meksika) deitirir.
Atama ilemini aadaki gibi tek seferde de yapabilirdik:
int *tablo[ ] = { Kanada, ABD, Meksika, Rusya, Japonya };
imdi de bir pointer dizisini fonksiyonlara nasl argman olarak gndereceimize bakalm.
#include<stdio.h>
void adresleri_goster( int *[ ] );
int main( void )
{
int Kanada[8];
int ABD[8];
int Meksika[8];
int Rusya[8];
int Japonya[8];
calloc( ) fonksiyonu eleman saysn, eleman boyutuyla arparak hafzada gereken bellek alann
ayrr. Dinamik oluturduunuz dizi iersindeki her elemana, otomatik olarak ilk deer 0 atanr.
malloc( ) fonksiyonu, calloc( ) gibi dinamik bellek ayrm iin kullanlr. calloc( ) fonksiyonundan
farkl olarak ilk deer atamas yapmaz. Kullanmysa aadaki gibidir:
isaretci_adi = malloc( eleman_sayisi * her_elemanin_boyutu );
Bu kadar konumadan sonra ii pratie dkelim ve dinamik bellekle ilgili ilk programmz yazalm:
#include<stdio.h>
#include<stdlib.h>
int main( void )
{
// Dinamik bir dizi yaratmak icin
// pointer kullaniriz.
int *dizi;
Yazdnz programlarn bir sre sonra bilgisayar belleini korkun bir ekilde igal etmesini
istemiyorsanz, free( ) fonksiyonunu kullanmanz gerekmektedir. Gelimi programlama dillerinde
( rnein, Java, C#, vb... ) kullanlmayan nesnelerin temizlenmesi otomatik olarak p toplayclarla
( Garbage Collector ) yaplmaktadr. Ne yazk ki C programlama dili iin bir p toplayc yoktur ve
iyi programcyla, kt programc burada kendisini belli eder.
Programnz bir kereliine altryorsanz ya da yazdnz program ok ufaksa, bo yere tketilen
bellek miktarn farketmeyebilirsiniz. Ancak byk boyutta ve kapsaml bir program sz konusuysa,
efektif bellek ynetiminin ne kadar nemli olduunu daha iyi anlarsnz. Gereksiz tketilen
bellekten kanmak gerekmektedir. Bunun iin fazla bir ey yapmanz gerekmez; calloc( )
fonksiyonuyla tahsis ettiiniz alan, iiniz bittikten sonra free( ) fonksiyonuyla boaltmanz
yeterlidir. Konu nemli olduu iin tekrar ediyorum; artk kullanmadnz bir dinamik dizi sz
konusuysa onu free( ) fonksiyonuyla kaldrlabilir hle getirmelisiniz!
Az evvel calloc( ) ile yazdmz programn aynsn imdi de malloc( ) fonksiyonunu kullanarak
yazalm:
#include<stdio.h>
#include<stdlib.h>
int main( void )
{
// Dinamik bir dizi yaratmak icin
// pointer kullaniriz.
int *dizi;
// Dizimizin kac elemanli olacagini
// eleman_sayisi isimli degiskende
// tutuyoruz.
int eleman_sayisi;
int i;
printf( "Eleman saysn giriniz> ");
scanf( "%d", &eleman_sayisi );
Hafza alan ayrrken bazen bir problem kabilir. rnein bellekte yeterli alan olmayabilir ya da
benzeri bir sknt olmutur. Bu tarz problemlerin sk olacan dnmeyin. Ancak hafzann
gerekten ayrlp ayrlmadn kontrol edip, iinizi garantiye almak isterseniz, aadaki yntemi
kullanabilirsiniz:
dizi = calloc( eleman_sayisi, sizeof( int ) );
// Eger hafiza dolmussa dizi pointer'i NULL'a
// esit olacak ve asagidaki hata mesaji cikacaktir.
if( dizi == NULL )
printf( "Yetersiz bellek!\n" );
Dinamik hafza kullanarak dizi yaratmay grdk. Ancak bu diziler tek boyutlu dizilerdi. Daha nce
pointer iaret eden pointer'lar grmtk. imdi onlar kullanarak dinamik ok boyutlu dizi
oluturacaz:
#include<stdio.h>
#include<stdlib.h>
int main( void )
{
int **matris;
int satir_sayisi, sutun_sayisi;
int i, j;
printf( "Satr says giriniz> " );
scanf( "%d", &satir_sayisi );
printf( "Stun says giriniz> " );
scanf( "%d", &sutun_sayisi );
// Once satir sayisina gore hafizada yer ayiriyoruz.
// Eger gerekli miktar yoksa, uyari veriliyor.
matris = (int **)malloc( satir_sayisi * sizeof(int) );
if( matris == NULL )
printf( "Yetersiz bellek!" );
// Daha sonra her satirda, sutun sayisi kadar hucrenin
// ayrilmasini sagliyoruz.
for( i = 0; i < satir_sayisi; i++ ) {
matris[i] = malloc( sutun_sayisi * sizeof(int) );
if( matris[i] == NULL )
printf( "Yetersiz bellek!" );
}
// Ornek olmasi acisindan matris degerleri
// gosteriliyor. Dizilerde yaptiginiz butun
// islemleri burada da yapabilirsiniz.
for( i = 0; i < satir_sayisi; i++ ) {
for( j = 0; j < sutun_sayisi; j++ )
printf( "%d ", matris[i][j] );
printf( "\n" );
Yukardaki rnek karmak gelebilir; tek seferde zemeyebilirsiniz. Ancak bir iki kez zerinden
geerseniz, temel yapnn aklnza yatacan dnyorum. Kodun koyu yazlm yerlerini
rendiiniz takdirde, sorun kalmayacaktr.
rnek Sorular
Soru 1: Kendisine gnderilen iki diziyi birletirip geriye tek bir dizi dndren fonksiyonu yaznz.
Cevap 1:
#include<stdio.h>
#include<stdlib.h>
/* Kendisine verilen iki diziyi birlestirip
sonuc dizisini geriye dondurur */
int *dizileri_birlestir( int [], int,
int [], int );
int main( void )
{
int i;
// liste_1, 5 elemanli bir dizidir.
int liste_1[5] = { 6, 7, 8, 9, 10 };
// liste_2, 7 elemanli bir dizidir.
int liste_2[7] = {13, 7, 12, 9, 7, 1, 14 };
// sonuclarin toplanacagi toplam_sonuc dizisi
// sonucun dondurulmesi icin pointer tanimliyoruz
int *ptr;
// fonksiyonu calistiriyoruz.
ptr = dizileri_birlestir( liste_1, 5, liste_2, 7 );
// ptr isimli pointer'i bir dizi olarak dusunebiliriz
for( i = 0; i < 12; i++ )
printf("%d ", ptr[i] );
printf("\n");
return 0;
}
int *dizileri_birlestir( int dizi_1[], int boyut_1,
int dizi_2[], int boyut_2 )
{
int *sonuc = calloc( boyut_1+boyut_2, sizeof(int) );
int i, k;
// Birinci dizinin degerleri ataniyor.
for( i = 0; i < boyut_1; i++ )
sonuc[i] = dizi_1[i];
// Ikinci dizinin degerleri ataniyor.
Soru 2: Sol aada bulunan 4x4 boyutundaki matrisi saat ynnde 90o dndrecek fonksiyonu
yaznz. ( Sol matris dndrld zaman sa matrise eit olmaldr. )
12
88
90
38
34
54
91
39
22
67
92
40
98
11
93
41
>>>
38
39
40
41
90
91
92
93
88
54
67
11
12
34
22
98
Cevap 2:
#include<stdio.h>
void elemanlari_goster( int [][4] );
void saat_yonunde_cevir( int [][4] );
int main( void )
{
int matris[4][4] = {
{12, 34, 22, 98},
{88, 54, 67, 11},
{90, 91, 92, 93},
{38, 39, 40, 41} };
elemanlari_goster( matris );
printf("\n");
saat_yonunde_cevir( matris );
}
void elemanlari_goster( int dizi[][4] )
{
int i, j;
for( i = 0; i < 4; i++ ) {
for( j = 0; j < 4; j++ )
printf( "%d ", dizi[i][j] );
printf( "\n" );
}
}
void saat_yonunde_cevir( int dizi[][4] )
{
int i, j;
for( i = 0; i < 4; i++ ) {
for( j = 0; j < 4 ; j++ )
printf( "%d ", dizi[3-j][i] );
printf( "\n" );
}
}
Katarlar ( String )
Dizileri ve ok boyutlu dizileri grdk. Katar dediimiz ey de aslnda bir dizidir. Deiken tipi
char yani karakter olan diziler, 'katar' ya da ngilizce adyla 'string' olarak isimlendirilirler.
Katarlar, imdiye kadar grdmz dizilerden ayran, onlar farkl klan zellikleri yoktur.
rnein bir tam say ( int ) dizisinde, tam saylar saklarken; bir karakter dizisinde -yani katardakarakterleri ( char ) saklarz. Bunun dnda bir fark bulunmaz. Ancak sk kullanlmalarna paralel
olarak, katarlara ayr bir nem vermek gerekir. Yaptnz ilemler bilimsel ve hesaplama arlkl
deilse, hangi dili kullanrsanz kullann, en ok ili dl olacanz dizi tipi, karakter dizileridir.
simler, adresler, kullanc adlar, telefonlar vs... szle ifade edilebilecek her ey iin karakter
dizilerini kullanrz. Katarlar ite bu yzden nemlidir!
Karakter dizilerine ngilizce'de String dendiini belirtmitik. String; ip, ba, kordon gibi anlamlar
tayor. lk olarak katar adn kim mnasip grd bilmiyorum. Muhtemelen bellek hcrelerine pei
sra dizilen karakterlerin, vagonlara benzetilmesiyle, String deiken tipi Trke'ye katar olarak
evrildi. ( Arapa kkenli Trke bir kelime olan katar, 'tren' anlamna gelmektedir. ) Daha uygun
bir isim verilebilirdi ya da sadece 'karakter dizisi' de diyebilirdik. Fakat madem genel kabul grm
bir terim var; yazmz iersinde biz de buna uyacaz. String, katar ya da karakter dizisi hi
farketmez; hepsi ayn kapya kyor: Deiken tipi karakter olan dizi...
rneimizde 30 karakterlik bir karakter dizisi tanmlayarak ie baladk. Bunun anlam girdileri
saklayacamz 'isim' katarnn 30 karakter boyutunda olacadr. Ancak bu katara en fazla 29
karakterlik bir kelime atanabilir. nk katarlarda, kelime bitiminden sonra en az bir hcre bo
braklmaldr. Bu hcre 'Bo Karakter' ( NULL Character ) tutmak iindir. Bo karakter "\0"
eklinde ifade edilir. C programlama dilinde, kelimelerin bittiini bo karakterlerle anlarz.
Herhangi bir katar bo karakterle sonlandrmaya, 'null-terminated' denmektedir.
Bu arada katarlara deer atarken ya da katarlardan deer okurken, sadece katar adn yazmamzn
yettiini farketmisinizdir. Yani scanf( ) fonksiyonu iersine & iareti koymamz gerekmiyor.
nk scanf( ), katarn ilk adresinden balayarak aaya doru harfleri tek tek atamas gerektiini
biliyor. ( Aslnda biliyor demek yerine, fonksiyonun o ekilde yazldn sylememiz daha doru
olur. )
Katarlarn, esasnda bir dizi olduundan bahsetmitik. imdi bunun uygulamasn yapalm. Katara
deer atamak iin yine ayn kodu kullanrken; katardan deer okumak iin kodumuzu biraz
deitirelim:
#include<stdio.h>
int main( void )
{
char isim[30];
int i;
printf( "sim giriniz> ");
scanf( "%s", isim );
Daha nce tek bir printf( ) fonksiyonuyla btn katar yazdrabilirken, bu sefer katar elemanlarn
tek tek, karakter karakter yazdrmay tercih ettik. kan sonu ayn olacaktr fakat gidi yolu biraz
farkllat. zellikle for dngs iersinde bulunan " isim[i]!='\0' " kouluna dikkat etmek
gerekiyor. steseydik, " i < 30 " yazar ve katarn btn hcrelerini birer birer yazdrabilirdik. Fakat
bu mantkl deil! 30 karakterlik bir dizi olsa bile, kullanc 10 harften oluan bir isim girebilir.
Dolaysyla kalan 20 karakteri yazdrmaya gerek yoktur. Kelimenin nerede sonlandn belirlemek
iin "isim[i]!='\0'" koulunu kullanyoruz. Bunun anlam; isim katarnn elemanlar, "\0" yani bo
karakterere ( NULL Character ) eit olmad srece yazdrmaya devam edilmesidir. Ne zaman ki
kelime biter, sradaki elemann deeri "\0" olur; ite o vakit dngy sonlandrmamz gerektiini
biliriz.
Yukardaki rneimize birden ok kelime girdiyseniz, sadece ilk kelimenin alndn
farketmisinizidir. Yani "Bugn hava ok gzel." eklinde bir cmle girdiiniz zaman, katara sadece
"Bugn" kelimesi atanr. Eer ayn anda birden fazla kelime almak istiyorsanz, ayr ayr
belirtilmesi gerekir.
#include<stdio.h>
int main( void )
{
char isim[25],
printf( "Ad ve
scanf( "%s%s",
printf( "Sayn
return 0;
}
soyad[30];
soyad giriniz> ");
isim, soyad );
%s %s, ho geldiniz!\n", isim, soyad );
gets( ) isminden anlayacanz ( get string ) gibi katara deer atamak iin kullanlr. puts( ) ( put
string ) ise, bir katarn ieriini ekrana yazdrmaya yarar. gets( ) atayaca deerin ayrmn
yapabilmek iin '\n' aramaktadr. Yani klavyeden Enter'a baslana kadar girilen her eyi, tek bir
katara atayacaktr. puts( ) fonksiyonuysa, printf( ) ile benzer alr. Bo karakter ( NULL
Character ) yani '\0' ulaana kadar katar yazdrr; printf( ) fonksiyonundan farkl olarak sonuna '\n'
koyarak bir alt satra geer. Olduka ak ve basit kullanmlara sahip olduklarndan, kendiniz de
baka rnekler deneyebilirsiniz.
return 0;
kinci yntemdeyse, kelime btn olarak yazlmaz. Bunun yerine harf harf yazlr ve sonlandrmak
iin en sonuna bo karakter ( NULL ) eklenir:
#include<stdio.h>
int main( void )
{
char isim[] = { 'C', 'A', 'G', 'A',
'T', 'A', 'Y', '\0' };
char soyad[5] = { 'C', 'E', 'B', 'I', '\0' };
printf( "%s %s\n", isim, soyad );
return 0;
}
Ben ilk deer atamas yapacam durumlarda, ilk yolu tercih ediyorum. kinci yntem, daha uzun
ve zahmeti...
return 0;
#include<string.h>
int main( void )
{
printf( "Katar Uzunluu: %d\n", strlen("Merhaba") );
return 0;
}
return 0;
strncpy( ) fonksiyonu, yine kopyalamak iindir. Fakat emsalinden farkl olarak, ka karakterin
kopyalanaca belirtilir. Protopi aada verilmitir:
char *strncpy( char[ ], char[ ], int );
return 0;
Yukardaki program altrrsanz, kopya isimli katara sadece 9 karakterin aktarldn ve ekrana
yazdrlan yaznn "Merhaba D" olduunu grebilirsiniz.
* strcmp( ) ve strncmp( ) ile katar karlatrma
strcmp( ) fonksiyonu, kendisine verilen iki katar birbiriyle karlatrr. Katarlar birbirine eitse,
geriye 0 dner. Eer ilk katar alfabetik olarak ikinciden bykse, geriye pozitif deer dndrr.
ayet alfabetik srada ikinci katar birinciden bykse, geriye negatif deer dnmektedir. Bu
dediklerimizi, daha iyi anlalmas iin bir tabloya dntrelim:
Dnen Deer
Aklama
<0
Katar1, Katar2'den kktr.
0
>0
strncmp( ) iin de ayn kurallar geerlidir. Tek fark, karlatrlacak karakter saysn girmemizdir.
strcmp( ) fonksiyonunda iki katar, null karakter iareti kana kadar karlatrlr. Fakat strncmp( )
fonksiyonunda, balangtan itibaren ka karakterin karlatrlacana siz karar verirsiniz.
Her iki fonksiyonu da kapsayan aadaki rnei inceleyelim:
#include<stdio.h>
#include<string.h>
int main( void )
{
int sonuc;
char ilk_katar[40]="Maymun";
char ikinci_katar[40]="Maytap";
sonuc = strcmp( ilk_katar, ikinci_katar );
printf( "%d\n", sonuc );
sonuc = strncmp( ilk_katar, ikinci_katar, 3 );
printf( "%d\n", sonuc );
}
return 0;
lk nce arlan strcmp( ), null karakterini grene kadar btn karakterleri karlatracak ve
geriye negatif bir deer dndrecektir. nk "Maymum" kelimesi alfabede "Maytap" kelimesinden
nce gelir; dolaysyla kktr. Fakat ikinci olarak ardmz strncmp( ) geriye 0 deeri
verecektir. Her iki katarn ilk harfi ayndr ve fonksiyonda sadece ilk harfin karlatrlmasn
istediimizi belirttik. Dolaysyla karlatrmann sonucunda 0 dndrlmesi normaldir.
* strcat( ) ve strncat( ) ile katar birletirme
strcat( ) ve strncat( ) fonksiyonlar, bir katar bir baka katarla birletirmeye yarar. Fonksiyon
adlarnda bulunan cat, ngilizce bir kelime olan ve birletirme anlamna gelen 'concatenate'den
gelmitir. strcat( ) kendisine verilen katarlar tamamen birletirirken, strncat( ) belirli bir eleman
saysna kadar birletirir. strcat ile ilgili basit bir rnek yapalm.
#include<stdio.h>
#include<string.h>
int main( void )
{
char ad[30], soyad[20];
char isim_soyad[50];
printf( "Ad ve soyadnz giriniz> " );
scanf( "%s%s", ad, soyad );
// isim_soyad <-- ad
strcat( isim_soyad, ad );
// isim_soyad <-- ad + " "
strcat( isim_soyad, " " );
// isim_soyad <-- ad + " " + soyad
strcat( isim_soyad, soyad );
printf( "Tam sim: %s\n", isim_soyad );
return 0;
}
balangcna yazmalsnz.
#include<stdio.h>
#include<stdlib.h>
int main( void )
{
char kok_iki[] = "1.414213";
char pi[] = "3.14";
char tam_bir_sayi[] = "156";
char hayatin_anlami[] = "42 is the answer";
printf( "%d\n",
printf( "%d\n",
printf( "%f\n",
printf( "%f\n",
return 0;
atoi(
atoi(
atof(
atof(
tam_bir_sayi ) );
hayatin_anlami ) );
kok_iki ) );
pi ) );
Her iki fonksiyonda rakam harici bir ey grene kadar alr. Eer nmerik ifadeler dnda bir
karakter karsa, fonksiyon o noktada almay keser.
Bu kodu yazp, "yeni_komut.c" adyla kaydedin. Ardndan eer Linux ve gcc kullanyrsanz,
aadaki komutu kullanarak kodun derlemesini yapn.
$ gcc yeni_komut.c -o yeni_komut
Yukardaki komut, "yeni_komut" adnda altrlabilir bir program dosyas oluturacak. Windows ve
Dev-C++ kullanyorsanz byle bir komuta gerek yok. Kodu kaydedip, derlediiniz zaman, alma
klasrnzde "yeni_komut.exe" adnda bir dosya zaten oluacaktr.
kinci aamada, programa parametre gndererek altracaz. Bunun iin gerek Linux gerekse
Windows kullanclarnn yapaca ey birbirine ok benziyor. Linux kullanclar aadaki gibi bir
komut girecekler:
$ ./yeni_komut Merhaba Dnya Hello World
Windows kullanclarnnsa, DOS komut istemini ap, programn kaytl olduu klasre gelmeleri
gerekiyor. Diyelim ki, "yeni_komut.exe" "C:\Belgelerim" iinde kaytl... O hlde aadaki komutu
giriyoruz:
C:\Belgelerim> yeni_komut Merhaba Dnya Hello World
argman:
argman:
argman:
argman:
argman:
./yeni_komut
Merhaba
Dnya
Hello
World
Dardan gelen argmanla alan bir baka main( ) fonksiyonu oluturalm. Toplama ve kartma
ilemini alaca argmanlara gre yapan bir program aada bulabilirsiniz:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main( int argc, char *arg[] )
{
// Eger eksik arguman soz konusuysa,
// program calismamalidir.
if( argc < 4 ) {
printf( "Hata: Eksik argman!\n");
return;
}
float sayi_1, sayi_2;
char islem_tipi[2];
sayi_1 = atof( arg[1] );
strcpy( islem_tipi, arg[2] );
sayi_2 = atof( arg[3] );
// Verilen sembolun neye esit oldugu asagidaki
// if-else if merdiveniyle saptaniyor.
if( !strcmp( islem_tipi, "+" ) )
printf( "Toplam: %.2f\n", sayi_1 + sayi_2 );
else if( !strcmp( islem_tipi, "-" ) )
printf( "Fark: %.2f\n", sayi_1 - sayi_2 );
else
printf( "Hatal ilem!\n" );
return 0;
Program bu ekilde altrdnz zaman argmanlarn, parametrelere atanmas aadaki gibi olur:
arg[ 0 ]
./hesapla
arg[ 1 ] arg[ 2 ]
4
+
arg[ 3 ]
12
rnek Sorular
Soru 1: Kendisine verilen bir katarn boyutunu bulan fonksiyonu yaznz. ( zm iin strlen( )
fonksiyonunu kullanmaynz. )
Cevap 1:
#include<stdio.h>
#include<string.h>
int katar_boyutu_bul( char [] );
int main( void )
{
char test_katari[50];
strcpy( test_katari, "ABCDEF" );
printf( "Katar boyutu: %d\n", katar_boyutu_bul( test_katari ) );
return 0;
}
int katar_boyutu_bul( char katar[] )
{
int i;
for( i = 0; katar[ i ]!='\0'; i++ );
return i;
}
Soru 2: Tersinden de ayn ekilde okunabilen kelime, cmle veya msraya 'palindrome'
denmektedir. Ad palindrome( ) olan ve verilen katarn tersinin kendisine eit olduu durumda
geriye 1; aksi hlde 0 dndren fonksiyonu yaznz.
Cevap 2:
#include<stdio.h>
#include<string.h>
int palindrome( char [] );
int main( void )
{
char test_katari[50];
strcpy( test_katari, "ABBA" );
printf( "%d\n", palindrome( test_katari ) );
return 0;
}
int palindrome( char katar[] )
{
int boyut =0 , i;
// Once katar boyutu bulunuyor
for( boyut = 0; katar[ boyut ]!='\0'; boyut++ );
for( i = 0; i < boyut/2; i++ ) {
if( katar[i] != katar[ boyut - i - 1 ] )
return 0;
}
return 1;
}
Cevap 3:
#include<stdio.h>
#include<string.h>
void ters_cevir( char [] );
int main( int argc, int arg[] )
{
int i;
for( i = 1; i < argc; i++ ) {
ters_cevir( arg[i] );
}
printf("\n");
return 0;
}
void ters_cevir( char katar[] )
{
int i, boyut;
for( boyut = 0; katar[ boyut ]!='\0'; boyut++ );
Daha nce boolean diye bir veri tipi bulunmuyordu. imdiyse, iki farkl deeri olabilen, doru ve
yanllar gstermekte kullanabileceimiz yeni bir deiken tipi oluturduk. Yanl gstermek iin
0; doruyu ifade etmek iinse 1 rakamlar kullandk. Yanln ve dorunun karln belirtmemiz
gerekmiyordu; boolean veri tipini tanmlarken, 0 ve 1 yazmadan sadece false ya da true da
yazabilirdik. Programnz derlenirken, karlk girilmeyen deerlere srayla deer atanmaktadr. lla
ki sizin bir eitlik oluturmanz gerekmez. Mesela ana rengi ( Krmz, Sar ve Mavi )alabilecek
ana_renkler veri tipini oluturalm:
#include<stdio.h>
int main( void )
{
// Degisken tipinin nasil olacagini tanimliyoruz
enum ana_renkler {
Kirmizi,
Mavi,
Sari
};
// Degiskeni tanimliyoruz.
enum ana_renkler piksel;
// Degisken degerini Mavi olarak belirliyoruz.
// Dilersek Sari ve Kirmizi da girebiliriz.
piksel = Mavi;
Kirmizi, Mavi ya da Sari'nin nmerik deerini bilmiyoruz; muhtemelen birden balam ve srayla
e kadar devam etmilerdir. Deerlerin nmerik karln bilmesek bile, bu onlarla ilem
yapmamz engellemiyor. Bir nceki rnekte olduu gibi rahata kullanabiliyoruz.
Oluturduumuz yeni veri tiplerinden, deiken tanmlarken her defasnda enum koyduumuzu
grmsnzdr. Bunu defalarca yazmak yerine iki alternatif biim bulunuyor. Birincisi yeni veri
tipini olutururken, deikeni tanmlamak eklinde... boolean rneimize geri dnp, farkl ekilde
nasl tanmlama yapabileceimizi grelim:
#include<stdio.h>
int main( void )
{
// Yeni veri tipini olusturuyoruz
// Ayrica yeni veri tipinden,
// bir degisken tanimliyoruz.
enum boolean {
false = 0,
true = 1
} dogru_mu;
dogru_mu = true;
if( dogru_mu == true )
printf( "Doru\n" );
return 0;
}
Yukarda grdnz yntem, yeni veri tipini oluturduunuz anda, bu veri tipinden bir deiken
tanmlamanz salar. Her seferinde enum yazmanzdan kurtaracak dier yntemse, typedef
kullanmaktan geer. typedef kullanm u ekildedir:
typedef veri_tipi_eski_adi veri_tipi_yeni_adi
Kullanacanz typedef ile herhangi bir deiken tipini, bir baka isimle adlandrabilirsiniz. rnein
yazacanz "typedef int tam_sayi;" komutuyla, deiken tanmlarken int yerine tam_sayi da
yazabilirsiniz. Bunun enum iin uygulamasna bakalm:
#include<stdio.h>
int main( void )
{
// Yeni veri tipini olusturuyoruz
// Ayrica yeni veri tipinden,
// bir degisken tanimliyoruz.
enum boolean {
false = 0,
true = 1
};
// Alttaki komut sayesinde, boolean
// veri tipini tek adimda yaratabiliyoruz.
typedef enum boolean bool;
bool dogru_mu;
dogru_mu = true;
if( dogru_mu == true )
printf( "Doru\n" );
return 0;
}
case
case
case
case
case
case
case
case
case
Grdnz gibi enum ile oluturacanz zel veri tiplerini fonksiyonlara aktarmak mmkn.
enum aracl ile yeni bir deiken tipi yaratmak, birok konuda iinizi basit hle getirir. zellikle
gruplandrlmas/tasnif edilmesi gereken veriler varsa, enum kullanmak yararldr. rnek olmas
asndan aada enum ile tanmlanm baz veri tiplerini bulabilirsiniz:
enum medeni_durum { bekar, evli, dul };
enum medeni_durum ayse = bekar;
enum egitim_durumu { ilkokul, ortaokul, lise, universite, master };
enum egitim_durumu ogrenci;
enum cinsiyet { erkek, kadin };
enum cinsiyet kisi;
Yaplar ( Structures )
Yaplar ( structures ); tam say, karakter vb. veri tiplerini gruplayp, tek bir at altnda toplar. Bu
gruplandrma iinde ayn ya da farkl veri tipinden dilediiniz sayda eleman olabilir. Yaplar, nesne
tabanl programlama ( Object Oriented Programming ) dilleri iin nemli bir konudur. Eer Java,
C# gibi modern dillerle almay dnyorsanz, bu konuya daha bir nem vermeniz gerekir.
Vakit kaybetmeden bir rnekle konumuza girelim. Doum gn bilgisi isteyip, bunu ekrana
yazdran bir program oluturalm:
#include<stdio.h>
int main( void )
{
struct {
int yil;
int ay;
int gun;
} dogum_gunu;
printf( "Doum gnnz " );
printf( "GG-AA-YYYY olarak giriniz> ");
scanf( "%d-%d-%d",
&dogum_gunu.gun,
&dogum_gunu.ay,
&dogum_gunu.yil );
printf( "Doum gnnz: " );
printf( "%d/%d/%d\n",
dogum_gunu.gun,
dogum_gunu.ay,
dogum_gunu.yil );
return 0;
}
Bir kullancnn doum gnn sorup, gn, ay ve yl bilgilerini farkl int deiken iersinde
tutabilirdik. Ancak gruplandrmak her zaman daha iyidir. Hem yaptnz ilerin takibi kolaylar,
hem de hata yapma riskinizi azaltr. Bunu daha iyi anlatmak iin ayn anda sizin ve iki kardeinizin
e Yaplar
Bir yap iersine tpk bir deiken koyar gibi, bir baka yap da koyulabilir. rnein kullanc
bilgisi alan bir programda, isim, boy ve doum tarihi bilgilerini ayn yap altna toplayabilirsiniz.
Ancak doum tarihi bilgilerini daha alt bir yap iersinde tutmak yararl olabilir. Bunu koda
dkersek yle olur:
#include<stdio.h>
int main( void )
{
struct {
char isim[40];
int boy;
struct {
int yil;
int ay;
int gun;
} dogum_bilgileri;
} kisi;
printf( "Adnz: " );
scanf( "%s", kisi.isim );
printf( "Boyunuz: " );
scanf( "%d", &kisi.boy );
"Girilen bilgiler:\n" );
"sim: %s\n", kisi.isim );
"Boy: %d\n", kisi.boy );
"Doum tarihi: %d/%d/%d\n",
return 0;
kisi.dogum_bilgileri.gun,
kisi.dogum_bilgileri.ay,
kisi.dogum_bilgileri.yil );
Alt yapya ulamak iin nokta kullanp, ardndan yapnn adn yazdmz gryorsunuz. Yaplar
kullanarak, bir arada durmas yararl olan deikenleri gruplarz. ie yaplar kullanaraksa, bu
gruplandrmay daha da ufak boyutlara indirgemekteyiz. Ksacas her ey, daha derli toplu alma
iin yaplyor. Yoksa programn temelinde deien bir ey yok.
Yap Etiketleri
Yaplara etiket koyabilir ve etiketleri kullanarak ilgili yapy temel alan deikenler
tanmlayabilirsiniz. Az evvel yaptmza benzer bir rnek yapalm:
#include<stdio.h>
#include<string.h>
int main( void )
{
// sahis_bilgileri, yapimizin
// etiketidir.
struct sahis_bilgileri {
char isim[40];
int boy;
};
// Yapidan iki adet degisken
// tanimliyoruz.
struct sahis_bilgileri kisi_1;
struct sahis_bilgileri kisi_2;
// Birinci sahsin bilgilerini
// kaydediyoruz.
strcpy( kisi_1.isim, "AHMET" );
kisi_1.boy = 170;
// Ikinci sahsin bilgilerini
// kaydediyoruz.
strcpy( kisi_2.isim, "MEHMET" );
kisi_2.boy = 176;
}
return 0;
Yaplarn etiket konarak tanmlanmas, daha mantkldr. Aksi hlde sadece yapy olutururken
tanmlama yaparsnz. Etiket koyduunuz zamansa, programn herhangi bir yerinde istediiniz
kadar yap deikeni tanmlayabilirsiniz. nemli bir noktay belirtmek isterim: yaplarda etiket
kullandnz zaman elinizde sadece bir ablon vardr. O etiketi kullanarak yapdan bir deiken
yaratana kadar, zerinde ilem yapabileceiniz bir ey olmaz. Yap ( structure ) bir kalptr; bu
kalbn etiketini kullanarak deiken tanmlamanz gerekir.
Bir yap deikenine, ilk deer atamas yapyorsanz sra nemlidir. Atayacanz deerlerin sras,
ilgili deikenlere gre olmaldr. Yani ilk yazacanz deer, ilk yap ii deikene; ikinci
yazacanz deer, ikinci yap ii deikene atanr. Sray armadnz srece bir problem
yaamazsnz. Aksi durumda, yanl deer yanl deikene atanacaktr. Sray armak iin, ekstra
ayra iaretleri kullanabilirsiniz. rnein { "Mehmet", 160, 23, 3, 1980 } yerine { "Mehmet", 160,
{23, 3, 1980} } yazmakta mmkndr.
Yap Dizileri
Veri tiplerine ait dizileri nasl oluturacamz biliyoruz. Bir tam say dizisi, bir karakter dizisi
rahatlkla oluturabiliriz. Benzer ekilde yap ( structure ) dizileri de tanmlanabilir. 3 kiilik bir
personel listesi tutacamz dnp, ona gre bir program oluturalm. Her eleman iin ayr ayr
deiken tanmlamaya gerek yoktur; yaplardan oluan bir dizi yaratabiliriz.
#include<stdio.h>
int main( void )
{
int i;
// Dogum tarihi tutmak icin
Tek bir yap deikeniyle, bir yap dizisi arasnda byk fark bulunmuyor. Sadece keli
parantezlerle eleman indisini belirtmek yetiyor. Yoksa, deer okuma, deer yazma... bunlarn hepsi
tpatp ayn. Bu yzden ayrca detaya inmiyorum.
return 0;
Yaplar ve Fonksiyonlar
enum ile yarattmz deiken tiplerini, fonksiyonlarda kullanmak iin global olarak tanmlyorduk.
Yaplar, fonksiyonlarda kullanlmak iin izlenecek yntem ayndr; yine global tanmlanmas
gerekir. ok basit bir rnekle yaplarn fonksiyonlarla kullanmn grelim:
#include<stdio.h>
#include<string.h>
struct sahis_bilgileri {
char isim[40];
int boy;
};
struct sahis_bilgileri bilgileri_al( void );
void bilgileri_goster( struct sahis_bilgileri );
int main( void )
return 0;
}
struct sahis_bilgileri bilgileri_al( void )
{
struct sahis_bilgileri sahis;
printf( "sim> " );
gets( sahis.isim );
printf( "Boy> " );
scanf( "%d", &sahis.boy );
return sahis;
}
void bilgileri_goster( struct sahis_bilgileri sahis )
{
printf( "Ad: %s\n", sahis.isim );
printf( "Boy: %d\n", sahis.boy );
}
Dinamik Yaplar
Dinamik bellek tahsis etmenin ne olduunu, niin bunu kullandmz aklamaya gerek
duymuyorum. Daha nceki derslerimizde bu konuya yer vermitik. ok basit bir rnekle dinamik
yaplarn kullanm gstermek yeterli olacaktr:
struct sahis_bilgileri *ptr;
ptr = calloc( 1, sizeof( struct sahis_bilgileri ) );
free( ptr );
admda, yaplar dinamik kullanmay gryorsunuz. En bata ptr adnda bir pointer
tanmlyoruz. kinci aamada, bellek ayrm yaplyor. Bu rnekte, sadece tek deikenlik yer
ayrlyor. ptr ile iimiz bittikten sonra, free( ) fonksiyonuyla, bellei boaltyoruz. Sadece temel
admla, yaplarda dinamik bellek kullanmn salayabilirsiniz. Yalnz calloc( ) ( ya da malloc( ) )
fonksiyonunun stdlib.h altnda olduunu unutmayn. ( Bu yzden kodun bana #include<stdlib.h>
yazmak gerekmektedir. )
Noktalarken...
C programlama diline dair anlatmlarmz burada bitiyor. Bu demek deildir ki; C zerine her eyi
anlattk; aksine daha birok konu bulunuyor. ( rnein dosya ilemleri, union kullanm vb...
konulara hi deinilmedi. ) Ancak imdiye kadar rendikleriniz, bundan sonrasn renebilmeniz
iin size temel tekil edecektir. Programlama dili renmek, yabanc dil renmekle hemen hemen
ayndr. ngilizce zerine dersler aldnzda, kimse Shakespeare olacanz syleyemez. Ama ok
alp kendinizi gelitirmek size baldr. Programlama dilleri de aynen byle... Burada ya da bir
baka kaynakta anlatlanlarla iin duayeni olamazsnz; fakat ii anlar duruma gelirsiniz. Bundan
sonras sizin elinizdedir... Ltfen bol bol pratik yapp, olabildiince ok algoritma kurun. Sizlere
temel programlama gramerini vermeye altm; umarm sonunda hepiniz birer "Macbeth"
yazarsnz!