You are on page 1of 110

Derleme: TD Software -Yazar: aatay EB

C Programlama Dersleri
Bu yazda renecekleriniz:

Bilgisayar ve Programlama nedir?


Program yazmak iin gerekli aralar ve temin edebileceiniz adresler
Algoritma gelitirme ve bunun zerine basit bir rnek
printf fonksiyonunun kullanm ve bununla ilgili rnekler

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.

Bilgisayar ve Programlama nedir?


Bilgisayar ok basit dndmzde ana grevi yerine getiren bir makinedir. Girilen bilgiyi alr
(INPUT), iler (PROCESSING) ve bu ilenmi veriden bir sonu (OUTPUT) karr. Bilgisayar,
sadece donanm olarak almaz. nk yazlm olmadan, donanm ne yapacan bilemez.
Bilgisayar donanmna ne yapacan syleyecek bir komutlar dizisi gerekir. Yapaca grevleri, ona
anlatan komutlara program diyebiliriz. Yani donanma sen unu yap, sonra bulduun sonucu yle
uraya ekle gibisinden iler yaptrmak programn veya bir baka deyile yazlmn iidir. Bir
programc olarak bundan fazlasn bilmek elbette ki avantajdr. Ama bilgisayarn btn zelliklerini
bilmeniz gerekmez. Yani yazacanz bir program iin o bilgisayarn zelliklerini bilmeseniz de
olur.
Bilgisayarn anlad tek dil, Makine Dilidir. Bu 16lk (Hexadecimal) sistemden oluan bir
programlama tipidir. Makine dilini anlamak ok zordur ve bu dili kullanmak iin o bilgisayarn
donanm zelliklerini mutlaka bilmeniz gerekir. C de ekrana yaz yazmanz salayan printf();
gibi ok basit bir fonksiyon, makine dilinde 1A BB 0D BC D5 FF C2 F7... gibi ok daha karmak
ve hibir anlam ifade etmeyen bir hle dnr. Makine dili programlama dilleri arasnda en alt
seviyedir.

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.

SEGMENT COM WORD PUBLIC CODE


ASSUME CS : COMDS : COM
ORG 100H
ENTRY: MOV DVX,OFFSET MSG
MOV AH,g
.
.
.

uan bunu anlamaya alp, hi zamannz harcamayn. nk reneceimiz dil C, ilerimizi ve


dolaysyla hayatmz ok daha kolaylatrmaktadr. C, orta seviye bir programlama dilidir. Bunun
anlam, hem yazmas kolay, hemde st seviye dillere gre daha ok eriim hakknzn olduudur.
st seviye programlama dilleri ise BASIC, PASCAL, gibi dillerdir. st seviye dillerde, yazmas
greceli olarak daha kolay olsa da C ile yapabileceklerimiz daha oktur.
Program yazmak iin ne gerekir?
Program yazabilmek iin hibir eye ihtiyacnz yoktur. Program yazmak iin Windowsun not
defterini veya Linux'da Gedit, Kwrite gibi bir program bile kullanabilirsiniz. nemli olan yazlan
programn derlenmesidir. Derlemeye compile ve derleme iini yapan derleyiciyeyse compiler
denir. C iin internet zerinden birok Compiler bulabilirsiniz. Ben, program uygulamalarn GCC
zerinden yapacam. Ayn ekilde bu derleyiciyi kurmanz tavsiye ederim. GCC gelmi gemi en
iyi derleyicilerden biri olduu gibi, zgr bir yazlmdr! Richard Stallman tarafndan ak kaynak
koduyla sunulmutur ve arzu ettiiniz takdirde, sonuna kadar deiiklik yapma imkannz vardr.
ayet Windows iletim sisteminiz varsa GCC'yi kurmanz biraz skntl olabilir. Basit bir Google
aratrmasyla, Bloodshed Dev-C++ adnda bir program buldum. GCC zerine kurulmu bir yaps
varm. GCC ile uramak istemeyen Windows kullanclar, bu program deneyebilir.
Algoritma Gelitirmek
C dilini ve komutlarn renmek, programlamaya balamak iin arttr ama algoritma
oluturamadmz srece bir program oluturmazsnz. Algoritma, mantktr. Yani neyi, nasl
yapacanz belirtir. Algoritma tretmek iin gelitirilmi bir metot yok. Her program iin o metodu
sizin bulmanz gerekiyor. Ama hi merak etmeyin, yazdnz program says arttka, algoritma
kurmanz daha kolaylar.
Algoritma, programlamann bel kemiidir. C dilinde kullanlan komutlar, BASIC veya FORTRAN
gibi baka dillerde ie yaramaz. Fakat programlama mantn bir kere oturttursanz, C komutlarnn
yerine pekl baka dillere ait komutlar da renebilir ve byk bir zorluk ekmeden dier dillerde
de program yazabilirsiniz.
Basit bir rnek zerinden dnelim. Bir markete gittiniz, kasada ki grevliye aldnz rn
gsterdiniz, paray uzattnz, parann stn aldnz. Gnlk hayatta gayet normal olan bu durumu
biraz deitirelim. Karnzda insan deil, elektronik bir kasiyer olsun. Ona gre bir algoritma
gelitirirsek,
1-)rne bak;
2-)rn Fiyatn bul;
3-)Paray al;
4-)Alnan paradan rn fiyatn kar;
5-)Kalan paray ver.
nsan zekasnn otomatik hle getirdii eylemleri, ne yazk ki bilgisayar bilmez ve ona biz retmek
zorundayz. retirken de hata yapma hakkmz yoktur, nk yanl reti yanl programlamayla
sonulanr.

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;
}

Grdnz gibi tek bir printf(); kullanarak ayn ilemi yaptrdk.


Varsayalm, ekrana ok uzun bir cmle yazmamz gerekti. rnein;
#include<stdio.h>
int main( void )
{
printf("Benim adm aatay EB ve Yazlm Mhendisiyim.\n");
return 0;
}

Bu yazdmz program hata vermemesine karn, alma verimini azaltr. nk yazacaklarnz


editr penceresine smazsa, yazlan okumak daha zahmetli olur. nemsiz bir detay gibi gelebilir,
ama kod yazma verimini ciddi oranda dreceinden emin olabilirsiniz.
Bu program aadaki gibi yazmamz daha uygundur:
#include<stdio.h>
int main( void )
{
printf("Benim adm "
"aatay EB"
"ve Yazlm Mhendisiyim.\n");
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);

printf("Girilen deer: %d\n",sayi);


return 0;
}

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

long int degisken;

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 ,&degisken
-128
en);
);
printf("% scanf("%d
d",degisk ",&degiske
-32768
en);
n);
printf("% scanf("%d
d",degisk ",&degiske
-32768
en);
n);
printf("% scanf("%ld
ld",degisk ",&degiske -2147483648
en);
n);
printf("% scanf("%u"
u",degisk ,&degisken
0
en);
);
printf("% scanf("%lu
lu",degisk ",&degiske
0
en);
n);
printf("% scanf("%f",
f",degiske &degisken) 1,17549e-38
n);
;
printf("% scanf("%lf"
lf",degisk ,&degisken 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

BOYUT\t\t MIN\t \tMAX\n" );

");

printf("==============================================================\n

printf( "char\t\t: %d byte(s)\t%d\t\t%d\n",


sizeof(char),CHAR_MIN,CHAR_MAX );
printf( "short\t\t: %d byte(s)\t%d\t\t%d\n", sizeof(short), SHRT_MIN,
SHRT_MAX );
printf( "int\t\t: %d byte(s)\t%d\t%d\n", sizeof(int), INT_MIN,
INT_MAX );
printf( "unsigned int\t: %d byte(s)\t\t\t%u\n",sizeof(unsigned),UINT_MAX
);
printf( "long\t\t: %d byte(s)\t%ld\t%ld\n", sizeof(long), LONG_MIN,
LONG_MAX );
printf( "float\t\t: %d byte(s)\t%e\t%e\n", sizeof(float), FLT_MIN,
FLT_MAX );
printf( "double\t\t: %d byte(s)\t%e\t%e\n\n", sizeof(double), DBL_MIN,
DBL_MAX );
return 0;
}

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

atanyor. Burada yabanc olduumuz, sadece scanf(); kullanmndaki deiiklik. scanf();


fonksiyonuna bakn. Dikkat edeceiniz gibi, deikenlerden ikisine de tek satrda deer atadk. Ayr
ayr yazmamz da mmknd, ancak kullanm asndan byle yazmak ak ekilde daha pratiktir.
Bu konuda bir baka rnek verelim. Diyelim ki, biri int, dieri float, sonuncusuysa char tipinde 3
deikeni birden tek scanf(); ile almak istiyorum. Deikenlerin isimleri, d1,d2 ve d3 olsun. Nasl
yaparz?
scanf("%d%f%c",&d1,&d2,&d3);

Peki aldmz bu deikenleri ekrana tek printf(); ile nasl yazdrabiliriz?


printf("%d %f %c",d1,d2,d3);

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:
*
*
*
*
*

8/4+2 => 2 + 2 => 4


8-4*2+-12 => 8 - 8 + -12 => -12
15*4/2%4*7 => 60/2%4*7 => 30%4*7 => 2*7 => 14
31+7/2-83%5*2-2 => 31+ 3 - 3 * 2 - 2 => 31 + 3 - 6 - 2 => 26
(31-7) * 2 + 83 / (5%2) => 24 * 2 + 83 / 1 => 48 + 83 => 131

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.

C Programlama Dersi - III


Bu yazda renecekleriniz:
Kodlarnza aklama (comment) koymak
Cast Operator
Koullu (Conditional) fadeler
Koullu Operatrler ( if, else, vs... )
likisel (Relational) Operatrler
Birleik (Compound) Operatrler
Konuyla ilgili rnek sorular

Kodlarnza aklama (comment) koymak


Yazlm mhendislerinin en byk sknts kod yazmak deildir. Yazlm bir kodu okuyup anlamak
-hele ki byk bir projeden sz ediyorsak- asl banza bela olacak konudur. Bundan korunmak iin
kodlarmza aklama/yorum koyarz.
C programlama dilinde iki ekilde aklama koymak mmkndr. Bunlardan bir tanesi, satr
baznda yaplr. Dieriyse, belirli bir blou yorumlamaya yarar. Compiler her iki ekilde de,
aklama olarak belirlemi yerleri ilemeyecektir. Aadaki rnekte satr ve blok olarak, nasl
kodlarnza aklama getirebileceinizi grebilirsiniz:
/*ok satrl bir aklama.
Yldzlar arasnda kalan btn
alan, yorum olarak deerlendirilir
ve derleyici (compiler) tarafndan
ilenmez.
*/
#include<stdio.h>
int main( void )
{
//Tek satrlk bir aklama.
printf("Hello World\n");
}

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;
}

Program kts; "Sonuc: 1.000000" olacaktr:


Normalde 1.5 kmasn beklediiniz sonucun, 0.000000 kmasnn nedeni casting
kullanmamamzdr. Bir tam sayy, bir baka tam sayya blerseniz, sonu bir baka tam say kar.
Ve C programlama dili, bir virgll sayy tam sayya atamaya kalktnzda, herhangi bir
yuvarlama ilemi yapmadan, virglden sonras atar.
Cast Operator u ekilde kullanlmaldr: degisken_1 = ( tip ) degisken_2;
Elimizdeki bu bilgiye gre programmz tekrar yazalm.
#include<stdio.h>
int main( void )
{
int bolunen = 12, bolen = 8;
float bolum;
bolum = (float)bolunen / bolen;
printf("Sonuc: %f\n",bolum);
return 0;
}

Sonu bu sefer, beklediimiz gibi 1.5 kacaktr.


Aadaki rnei inceleyelim:
#include<stdio.h>
int main( void )
{
printf("Sonuc: %f\n", 2 / 4);
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;
}

Koullu (Conditional) fadeler


if
Bilgisayarda yaplan btn mantksal ilemler kaba bir temele dayanr. artlar saland halde
yaplacak ilem belirlenir. Ve artlar salandnda, bu ilemler yaplr. artlarn kontrol edilmesini,
C (ve daha birok) programlama dilinde if operatrn kullanarak yaparz.
if operatrnn genel kullanm yaps u ekildedir:
if( koul ) {
komut(lar)
}

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)
}

nceki yazdmz program dnelim; 100'den byk olduunda, ekrana kt alyorduk. Bu


programa bir zellik daha ekleyelim ve 100'den kkse, bunu da syleyen bir yapy oluturalm:
#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");
else
printf("Girilen say 100'den kktr\n");
return 0;
}

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:

likisel (Relational) Operatrler


Koullu operatrlerde, koulun doruluunu kontrol ederken kullandmz ilikisel operatrler,
aada verilmitir:
<

Kktr

>

Byktr

==

Eittir

<=

Kk eittir

>=

Byk eittir

!=

Eit deildir

Birleik (Compound) Operatrler


Baz durumlarda, kontrol edeceimiz koul, tek bir parametreye bal deildir. rnein, bir kiinin
yann 65'den kk olup olmadna bakabiliriz. Ama 65'den kk ve 18 yandan byk olup
olmadna karar vermek istersek, o zaman Birleik/Birletirici Operatrler'i kullanmamz uygun
olacaktr.
Compound operator'ler aadaki gibidir:
&&

and

ve

||

or

veya

not

tersi

Bu operatrlerin mantksal (logical) doruluk tablosu da u ekildedir:


p

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

ie gemi (Nested) fadeler


Daha nce, koullu ifadeleri grmtk. Hatrlatmak iin zerinden geersek, if ile bir ifadeyi

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;
}

Yukarda ki kodu if - else kullanarak daha efektif hale getirebiliriz:


/*
if - else yapsyla daha
efektif bir yap
*/
#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");
}
}
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

printf("HATA: Girilen ya tanml deildir!\n");


}

return 0;

swicth - case ifadesi


switch - case, if - else if yapsna olduka benzer bir ifadedir. Ancak aralarnda iki fark vardr.
Birincisi, switch - case yapsnda, aralk deeri girmezsiniz. Direkt olarak ifadelerin bir eylere eit
olup olmadna bakarsnz. kinci farksa, switch - case yaplarnda, illa ki uygun koulun
salanmasyla yapnn kesilmek zorunda olmaydr. 'break' komutu kullanmadnz takdirde,
dier artlarn iindeki ilemleri de yapma imkannz olabilir. switch case en tepeden balayarak
artlar tek tek kontrol eder. Uygun art yakalanrsa, bundan sonra ki ifadeleri kontrol etmeden
doru kabul eder. Ve ayet siz break koymamsanz, eitlik uygun olsun olmasn, alt tarafta kalan
case'lere ait komutlarda altrlacaktr. if - else if ise daha nce sylemi olduumuz gibi byle
deildir. Uygun koul salandnda, yap darsna klr.
switch case yapsnda ki durumu, aadaki tabloda grebilirsiniz:
switch case Yaps

switch case Ak Diyagram

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",&not);
switch( not / 10 ) {
case 10:
case 9: printf("NOT: A\n"); break;
case 8: printf("NOT: B\n"); break;
case 7: printf("NOT: C\n"); break;
case 6: printf("NOT: D\n"); break;
case 5:
case 4:
case 3:
case 2:
case 1:
case 0: printf("NOT: F\n"); break;
default:
printf("HATA: Bilinmeyen bir 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.

Arttrma (Increment) ve azaltma (decrement) ilemleri


Daha nceki derslerimizde, aritmetik ilemlerden bahsetmitik. Bunlarn dnda yapabileceimiz
baka eylerde bulunmaktadr. Bunlardan biri de, arttrma ve azaltma ilemleridir.
Eer i adnda bir deikenin deerini 1 arttrmak isterseniz, i = i + 1 olarak yazarsnz. Veya 1
azaltmak isterseniz, benzer ekilde i = i - 1 de yazabilirsiniz. Arttrma ve azaltma ilemleri bu olay
daha basit bir forma sokmaktadr. i = i + 1 yazmak yerine i++ veya i = i - 1 yazmak yerine i-yazabilirsiniz.
Arttrma ve azaltma ilemleri temelde iki eittir. Birinci yntemde yukarda yazdmz gibi,
arttrma/azaltma sonradan yaplr. kinci yntemdeyse arttrma/azaltma ilk bata yaplr. Aadaki
rneklere bakalm.
/*
Bu programda, arttrma ve azaltma
ilemleri nce yaplacaktr.
*/
#include<stdio.h>
int main( void )
{
int i = 10, j = 60;
printf("i = %d ve j = %d\n", ++i, --j);
return 0;
}

Yukardaki program yazar ve altrsanz elde edeceiniz kt u ekilde grnecektir:


i = 11 ve j = 59
nk arttrma ve azaltma ilemleri ekrana bastrmadan nce yaplm ve i ile j'nin deerleri
deitirilmitir. imdi program deitirip yle yazalm:
/*
Bu programda, arttrma ve azaltma
ilemleri sonra yaplacaktr.
*/
#include<stdio.h>
int main( void )
{
int i = 10, j = 60;
printf("i = %d ve j = %d\n", i++, j--);
return 0;
}

Bu sefer program kts yle olacaktr:


i = 10 ve j = 60
Farkettiiniz zere hibir deiiklik yaplmam gibi duruyor. Aslnda deiiklik yapld ve program
sonlanmadan nce i 10 olurken, j'de 59 oldu. Ama arttrma ve azaltma ilemleri printf komutu
altrldktan sonra yapld iin, biz bir deiiklik gremedik.
Ksacas nce arttrma (pre-increment) veya nce azaltma (pre-decrement) kullandnzda, ilgili
komut satrnda alacak ilk ey bu komutlar olur. Ancak sonra arttrma (post increment) veya
sonra azaltma kullanrsanz, o zaman bu ilemlerin etkileri ilgili komut satrndan sonra geerli
olacaktr. Aadaki zel tabloya bakabilirsiniz:
Form

Tip

sim

Aklama

i++

postfix

post-increment

lem sonras arttrma

++i

prefix

pre-increment

lem ncesi arttrma

i--

postfix

post-decrement

lem sonras azaltma

--i

prefix

pre-decrement

lem ncesi azaltma

Gelimi atama (Advanced Assignment) yntemleri


C'de yazm kolayl amacyla sunulmu bir baka konu da, gelimi aama yntemleridir. Biraz
daha uzun yazacanz kodu, ksaltmanza yaramaktadr.
degisken_1 = degisken_1 (operator) degisken_2 eklinde yazacanz ifadeleri, daha ksa
yazabilmeniz iin, degisken_1 (operator) = degisken_2 eklinde ifade edebilirsiniz. Gelimi
atamalarda sunulan genel formlar u ekildedir:
+= , -= , *= , /= , %=

Sanrm aadaki rneklere bakarsanz, konuyu ok daha net anlayacaksnz:


1-) j = j * ( 3 + x ) ==> j *= ( 3 + x )
2-) a = a / ( 5 - z ) ==> a /= ( 5 - z )
3-) x = x - 5 ==> x -= 5

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 {

Conditional Operator ( ? ) Yaps


koul?if_komut(lar):else_komutlar

else_komut(lar)
}

Conditional Operator ( ? ) Ak Diyagram

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;
}

imdi de ayn program conditional operator kullanarak yazalm:


/*
Girilen tam saynn
10'dan byk olup
olmadn syleyen
program
*/
#include<stdio.h>
int main( void )
{
int sayi;
printf("Ltfen bir say giriniz> ");
scanf("%d",&sayi);
( sayi > 10 ) ? printf("Say 10'dan byktr\n"):
printf("Say 10'dan kktr veya 10'a eittir\n");

return 0;

Program grdnz gibi biraz daha ksald.


Conditional Operator'ler pek kullanmay sevmediim bir yapdr. nk kodun ksa olmasndan
ok, anlalabilir olmas nemli. Ve conditional operator kullanmak ne yazk ki, kodu daha karmak
hale getiriyor. UNIX filozofisinde bir eyi akllca yapacanza, temiz/ak yapn diye bir yaklam
mevcut. Belki bu yzden veya belki de tembellik, conditional operator'lere alamadm gitti... :)
imdi rnek sorularmza gelelim...
Soru 1: Aadaki kodu yorumlaynz:
s = ( x < 0 ) ? -1 : x * x
Soru 2: ki tam say alacak ve verilecek operatre gre (+, -, *, /, %) ilem yapacak bir program
yaznz.
Soru 3: Verilecek saydan en byn ekrana yazdracak bir program yaznz.
Cevap1:
Eer x, 0'dan kk bir deerse, s deikenine, -1 deeri atanr. Eer x, 0'dan
bykse,
x'in karesi, s deikenine atanr. (Grdnz gibi ilk bakta kodu yorumlamak
biraz
skc olabiliyor. Sanrm yukarda ne demek istediimi anlamsnzdr.)

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 );

nce Merhaba Dnya rneimizi yapalm:


#include<stdio.h>
int main( void )
{
int i = 0;
do {
//nce i'nin deeri arttrlyor
//sonra ekrana Merhaba Dnya yazdrlyor.
printf("%2d: Merhaba Dnya\n",++i);
} while( i < 10 );
return 0;
}

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

for( ilk_deger_atama; koul; arttrma/azaltma ){


komut(lar)
}

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.

if( i%2 == 0 ) continue;


printf("%2d\n",i);
}
return 0;
}

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,

// program buraya donecektir.


baslangic_noktasi:
printf( "Merhaba Dnya\n" );
// i degerini arttiriyoruz.
i++;
// i degeri kontrol ediliyor. Sayet 10'dan kucukse,
// en basa donuyor.
if( i<10 ) goto baslangic_noktasi;
return 0;
}

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

Hexadecimal/16'lk say tabanyla ilgili aadaki rneklere gz atalm:


( 3FC )16 = ( 3 . 162 ) + ( F . 161 ) + ( C . 160 ) = 768 + 240 + 12 = 1020

( 1FA9 )16 = ( 1 . 163 ) + ( F . 162 ) + ( A . 161 ) + ( 9 . 160 ) = 4096 + 3840


+ 160 + 9 = 8105
( 75 )16 = ( 7 . 161 ) + ( 7 . 160 ) = 112 + 5 = 117

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

Bu durumu bir rnekle yle gsterebiliriz:


( A3F1 )H : A
3
F
: 1010 0011 1111

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

Bit Baznda ( Bitwise ) Operatrler


Bit baznda operatrlerin, ngilizce'deki karl Bitwise Operators ( yani Bit bit Operatrler )
olarak gemektedir. Bit baznda operatrler, ikilik say tabannda yapabileceimiz ilemleri temsil
eder. Kullanlan operatrleri aada inceleyeceiz.

AND ( & ) Operatr


AND operatr, kendisine verilen iki deikenin btn bitleri 1'e eit olduu takdirde, geriye 1
dndrr. Aksi halde -yani en ufak bir fark varsa- 0 deeri dnmektedir.
p

p&q

imdi, AND ( & ) operatrn 25 ve 14 saylarn karlatrmak iin kullanalm:


25 ==> ( 0001 1001 )2
14 ==> ( 0000 1110 )2
&
---------------------------8 ==> ( 0000 1000)2

OR ( | ) Operatr
ki deikenden herhangi biri 1 ieriyorsa, geriye 1 dner. Eer her ikisi de 0 ieriyorsa, geriye 0
dnmektedir.
p

p|q

Daha nce kullandmz 25 ve 14 saylar zerinde OR ( | ) ilemi kullanalm:


25 ==> ( 0001 1001 )2
14 ==> ( 0000 1110 )2
|
---------------------------31 ==> ( 0001 1111)2

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

25 ==> ( 0001 1001 )2

~
---------------------------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

25 ==> ( 0001 1001 )2


14 ==> ( 0000 1110 )2
^
---------------------------23 ==> ( 0001 0111 )2

Kaydrma ( Shift ) Operatrleri


Kaydrma operatrleri, zellikle Assembly ile uraanlara tandk gelecektir. Bunlar kullanarak son
derece hzl arpma ve blme yaplabilir. C'deyse benzer amalarla kullanmanz elbette
mmkndr. ki eit kaydrma operatr vardr:
i) Sola Kaydrma - Shift Left ( << )
ii) Saa Kaydrma - Shift Right ( >> )
Her iki durumda da genel kullanm ekli aadaki gibidir:
[ Tam Say ][ Operatr ][ Kaydrma Adm Says ]
Aadaki rnek, sola kaydrma operatr kullanlarak yaplan bir ilemi gstermektedir. x
deikeni, 10 tabannda 22 saysn tutmaktadr. 2 adm sola kaydrlmas sonucu, say 88 olmu ve
y'ye atanmtr.
x = ( 0001 0110 )2 ==> 22
y = x << 2
y = ( 0101 1000 )2 ==> 88

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

&

OPERATR NCELK SIRASI


<< >> + - * / % ! ~ - ++ -- ( )

YKSEK

Aada bulunan tablo, ilikisel ve mantksal operatrlerde ki ncelik srasn gstermektedir:


LKSEL ve MANTIKSAL OPERATR NCELK SIRASI

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

imdi de benzer bir rnei, C program yazarak yapalm:


#include<stdio.h>
int main( void )
{
printf( "lem Sonucu: %d\n", 117 & 11 << 2 * 3 );
return 0;
}

Yukardaki program, 64 sonucunu vermektedir. Program altrdnzda, ikilik dzeyde ilemler


yaplacak ve 64 cevabna ulalacaktr. Siz de hesaplayarak, ayn yant bulabilirsiniz.
Bir sonraki dersimizde, konu anlatm olmayacak. Onun yerine bol bol rnek yapp, imdiye kadar
ilediimiz konularn zerinden geeceiz. Grmek zere...

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?

Soru 1.b: Aadaki program doru olarak y

#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;

//Onlar basaman bulmak iin, saynn


//yze blmnden kalan deeri, 10'a
//blyoruz. Yzler basaman bir nceki
//admda ele aldmz iin, bu admda,
//saynn yze blmn deil, blmnden
//kalan kullandk.
//ONLAR BASAMAI:
switch ( (sayi%100)/10 ) {
case 9: printf( "doksan" );
case 8: printf( "seksen" );
case 7: printf( "yetmi" );
case 6: printf( "altm" );
case 5: printf( "elli" );
case 4: printf( "krk" );
case 3: printf( "otuz" );
case 2: printf( "yirmi" );
case 1: printf( "on" );
}

break;
break;
break;
break;
break;
break;
break;
break;
break;

//Birler basaman bulabilmek iin, saynn


//10'a blmnden kalana bakyoruz.
//BRLER BASAMAI:
switch ( (sayi%10) ) {
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(
}

"dokuz" );
"sekiz" );
"yedi" );
"alt" );
"be" );
"drt" );
"" );
"iki" );
"bir" );

break;
break;
break;
break;
break;
break;
break;
break;
break;

//Eer say 0 ise, yukarda ki dzenee


//uymayacandan, onu ayrca ele alyoruz.
if( sayi == 0 )
printf( "sfr" );

printf( "' eklinde okunur.\n" );


return 0;
}

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.

sayinin_tersi = d * 1000 + c * 100 + b *

10 + a;

//Sayinin tersinin 4 katinin ilk sayiya


//esit olup olmadigi kontrol ediliyor.
//Ayrica sayinin 0 olmamasi
gerekmektedir.

//Bu kontrol de yapilmaktadir.


if( sayi == 4 * sayinin_tersi && sayi !=

0 ) {

//Sayi ve uygun olan tersi


gosterilir:

printf( "Say: %d, tersi: %d\n",

sayi, sayinin_tersi );
//return ifadesi programin daha

fazla devam

//etmemesi icin burada

kullanilmistir.

//Program donguye devam etmez ve

burada kesilir.

//return, main fonksiyonunu

sonlandirir.
}
}

return 0;

//Uygun bir sayi bulunamazsa, program burada sonlanacaktir.


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)) {

printf("Lutfen 0 ile 20 arasinda bi deger giriniz.");


printf("Karenin kenar uzunlugu");
scanf("%d", &kenar);

/* 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;

Soru 8: Aadaki ekenar drtgen ktsn retecek bir program yaznz:


*
***
*****
*******
*********
*******
*****
***
*

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;

for(a = 1; a < 500; a++)


for(b = a; b < 500; b++)
for(hipotenus = b+1; hipotenus <= 500; hipotenus++)
if( (a*a + b*b) == hipotenus*hipotenus )
printf("%5d%5d%5d\n", a, b, hipotenus);
return 0;

Ksa Devre Deerlendirme


Ksa devre deerlendirme, ne yazk ki pek iyi bir eviri olmad ve bu yzden hibir anlam ifade
etmeyebilir. ngilizce'de, Short Circuit Evaluation olarak geen bu konu, mantksal ifadelerle
ilgilidir.
Hatrlarsanz, daha nce ki derslerimizde iki farkl AND ve OR operatr grmtk. Bu yaplardan
biri AND iin && iaretini kullanyorken, dieri sadece tek & simgesini kullanyordu. Keza, OR
ifadesi bir yerde, || eklinde gsteriliyorken, dier yerde, tek bir | simgesiyle ifade edilmekteydi. Bu
iaretler, ayn sonucu retiyor gibi grnseler de, farkl ekilde alrlar.
ift ekilde yazlan operatrler, ( yani && ve || ) ksa devre operatrleridir. ngilizce, Short Circuit
Operator olarak isimlendirilirler. Tek sembolle yazlan operatrlerden fark, ilemleri
ksaltmalardr.
Bir koul iersinde AND ( && ) operatr kullandnzda, koulun sol taraf yanlsa, sa taraf
kontrol edilmez. nk artk sa tarafn doru veya yanl olmasnn nemi yoktur; sonu her
ekilde yanl olacaktr.
Benzer bir mantk OR ( || ) operatr iinde geerlidir. Eer sol taraf doruysa, sa tarafn kontrol
edilmesine gerek yoktur. nk OR operatrnde taraflardan birinin doru olmas durumunda,
dierinin nemi kalmaz ve sonu doru dner.
Aadaki rnekleri inceleyelim:
&& Operatr
#include<stdio.h>
int main( void )
{

& 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 {

printf( "if iersine girmedi\n" );


printf( "i: %d, j: %d\n", i, j );

}
return 0;

if iersine girmedi
i: 0, j: 5

i, j;
0;
5;
i == 1 & j++ ) {
printf( "if iersine g

printf( "if iersine g


printf( "i: %d, j: %d\

}
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.

#define nilemci Komutu


#define komutu, adndan da anlalabilecei gibi tanmlama ilemleri iin kullanlr. Tanmlama
komutunun kullanm mant ok basittir. Btn yapmamz gereken, neyin yerine neyi
yazacamza karar vermektir. Bunun iin #define yazp bir boluk braktkan sonra, nce
kullanacamz bir isim verilir, ardndan da yerine geecei deer.
Altta ki program, PI sembol olan her yere 3.14 koyacak ve ilemleri buna gre yapacaktr:
/* ember alann hesaplar */

#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;
}

#define komutunun baka marifetleri de vardr. lerki konularmzda greceimiz fonksiyon


yapsna benzer ekilde kullanm mmkndr. Elbette ki, fonksiyonlar ok daha gelimitir ve
saladklar esneklii, #define tutamaz. Bu yzden #define ile yaplacaklarn snrn ok
zorlamamak en iyisi. Ancak yine de bilginiz olmas asndan aada ki rnee gz atabilirsiniz:
/* Istenen sayida, "Merhaba" yazar */
#include<stdio.h>
#define merhaba_yazdir( x ) int i; for ( i = 0; i < (x); i++ )
printf( "Merhaba\n" );
int main( void )
{
int yazdirma_adedi;
printf( "Ka defa yazdrlsn> " );
scanf( "%d", &yazdirma_adedi );
merhaba_yazdir( yazdirma_adedi );
return 0;
}

#undef nilemci Komutu


Baz durumlarda, #define komutuyla tanmladmz eyleri, iptal etmek isteriz. Tanmlamay iptal
etmek iin, #undef komutu kullanlr. rnein #undef PI yazdnz da, o noktadan itibaren PI
tanmsz olacaktr. #define ile oluturduunuz sembolleri belirli noktalardan sonra geerliliini iptal

etmek veya yeniden tanmlamak iin #undef komutunu kullanabilirsiniz.

#ifdef ve #ifndef nilemci Komutlar


nilemci komutlarnda bir sembol veya simgenin daha nce tantlp tantlmadn kontrol etmek
isteyebiliriz. Tantlmsa, yle yaplsn; yok tantlmadysa, byle olsun gibi farkl durumlarda ne
olacan belirten yaplar gerekebilir. Bu a kapatmak iin #ifdef (if defined - ayet
tanmlandysa) veya #ifndef (if not defined - ayet tanmlanmadysa) operatrleri kullanlr.
#include<stdio.h>
#define PI 3.14
int main( void )
{
// Tanml PI deeri, tanmsz hle getiriliyor.
#undef PI
int yaricap;
float alan;
printf( "emberin yar apn giriniz> " );
scanf( "%d", &yaricap );
// PI deerinin tanml olup olmad kontrol ediliyor.
#ifdef PI
//PI tanmlysa, daire alan hesaplanyor.
alan = PI * yaricap * yaricap;
printf( "ember alan: %.2f\n", alan );
#else
//PI deeri tanmszsa, HATA mesaj veriliyor.
printf("HATA: Alan deeri tanml deildir.\n");
#endif
}

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;
}

#if, #else, #endif, #elif nilemci Komutlar


Bazen bir deerin tanmlanp, tanmlanmadn bilmek yetmez. Baz deerler, bayrak (flag) olarak
kullanlr. Yani eer doruysa, byle yaplmas lzm, aksi hlde byle olacak gibi... Baz
programlar, nilemci komutlarndan yararlanr. Deiken yerine, nilemcileri kullanarak
tanmlanan simgeler, bu programlarda flag grevi grr.
Konumuza dnersek, #if, #else, #endif yaps daha nce ilemi olduumuz if-else yapsyla hemen
hemen ayndr. if-elif yaps da if-else if yapsna benzer. Her ikisinin de genel yazm kural aada
verilmitir:
#if - #else Yaps:
#if koul
komut(lar)
#else
komut(lar)
#endif

#if - #elif Yaps:


#if koul 1
komut(lar)
#elif koul 2
komut(lar)
.
.
.
#elif koul n-1
komut(lar)
#else
komut(lar)
#endif

1
2

n-1
n

Bir program tasarlayalm. Bu programda, pi saysnnn virglden sonra ka basamann hesaba


katlacana karar veren bir mekanizma olsun. Soruyu, u ana kadar grdmz, if - else gibi
yaplarla rahata yapabiliriz. nilemci komutuyla ise, aadakine benzer bir sistem oluturulabilir:
/* Daire alann hesaplar */
#include<stdio.h>
#define HASSASLIK_DERECESI 2
int main( void )
{
int yaricap;
float alan;
printf( "emberin yar apn giriniz> " );
scanf( "%d", &yaricap );
//
//
//
//

Hassaslk derecesi, pi saysnn virglden ka


basamak sonrasnn hesaba katlacan belirtir.
Eer hassaslk derecesi bunlara uymuyorsa, alan
deeri -1 yaplr.

#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

printf( "ember alan: %.2f\n", alan );


return 0;

#include nilemci Komutu


#include olduka tandk bir operatrdr. Her programmzda, #include nilemci komutunu
kullanrz. ayet kullanmasak, printf( ) veya scanf( ) gibi fonksiyonlar tekrar tekrar yazmamz
gerekirdi. #include komutu, programmza bir balk dosyasnn (header file) dhil edileceini
belirtir. Bu balk dosyas, standart giri k ilemlerini ieren bir ktphane olabilecei gibi,
kendimize ait fonksiyonlarn bulunduu bir dosya da olabilir.
Eer sistem ktphanelerine ait bir balk dosyasn programnza dhil edeceksek, kktr ( < ) ve
byktr ( > ) iaretlerini kullanrz. rnein stdio.h sisteme ait bir ktphane dosyasdr ve
Linux'ta /usr/include/stdio.h adresinde bulunur. Dolaysyla stdio.h ktphanesini programmza
eklerken, #include<stdio.h> eklinde yazarz. Kendi oluturduumuz balk dosyalar iinse, durum
biraz daha farkldr.
alma ortammzla ayn klasrde olan bir balk dosyasn, programmza eklemek iin
#include "benim.h" eklinde yazarz. lerki derslerimizde, kendi balk dosyalarmz oluturmay
greceiz. Ancak imdilik burada keselim...

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.

Bu yazmzda, fonksiyonlar aklayacaz.

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.
/\

\
/
\
---------|
|
|
|
|
|
----------

Ev veya kule benzeri bu ekli aadaki, kod yardmyla gsterebiliriz:


/* Ev sekli cizen program */
#include<stdio.h>
int main( void )
{
printf( "
/\\
\n"
printf( "
/ \\ \n"
printf( " /
\\ \n"
printf( " /
\\\n"
printf( "----------\n"
printf( "|
|\n"
printf( "|
|\n"
printf( "|
|\n"
printf( "----------\n"
}

);
);
);
);
);
);
);
);
);

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

kodu, iki adet fonksiyon kullanarak yapalm:


/* 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( );
kat_ciz( );
}

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

// Evin katini cizen fonksiyon.


// void yok

void kat_ciz( void )


{
printf( "|
|\n"
printf( "|
|\n"
printf( "|
|\n"
printf( "----------\n"
}

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.

/* 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.
// sol ve sag degiskenleri fonksiyon
// parametreleridir.
void kat_ciz( char sol, char sag )
{
printf( "%c
%c\n", sol, sag );
printf( "%c
%c\n", sol, sag );
printf( "%c
%c\n", sol, sag );
printf( "----------\n" );
}
// Programin calismasini saglayan
// ana fonksiyon.
int main( void )
{
char sol_duvar, sag_duvar;
printf( "Kullanlacak karakterler> " );
scanf( "%c%c",&sol_duvar, &sag_duvar );
catiyi_ciz( );
// sol_duvar ve sag_duvar, fonksiyona
// giden argumanlardir.
kat_ciz( sol_duvar, sag_duvar );
kat_ciz( sol_duvar, sag_duvar );
kat_ciz( sol_duvar, sag_duvar );
}

return 0;

Argmanlarn deer olduunu unutmamak gerekiyor. Yukardaki rneimizden, deiken olmas


gerektii yanlgsna debilirsiniz. Ancak bir fonksiyona deer aktarrken, direkt olarak deeri de
yazabilirsiniz. Program deitirip, sol_duvar ve sag_duvar deikenleri yerine, '*' simgesini koyun.
eklin duvarlar, yldz iaretinden oluacaktr.
Yazdmz kat_ciz( ) fonksiyonunu incelemek iin, aada bulunan grafie gz atabilirsiniz:

imdi de baka bir rnek yapalm ve verilen herhangi bir saynn tek mi yoksa ift mi olduuna
karar veren bir fonksiyon oluturalm:

/* Saynn tek veya ift olmasn


kontrol eder. */
#include<stdio.h>
void tek_mi_cift_mi( int sayi )
{
if( sayi%2 == 0 )
printf( "%d, ift bir saydr.\n", sayi );
else
printf( "%d, tek bir saydr.\n", sayi );
}
int main( void )
{
int girilen_sayi;
printf( "Ltfen bir say giriniz> " );
scanf( "%d",&girilen_sayi );
tek_mi_cift_mi( girilen_sayi );
return 0;
}

Yerel ( Local ) ve Global Deikenler


Kendi oluturacanz fonksiyon iersinde, main( ) fonksiyonunda ki her eyi yapabilirsiniz.
Deiken tanmlayabilir, fonksiyon iinden baka fonksiyonlar arabilir veya dilediiniz
operatr kullanabilirsiniz. Ancak deiken tanmlamalaryla ilgili gz ard etmememiz gereken bir
konu bulunuyor. Bir fonksiyon iersinde tanmladnz deikenler, sadece o fonksiyon iersinde
tanmldr. main( ) veya kendinize ait fonksiyonlardan bu deikenlere ulamamz mmkn
deildir. main( ) iinde tanmladnz a isimli deikenle, kendinize zg tanmladnz
kup_hesapla( ) iersinde tanmlanm a isimli deiken, bellekte farkl adresleri iaret eder.
Dolaysyla deikenlerin arasnda hibir iliki yoktur. kup_hesapla( ) iersinde geen a
deikeninde yapacanz deiiklik, main( ) fonksiyonundakini etkilemez. Keza, tersi de
geerlidir. u ana kadar yaptmz btn rneklerde, deikenleri yerel olarak tanmladmz
belirtelim.
Yerel deiken dnda, bir de global deiken tipi bulunur. Programn herhangi bir noktasndan
eriebileceiniz ve nerede olursa olsun ayn bellek adresini iaret eden deikenler, global
deikenlerdir. Hep ayn bellek adresi sz konusu olduun iin, programn herhangi bir noktasnda
yapacanz deiiklik, global deikenin getii btn yerleri etkiler. Aadaki rnei inceleyelim:
#include<stdio.h>
// Verilen sayinin karesini hesaplar
void kare_hesapla( int sayi )
{
// kare_hesapla fonksiyonunda
// a degiskeni tanimliyoruz.
int a;
a = sayi * sayi;
printf( "Saynn karesi\t: %d\n", a );
}
// Verilen sayinin kupunu hesaplar
void kup_hesapla( int sayi )
{
// kup_hesapla fonksiyonunda
// a degiskeni tanimliyoruz.
int a;
a = sayi * sayi * sayi;
printf( "Saynn kp\t: %d\n", a );
}

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 );
// Eger a degiskeni lokal olmasaydi,
// kare_hesapla fonksiyonundan sonra,
// a'nin degeri bozulur ve kup yanlis
// hesaplanirdi.
kup_hesapla( a );
return 0;
}

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

gerekmez. Bir fonksiyon iersinde 'daha lokal' deikenleri tanmlayabilirsiniz. Internet'te


bulduum aadaki program incelerseniz, konuyu anlamanz asndan yardmc olacaktr.
#include<stdio.h>
int main( void )
{
int i = 4;
int j = 10;
i++;
if( j > 0 ){
printf("i : %d\n",i);
degiskeni */
}
if (j > 0){
int i=100;
}

printf("i : %d\n",i);

degerini

/* 'main' icinde tanmlanmis 'i'

/* 'i' sadece bu if blogunda gecerli


olmak uzere tanimlaniyor. */
/* if blogunda tanimlanan ve 100
tasiyan 'i' degiskeni burada sonlaniyor.

*/
tasiyan

printf("i : %d\n",i);

/* En basta tanimlanan ve 5 degerini


'i' degiskenine donuyoruz */

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.

int sayi_asal_mi( int sayi )


{
int i;
for( i = 2; i <= sayi/2; i++ ) {
// Sayi asal degilse, i'ye tam olarak
// bolunur.
if( sayi%i == 0 ) return 0;
}
// Verilen sayi simdiye kadar hicbir
// sayiya bolunmediyse, asaldir ve
// geriye 1 doner.
return 1;
}
// main fonksiyonu
int main( void )
{
int girilen_sayi;
int test_sonucu;
do{
printf( "Ltfen bir say giriniz> " );
scanf( "%d",&girilen_sayi );
test_sonucu = sayi_asal_mi( girilen_sayi );
if( !test_sonucu )
printf("Girilen say asal deildir!\n");
} while( !test_sonucu );
printf( "Girilen say asaldr!\n" );
}

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.

Baz Aritmetik Fonksiyonlar


Geen dersimizde, fonksiyonlar ve bunlar nasl kullanlacan grmtk. Ayrca ktphanelerin
hazr fonksiyonlar ierdiinden bahsetmitik. Baz matematiksel ilemlerin kullanm ska
gerekebilecei iin bunlar bir liste hlinde vermenin uygun olduuna inanyorum. Bylece var olan
aritmetik fonksiyonlar tekrar tekrar tanmlayarak zaman kaybetmezsiniz.
double ceil( double n ) : Virgll n saysn, kendisinden byk olan ilk tam sayya
tamamlar. rnein ceil(51.4) ilemi, 52 sonucunu verir.
double floor( double n ) : Virgll n saysnn, virglden sonrasn atarak, bir tam sayya
evirir. floor(51.4) ilemi, 51 saysn dndrr.
double fabs( double n ) : Verilen n saysnn mutlak deerini dndrr. fabs(-23.5), 23.5
deerini verir.
double fmod( double a, double b ) : a saysnn b saysna blmnden kalan verir. (Daha
nce grdmz modl (%) operatr, sadece tam saylarda kullanlrken, fmod
fonksiyonu virgll saylarda da alr.)
double pow( double a, double b ) : stel deer hesaplamak iin kullanlr; ab deerini verir.
double sqrt( double a ) : a'nn karekkn hesaplar.
Yukarda verilmi fonksiyonlar, matematik ktphanesi ( math.h ) altndadr. Bu fonksiyonlardan
herhangi birini kullacanz zaman, program kodununun bana #include<math.h> yazmalsnz.
Ayrca derleyici olarak gcc'yle alyorsanz, derlemek iin -lm parametresini eklemeniz gerekir.
(rnein: "gcc test.c -lm" gibi...)

Bellek Yaps ve Adresler


imdiye kadar deiken tanmlamay grdk. Bir deiken tanmlandnda, arka plnda
gerekleen olaylara ise deinmedik. Hafzay kk hcrelerden olumu bir blok olarak
dnebilirsiniz. Bir deiken tanmladnzda, bellek bloundan gerekli miktarda hcre, ilgili
deikene ayrlr. Gereken hcre adedi, deiken tipine gre deiir. imdi aadaki kod parasna
bakalm:
#include<stdio.h>
int main( void )
{
// Degiskenler tanmlanyor:
int num1, num2;
float num3, num4;
char i1, i2;
// Degiskenlere atama yapiliyor:
num1 = 5;
num2 = 12;
num3 = 67.09;
num4 = 1.71;
i1 = 'H';
i2 = 'p';
}

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;

// int tipinde pointer


// tanmlyoruz:
int *p;
// xyz deikeninin adresini
// pointer'a atyoruz.
// Bir deiken adresini '&'
// iaretiyle alrz.
p = &xyz;
// k deikenine xyz'nin deeri
// atanr. Pointer'lar deer tutmaz.
// deer tutan deikenleri iaret
// eder. Bana '*' koyulduunda,
// iaret ettii deikenin deerini
// gsterir.
k = *p;
}

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.

Pointer tutan Pointer'lar


Pointer'lar, grdmz gibi deikenleri iaret ederler. Pointer'da bir deikendir ve onu da iaret
edecek bir pointer yaps kullanlabilir. Geen sefer ki bildirimden fark, pointer deikenini iaret
edecek bir deiken tanmlyorsanz; bana '**' getirmeniz gerekmesidir. Buradaki yldz says
deiebilir. Eer, pointer iaret eden bir pointer'i iaret edecek bir pointer tanmlamak istiyorsanz,
defa yldz ( *** ) yazmanz gerekir. Evet, cmle biraz karmak, ama kullanm olduka basit!
Pointer iaret eden pointer'lar aadaki rnekte bulabilirsiniz:
#include<stdio.h>
int main( void )
{
int r = 50;
int *p;
int **k;
int ***m;
printf( "r: %d\n", r );
p = &r;
k = &p;
m = &k;
***m = 100;
printf( "r: %d\n", r );
}

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.

Referansla Argman Aktarm


Fonksiyonlara nasl argman aktaracamz biliyoruz. Hatrlayacanz gibi parametrelere deer
atyorduk. Bu yntemde, kullandnz argmanlarn deeri deimiyordu. Fonksiyona parametre
olarak yollanan argman hep ayn kalyordu. Fonksiyon iinde yaplan ilemlerin hibiri argman
deikeni etkilemiyordu. Sadece deiken deerinin aktarld ve argmann etkilenmedii bu
duruma, "call by value" veya "pass by value" ad verilir. Bu isimleri bilmiyor olsanz dahi, u ana
kadar ki fonksiyon almalar byleydi.
Geriye birden ok deer dnmesi gereken veya fonksiyonun iersinde yapacanz deiikliklerin,
argman deikene yansmas gereken durumlar olabilir. te bu gibi zamanlarda, "call by
reference" veya "pass by reference" olarak isimlendirilen yntem kullanlr. Argman deer olarak
aktarlmaz; argman olan deikenin adres bilgisi fonksiyona aktarlr. Bu sayede fonksiyon
iersinde yapacanz her trl deiiklik argman deikene de yansr.
Sylediklerimizi uygulamaya dkelim ve kendisine verilen iki saynn yerlerini deitiren bir
fonksiyon yazalm. Yani kendisine a ve b adnda iki deiken yollanyorsa, a'nn deerini b; b'nin
deeriniyse a yapsn.
#include<stdio.h>
// Kendisine verilen iki degiskenin
// degerlerini degistirir.
// Parametreleri tanimlarken baslarina
// '*' koyuyoruz.
void swap( int *x, int *y )
{
int temp;
temp = *x;
*x = *y;
*y = temp;
}
int main( void )
{
int a, b;
a = 12;
b = 27;
printf( "a: %d b: %d\n", a, b );
// Argumanlar aktarrken, baslarina
// '&' koyuyoruz.
swap(&a, &b);
printf( "a: %d b: %d\n", a, b );

return 0;

Referans yoluyla aktarm olmasayd, iki deikenin deerlerini fonksiyon kullanarak


deitiremezdik. Eer yazdnz fonksiyon birden ok deer dndrmek zorundaysa, referans
yoluyla aktarm zorunlu hle geliyor. nk daha nce ilediimiz return ifadesiyle sadece tek bir
deer dndrebiliriz. rnein bir blme ilemi yapp, blm sonucunu ve kalan syleyen bir
fonksiyon yazacamz dnelim. Bu durumda, blnen ve blen fonksiyona gidecek argmanlar
olurken; kalan ve blm geriye dnmelidir. return ifadesi geriye tek bir deer vereceinden, ikinci
deeri alabilmek iin referans yntemi kullanmamz gerekir.
#include<stdio.h>
int bolme_islemi( int bolunen, int bolen, int *kalan )
{
*kalan = bolunen % bolen;
return bolunen / bolen;
}
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;

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;
}

bolme_islemi( ) fonksiyonunu, main( ) fonksiyonundan nce yazmadk. Sadece byle bir


fonksiyon olduunu ve alaca parametre tiplerini bildirdik. ( steseydik parametre adlarn da

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>

void seri_olustur( int );


int main( void )
{
seri_olustur( 1 );
}
void seri_olustur( int sayi )
{
if( sayi <= 13 ) {
printf("%d ", sayi );
sayi += 4;
seri_olustur( sayi );
}
}

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;
}

Yukardaki programn detayl bir ekilde ak diyagramn vermeyeceim. Ancak faktriyel


hesaplamas yaplrken, admlar grmenizi istiyorum. Adm olarak geen her kutu, fonksiyonun bir
kez arlmasn temsil ediyor. Balang ksmn geerseniz fonksiyon toplamda 5 kere arlyor.

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

istediimiz eleman da yer numarasn yazarak belirtiriz. rnein a dizisinin, 25.eleman


gerekiyorsa, a[24] ile arlr. Sanrm 25 yerine 24 yazldn fark etmisinizdir. C programlama
dilinde, dizilerin ilk eleman 0'dr. Diziler 0'dan balad iin, ulamak istenilen dizi eleman
hangisiyse bir eksiini yazarz. Yani a dizisinin 25.eleman, a[24]; 100.eleman a[99] ile arrz.
imdi basit bir rnek yapalm. Bu rnekte, her aya ait gneli gn says sorulsun ve sonunda yllk
gneli gn says yazlsn.
#include<stdio.h>
int main( void )
{
// Aylari temsil etmesi icin
// aylar adinda 12 elemanli
// bir dizi olusturuyoruz.
int aylar[ 12 ];
int toplam = 0;
int i;
// Birinci dongu, deger atamak icindir
for( i = 0; i < 12; i++ ) {
printf( "%2d.Ay: ", (i+1) );
// aylara deger atyoruz:
scanf( "%d", &aylar[ i ] );
}
// Az evvel girilen degerleri gostermek icin
// ikinci bir dongu kurduk
printf( "\nGRDNZ DEERLER\n\n" );
for( i = 0; i < 12; i++ ) {
printf( "%2d.Ay iin %d girdiniz\n", (i+1), aylar[i] );
toplam += aylar[ i ];
}

printf( "Toplam gneli gn says: %d\n", toplam );


return 0;

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>

int main( void )


{
// Degerleri tutacagimiz 'dizi'
// adinda bir dizi olusturuyoruz.
float dizi[ 10 ];
float ortalama, toplam = 0;
int ortalama_ustu_adedi = 0;
int ortalama_alti_adedi = 0;
int i;
// Kullanici dizinin elemanlarini giriyor:
for( i = 0; i < 10; i++ ) {
printf( "%2d. eleman giriniz> ", (i+1) );
scanf( "%f", &dizi[ i ] );
toplam += dizi[ i ];
}
// dizinin ortalamasi hesaplaniyor.
ortalama = toplam / 10.0;
// ortalamadan kucuk ve buyuk elemanlarin
// kac adet oldugu belirleniyor.
for( i = 0; i < 10; i++ ) {
if( dizi[ i ] < ortalama )
ortalama_alti_adedi++;
else if( dizi[ i ] > ortalama )
ortalama_ustu_adedi++;
}
// raporlama yapiliyor.
printf( "Ortalama: %.2f\n", ortalama );
printf( "Ortalamadan dk %d eleman vardr.\n", ortalama_alti_adedi );
printf( "Ortalamadan yksek %d eleman vardr.\n", ortalama_ustu_adedi );
}

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.

Dizilere lk Deer Atama


Deiken tanm yaparken, ilk deer atamay biliyoruz. rnein "int a = 5;" eklinde yazacanz
bir kod, a deikenini oluturaca gibi, iine 5 deerini de atayacaktr. ( Bu deikene,
tanmladktan sonra farkl deerler atayabilirsiniz. ) Benzer ekilde, bir diziyi tanmlarken, dizinin
elemanlarna deer atayabilirsiniz. Aada bunu nasl yapabileceinizi grebilirsiniz:
int dizi1[ 6 ] = { 4, 8, 15, 16, 23, 42 };
float dizi2[ 5 ] = { 11.5, -1.6, 46.3, 5, 21.56 };

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:

int dizi1[ ] = { 4, 8, 15, 16, 23, 42 };


float dizi2[ ] = { 11.5, -1.6, 46.3, 5, 21.56 };

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 );

printf( "En Byk Deer: %d\n", max );


}

return 0;

Dizilerin fonksiyonlara aktarm


Dizileri fonksiyonlara aktarmak, tpk deikenleri aktarmaya benzemektedir. Uzun uzadya
anlatmak yerine, rnek stnden gitmenin daha fayda olacan dnyorum. Bir fonksiyon
yazalm ve bu fonksiyon kendisine gnderilen dizinin elemanlarn ekrana yazsn.
#include<stdio.h>
void elemanlari_goster( int [ 5 ] );
int main( void )
{
int dizi[ 5 ] = { 55, 414, 7, 210, 15 };
elemanlari_goster( dizi );
return 0;
}
void elemanlari_goster( int gosterilecek_dizi[ 5 ] )
{
int i;
for( i = 0; i < 5; i++)
printf( "%d\n", gosterilecek_dizi[ i ] );
}

Fonksiyon prototipini yazarken, dizinin tipini ve boyutunu belirttiimizi fark etmisinizdir.


Fonksiyonu tanmlama aamasnda, bunlara ilaveten parametre olarak dizinin adn da yazyoruz.
( Bu isim herhangi bir ey olabilir, kendisine gnderilecek dizinin adyla ayn olmas gerekmez. )
Bir dizi yerine sradan bir deiken kullansaydk, benzer eyleri yapacaktk. Farkl olan tek nokta;
dizi eleman saysn belirtmemiz. imdi main( ) fonksiyonuna dnelim ve elemanlari_goster( );
fonksiyonuna bakalm. Anlayacanz gibi, "dizi" ismindeki dizinin fonksiyona argman olarak
gnderilmesi iin sadece adn yazmamz yeterli.
Fonksiyonlarla ilgili bir baka rnek yapalm. Bu sefer fonksiyon oluturalm. Birinci fonksiyon
kendisine gnderilen dizideki en byk deeri bulsun; ikinci fonksiyon, dizinin en kk deerini
bulsun; nc fonksiyon ise elemanlarn ortalamasn dndrsn.
#include<stdio.h>
float maksimum_bul( float [ 8 ] );
float minimum_bul( float [ 8 ] );
float ortalama_bul( float [ 8 ] );
int main( void )
{
// 8 boyutlu bir dizi olusturup buna
// keyfi degerler atiyoruz.
float sayilar[ 8 ] = { 12.36, 4.715, 6.41, 13,
1.414, 1.732, 2.236, 2.645 };
float max, min, ortalama;
// Ornek olmasi acisindan fonksiyonlar
// kullaniliyor.
max = maksimum_bul( sayilar );
min = minimum_bul( sayilar );
ortalama = ortalama_bul( sayilar );
printf( "Maksimum: %.2f\n", max );
printf( "Minimum: %.2f\n", min );
printf( "Ortalama: %.2f\n", ortalama );
return 0;
}
/* Dizi icindeki maksimum degeri bulur */

float maksimum_bul( float dizi[ 8 ] )


{
int i, max;
max = dizi[0];
for( i = 1; i < 8; i++ ) {
if( max < dizi[ i ] )
max = dizi[ i ];
}
return max;
}
/* Dizi icindeki minimum degeri bulur */
float minimum_bul( float dizi[ 8 ] )
{
int i, min;
min = dizi[ 0 ];
for( i = 1; i < 8; i++ ) {
if( min > dizi[ i ] ) {
min = dizi[ i ];
}
}
return min;
}
/* Dizi elemanlarinin ortalamasini bulur */
float ortalama_bul( float dizi[ 8 ] )
{
int i, ortalama = 0;
for( i = 0; i < 8; i++ )
ortalama += dizi[ i ];
return ortalama / 8.0;
}

Yukardaki rneklerimizde, dizilerin boyutlarn bilerek fonksiyonlarmz yazdk. Ancak gerek


hayat byle deildir; bir fonksiyona farkl farkl boyutlarda diziler gndermeniz gerekir. Mesela
ortalama_bul( ) fonksiyonu hem 8 elemanl bir diziye hizmet edecek, hem de 800 elemanl bir
baka diziye uyacak ekilde yazlmaldr. Son rneimizi her boyutta dizi iin kullanlabilecek hle
getirelim ve ortalama_bul( ), minimum_bul( ) ve maksimum_bul( ) fonksiyonlarn biraz
deitirelim.
#include<stdio.h>
float maksimum_bul( float [ ], int );
float minimum_bul( float [ ], int );
float ortalama_bul( float [ ], int );
int main( void )
{
// 8 boyutlu bir dizi olusturup buna
// keyfi degerler atiyoruz.
float sayilar[ 8 ] = { 12.36, 4.715, 6.41, 13,
1.414, 1.732, 2.236, 2.645 };
float max, min, ortalama;
// Ornek olmasi acisindan fonksiyonlar
// kullaniliyor.
max = maksimum_bul( sayilar, 8 );
min = minimum_bul( sayilar, 8 );
ortalama = ortalama_bul( sayilar, 8 );
printf( "Maksimum: %.2f\n", max );
printf( "Minimum: %.2f\n", min );
printf( "Ortalama: %.2f\n", ortalama );
return 0;
}
/* Dizi icindeki maksimum degeri bulur */
float maksimum_bul( float dizi[ ], int eleman_sayisi )

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 ];
}

return ortalama / 8.0;

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.

Dizilere Pointer ile Eriim


Pointer'larn deikenleri iaret etmesini geen dersimizde ilemitik. Benzer ekilde dizileri de
iaret edebilirler. rnein, int dizi[6]; eklinde tanmlanm bir diziyi, pointer ile iaret etmek
istersek, ptr = dizi; yazmamz yeterlidir. Deikenlerde, deiken adnn bana '&' iareti
getiriyorduk, fakat dizilerde buna gerek yoktur. nk dizilerin kendisi de bir pointer'dr. Dizilerin
hepsi hafza alannda bir balang noktas iaret eder. rnek olmas asndan bu noktaya 6066
diyelim. Siz "dizi[0]" dediiniz zaman 6066 ile 6068 arasnda kalan blgeyi kullanrsnz. Ya da
"dizi[4]" dediiniz zaman 6074 ile 6076 hafza blgesi ileme alnr.
Bir diziyi iaret eden pointer aynen dizi gibi kullanlabilir. Yani ptr = dizi; komutunu vermenizden
sonra, ptr[0] ile dizi[0] birbirinin aynsdr. Eer *ptr yazarsanz, yine dizinin ilk eleman dizi[0]'
iaret etmi olursunuz. Ancak dizi iaret eden pointer'lar genellikle, *( ptr + 0 ) eklinde kullanlr.
Burada 0 yerine ne yazarsanz, dizinin o elemann elde ederseniz. Diyelim ki, 5.eleman ( yani
dizi[ 4 ] ) kullanmak istiyorsunuz, o zaman *( ptr + 4 ) yazarsanz. Bir resim, bin szden iyidir...
Aadaki resmi incelerseniz, durumu daha net anlayacanz dnyorum.

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;

Dizilerin fonksiyonlara gnderilmesini grmtk. Parametre ksmna dizinin tipini ve boyutunu


yazyorduk. Ancak bunun yerine pointer da kullanabiliriz. rnein aadaki iki komut satr
birbirinin aynsdr.
int toplam_bul( int dizi[ ], int boyut );
int toplam_bul( int *dizi, int boyut );

Fonksiyondan Dizi Dndrmek


Fonksiyondan bir diziyi dndrmeden nce nemli bir konuyla balayalm. Hatrlarsanz
fonksiyonlara iki ekilde argman yolluyorduk. Birinci yntemde, sadece deer gidiyordu ve
deiken zerinde bir deiiklik olmuyordu. ( Call by Value ) kinci yntemdeyse, yollanlan
deiken, fonksiyon iersinde yapacanz ilemlerden etkileniyordu. ( Call by Reference ) Dizilerin
aktarlmas, referans yoluyla olur. Fonksiyon iersinde yapacanz bir deiiklik, dizinin aslnda da
deiiklie sebep olur. Aadaki rnee bakalm:
#include<stdio.h>
/* Kendisine verilen dizinin butun
elemanlarinin karesini alir */
void karesine_donustur( int [ ], int );
int main( void )
{
int i;
int liste[ ] = { 1,2,3,4,5,6,7 };
for( i = 0; i < 7; i++ ) {
printf( "%d ", liste[ i ] );
}
printf("\n");
// Fonksiyonu cagiriyoruz. Fonksiyon geriye
// herhangi bir deger dondurmuyor. Diziler
// referans yontemiyle aktarildigi icin dizinin
// degeri bu sekilde degismis oluyor.
karesine_donustur( liste, 7 );
for( i = 0; i < 7; i++ ) {
printf( "%d ", liste[ i ] );
}
printf("\n");
return 0;
}
void karesine_donustur( int dizi[ ], int boyut )
{
int i;

for( i = 0; i < boyut; i++ ) {


dizi[ i ] = dizi[ i ] * dizi[ i ];
}

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;
}

Neyin nasl olduunu sanrm anlamsnzdr. Diziler referans yoluyla gnderilirken ve


gnderdiimiz dizilerin boyutlar belliyken, neden bir de iin iine pointer'lar soktuumuzu

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

// kucuk bir degeri varsa, elemanlarin


// degerleri yer degistirir.
for( j = boyut - 1; j > i; j-- ) {
if( dizi[ j ] < dizi[ j - 1 ] ) {
temp = dizi[ j -1 ];
dizi[ j - 1 ] = dizi[ j ];
dizi[ j ] = temp;
}
}
}

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.

ok Boyutlu Dizilere lk Deer Atama


ok boyutlu bir diziyi tanmlarken, eleman deerlerini atamak mmkndr. Aadaki rnei
inceleyelim:
int tablo[3][4] = { 8, 16, 9, 52, 3, 15, 27, 6, 14, 25, 2, 10 };

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.

Fonksiyonlara 2 Boyutlu Dizileri Aktarmak


ki boyutlu bir diziyi fonksiyona parametre gndermek, tek boyutlu diziyi gndermekten farkl
saylmaz. Tek fark dizinin iki boyutlu olduunu belirtmemiz ve ikinci boyutun elemann mutlaka
yazmamzdr. Basit bir rnek yapalm; kendisine gnderilen iki boyutlu bir diziyi matris eklinde
yazan bir fonksiyon oluturalm:
#include<stdio.h>
/* Parametre tanimlamasi yaparken, iki boyutlu dizinin
satir boyutunu girmemize gerek yoktur. Ancak sutun
boyutunu girmek gerekir.
*/
void matris_yazdir( int [ ][ 4 ], int );
int main( void )
{
// Ornek olmasi acisindan matrise keyfi
// degerler atiyoruz. Matrisimiz 3 satir
// ve 4 sutundan ( 3 x 4 ) olusuyor.
int matris[ 3 ][ 4 ] = {
{10, 15, 20, 25},
{30, 35, 40, 45},
{50, 55, 60, 65} };
// Matris elemanlarini yazdiran fonksiyonu
// cagriyoruz.
matris_yazdir( matris, 3 );
return 0;
}
void matris_yazdir( int dizi[ ][ 4 ], int satir_sayisi )
{
int i, j;
for( i = 0; i < satir_sayisi; i++ ) {
for( j = 0; j < 4; j++ ) {
printf( "%d ", dizi[ i ][ j ] );
}
printf( "\n" );
}
}

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

says 4 olduu srece...

2 Boyutlu Dizilerin Hafza Yerleimi


Dizilerin ok boyutlu olmas sizi yanltmasn, bilgisayar hafzas tek boyutludur. ster tek boyutlu
bir dizi, ister iki boyut ya da isterseniz 10 boyutlu bir dizi iersinde bulunan elemanlar, birbiri pei
sra gelen bellek hcrelerinde tutulur. ki boyutlu bir dizide bulunan elemanlarn, hafzada nasl
yerletirildiini aadaki grafikte grebilirsiniz.

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

// dusunulebilir ve her satir tek boyutlu bir dizi olarak


// ele alinabilir. Once her satirin baslangic adresini
// gosteriyoruz. Sonra satirlari tek boyutlu dizi seklinde
// satir_goster( ) fonksiyonuna gonderiyoruz.
printf( "\nTablo satrlarnn balang adresleri: \n");
for( i = 0; i < 5; i++ )
printf( "tablo[%d]'nin balang adresi %p\n", i, tablo[i] );
printf( "\nsatir_goster( ) fonksiyonuyla, "
"tablo elemanlar ve hafza adresleri:\n");
for( i = 0; i < 5; i++ )
satir_goster( tablo[i] );
}
// Kendisine gonderilen tek boyutlu bir dizinin
// elemanlarini yazdirir.
void satir_goster( int satir[ ] )
{
int i;
for( i = 0; i < 4; i++ ) {
printf( "%d (%p) ", satir[i], &satir[i] );
}
printf( "\n" );
}

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} };

// Cok boyutlu dizinin baslangic


// adresini bir pointer'a atiyoruz.
int *p = tablo[0];
// p isimli pointer'i tek boyutlu
// bir dizi gibi kullanabiliriz.
// Ayni zamanda p uzerinde yapacagimiz
// degisikler, tablo'yu da etkiler.
for( i = 0; i < 5*4; i++ )
printf( "%d\n", p[i] );
}

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;

// Tablo elemanlarinin adreslerini gosteriyor


// gibi gozukse de, gosterilen adresler Kanada,
// ABD, Meksika, Rusya ve Japonya dizilerinin
// eleman adresleridir.
for( i = 0; i < 5; i++ ) {
for( j = 0 ; j < 8; j++ )
printf( "%p\n", &tablo[i][j] );
}
return 0;

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];

int *tablo[ ] = { Kanada, ABD, Meksika, Rusya, Japonya };


// Adresleri gostermesi icin adresleri_goster( )
// fonksiyonunu cagriyoruz.
adresleri_goster( tablo );
return 0;
}
void adresleri_goster( int *dizi[ ] )
{
int i, j;
for( i = 0; i < 5; i++ ) {
for( j = 0 ; j < 8; j++ )
printf( "%p\n", &dizi[ i ][ j ] );
}
}

Dinamik Bellek Ynetimi


Dizileri etkin bir biimde kullanmay rendiinizi ya da reneceinizi umuyorum. Ancak
dizilerle ilgili ilememiz gereken son bir konu var: Dinamik Bellek Ynetimi...
imdiye kadar yazdmz programlarda ka eleman olaca nceden belliydi. Yani snf listesiyle
ilgili bir program yazacaksak, snfn ka kii olduunu biliyormuuz gibi davranyorduk.
Programn en banda ka elemanlk alana ihtiyacmz varsa, o kadar yer ayryorduk. Ama bu
gerek dnyada karmza kacak problemler iin yeterli bir yaklam deildir. rnein bir snfta
100 renci varken, dier bir snfta 50 renci olabilir ve siz her ortamda alsn diye 200 kiilik
bir st snr koyamazsnz. Bu, hem hafzann verimsiz kullanlmasna yol aar; hem de karma
eitimlerin yapld baz fakltelerde say yetmeyebilir. Statik bir ekilde dizi tanmlayarak bu
sorunlarn stesinden gelemezsiniz. zm dinamik bellek ynetimindedir.
Dinamik bellek ynetiminde, dizilerin boyutlar nceden belirlenmez. Program aknda dizi
boyutunu ayarlarz ve gereken bellek miktar, program alrken tahsis edilir. Dinamik bellek
tahsisi iin calloc( ) ve malloc( ) olmak zere iki nemli fonksiyonumuz vardr. Bellekte yer
ayrlmasn bu fonksiyonlarla salarz. Her iki fonksiyon da stdlib ktphanesinde bulunur. Bu
yzden fonksiyonlardan herhangi birini kullanacanz zaman, programn bana
#include<stdlib.h> yazlmas gerekir.
calloc( ) fonksiyonu aadaki gibi kullanlr:
isaretci_adi = calloc( eleman_sayisi, her_elemanin_boyutu );

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;

// Dizimizin kac elemanli olacagini


// eleman_sayisi isimli degiskende
// tutuyoruz.
int eleman_sayisi;
int i;
// Kullanicidan eleman sayisini girmesini
// istiyoruz.
printf( "Eleman saysn giriniz> ");
scanf( "%d", &eleman_sayisi );
// calloc( ) fonksiyonuyla dinamik olarak
// dizimizi istedigimiz boyutta yaratiyoruz.
dizi = calloc( eleman_sayisi, sizeof( int ) );
// Ornek olmasi acisindan dizinin elemanlarini
// ekrana yazdiriliyor. Dizilerde yapabildiginiz
// her seyi hicbir fark olmaksizin yapabilirsiniz.
for( i = 0; i < eleman_sayisi; i++ )
printf( "%d\n", dizi[i] );
// Dinamik olan diziyi kullandiktan ve isinizi
// tamamladiktan sonra free fonksiyonunu kullanip
// hafizadan temizlemelisiniz.
free( dizi );
return 0;
}

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 );

// malloc( ) fonksiyonuyla dinamik olarak


// dizimizi istedigimiz boyutta yaratiyoruz.
dizi = malloc( eleman_sayisi * sizeof( int ) );
for( i = 0; i < eleman_sayisi; i++ )
printf( "%d\n", dizi[i] );
// Dinamik olan diziyi kullandiktan ve isinizi
// tamamladiktan sonra free fonksiyonunu kullanip
// hafizadan temizlemelisiniz.
free( dizi );
return 0;
}

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" );

// Bu noktada matris ile isimiz bittiginden


// hafizayi bosaltmamiz gerekiyor. Oncelikle
// satirlari bosaltiyoruz.
for( i = 0; i < satir_sayisi; i++ ) {
free( matris[i] );
}
// Satirlar bosaldiktan sonra, matrisin
// bos oldugunu isaretliyoruz.
free( matris );
return 0;
}

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.

for( k = 0; k < boyut_2; i++, k++ ) {


sonuc[i] = dizi_2[k];
}
// Geriye sonuc dizisi gonderiliyor.
return sonuc;
}

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...

Katarlarda printf( ) ve scanf( ) Kullanm


Katarlarla, daha nce grdmz diziler arasnda bir farkn olmadn sylemtitik. Bu szmz,
teorik olarak doru olsa da, pratikte ufak tefek farklar kapsam d brakyor. Hatrlayacaksnz,
dizilerde elemanlara deer atama ya da onlardan deer okuma adm adm yaplan bir ilemdi.
Genellikle bir dng iersinde, her dizi eleman iin scanf( ) veya printf( ) fonksiyonunu
armamz gerekiyordu. Katarlar iin byle bir mecburiyet bulunmuyor. Tek bir kelimeyi, tek bir
scanf( ) fonksiyonuyla okutabilir ve elemanlara otomatik deer atayabilirsiniz. Yani "Merhaba"
eklinde bir girdi-input gelirse, 3.dizi eleman 'r' olurken; 6.dizi eleman 'b' olur. nceki dizilerde
grdmzn aksine, eleman atamalar kendiliinden gerekleir. Aadaki rnei inceleyelim:
#include<stdio.h>
int main( void )
{
char isim[30];
printf( "sim giriniz> ");
scanf( "%s", isim );
printf( "Girdiiniz isim: %s\n", isim );
return 0;
}

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 );

printf( "Girdiiniz isim: ");


for( i = 0; isim[i]!='\0'; i++ )
printf( "%c", isim[i] );
printf("\n");
return 0;
}

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( ) ve puts( ) Fonksiyonlar


Grdnz gibi ayn anda iki farkl kelime alp, ikisini birden yazdrdk. Fakat scanf( )
fonksiyonu "Bugn hava ok gzel." cmlesini tek bir katara alp, atamak iin hlen yetersizdir.
nk boluk grd noktada, veriyi almay keser ve sadece "Bugn" kelimesinin atamasn
yapar. Boluk ieren bu tarz cmleler iin puts( ) ve gets( ) fonksiyonlar kullanlmaktadr.
Aadaki rnek program, 40 harfi gemeyecek her cmleyi kabul edecektir:
#include<stdio.h>
int main( void )
{
char cumle[40];
printf( "Cmle giriniz> ");
gets( cumle );
printf( "Girdiiniz cmle:\n" );
puts( cumle );
return 0;
}

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.

Katarlara lk Deer Atama


Bir katar tanm yaptnz anda, katarn btn elemanlar otomatik olarak '\0' ile doldurulur. Yani
katarn btn elemanlarna bo karakter (NULL Character) atanr. Dilerseniz, katar yaratrken iine
farkl deerler atayabilirsiniz. Katarlarda ilk deer atamas iki ekilde yaplr.
Birinci yntemle deer atamas yapacaksanz, istediiniz kelimeyi bir btn olarak yazarsnz:
#include<stdio.h>
int main( void )
{
// Her iki katarada ilk deger
// atamasi yapiliyor. Ancak
// isim katarinda, boyut
// belirtilmezken, soyad katarinda
// boyutu ayrica belirtiyoruz.
char isim[] = "CAGATAY";
char soyad[5] = "CEBI";
printf( "%s %s\n", isim, soyad );
}

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...

Biimlendirilmi ( Formatl ) Gsterim


Daha nce float tipindeki bir saynn, noktadan sonra iki basaman gstermek trnden eyler
yapmtk. rnein printf( ) fonksiyonu iersinde, sayy %.2f eklinde ifade ederseniz, saynn
virglden sonra sadece iki basama gsterilir. Yada %5d yazarak tam saylar gsterdiiniz bir
durumda, say tek bir rakamdan dahi olusa, onun iin 5 rakamlk gsterim yeri ayrlr. Ayn ekilde
biimlendirilmi ( formatl ) gsterim, katarlarda da yaplmaktadr.
Katarlar biimlendirilmi ekilde gstermeyi, rnek zerinden anlatmak daha uygun olacaktr:
#include<stdio.h>
int main( void )
{
char cumle[20] = "Denemeler";
// Cumleyi aynen yazar:
printf( "%s\n", cumle );
// 20 karakterlik alan ayirir

// ve en saga dayali sekilde yazar.


printf( "%20s\n", cumle );
// 20 karakterlik alan ayirir
// ve en saga dayali sekilde,
// katarin ilk bes kelimesini
// yazar
printf( "%20.5s\n", cumle );
// 5 karakterlik alan ayirir
// ve en saga dayali sekilde yazar.
// Eger girilen kelime 5 karakterden
// buyukse, kelimenin hepsi yazilir.
printf( "%5s\n", cumle );
// 20 karakterlik alan ayirir
// ve sola dayali sekilde yazar.
// Sola dayali yazilmasi icin
// yuzde isaretinden sonra, // (eksi) isareti konulur.
printf( "%-20s\n", cumle );
}

return 0;

rneimizde bulunan formatlama biimlerini gzden geirirsek:


%20s, ekranda 20 karakter alan ayrlaca anlamna gelir. Katar, en saa dayanr ve
"Denemeler" yazlr.
%.5s olursa 5 karakterlik boluk ayrlr. Yzde iaretinden sonra nokta olduu iin katarn
sadece ilk be harfi yazdrlr. Yani sonu "Denem" olacaktr. %20.5s yazldnda, 20
karakterlik boluk ayrlmas istenmi ancak katarn sadece ilk 5 harfi bu boluklara
yazlmtr.
%5s kullanrsanz, yine 5 karakterlik boluk ayrlacaktr. Ancak yzdeden sonra nokta
olmad iin, katarn hepsi yazlr. Belirtilen boyutu aan durumlarda, eer noktayla snr
konmamsa, katar tamamen gsterilir. Dolaysyla kt, "Denemeler" eklinde olacaktr.
Anlattklarmzn hepsi, saa dayal ekilde kt retir. Eer sola dayal bir kt isterseniz,
yzde iaretinden sonra '-' (eksi) iareti koymanz gerekir. rnein %-20.5s eklinde bir
format belirlerseniz, 20 karakterlik boluk ayarlandktan sonra, sola dayal olarak katarn ilk
5 harfi yazdrlacaktr. mle ( cursor ), sa ynde 20 karakter sonrasna decektir.

Standart Katar Fonksiyonlar


Katarlarla daha kolay alabilmek iin, baz hazr ktphane fonksiyonlarndan bahsedeceiz. Bu
fonkisyonlar, string ktphanesinde bulunuyor. Bu yzden, programnzn bana,
#include<string.h> eklemeniz gerekiyor.
* strlen( ) fonksiyonuyla katar boyutu bulma
Dizi boyutuyla, katar uzunluunun farkl eyler olduundan bahsetmitik. Dizi boyutu, 40 karakter
olacak ekilde ayarlanmken, dizi iinde sadece 7 karakterlik "Merhaba" kelimesi tutulabilir. Bu
durumda, dizi boyutu 40 olmasna ramen, katar boyutu yalnzca 7'dir. Katarlarn boyutunu
saptamak iin, bo karakter ( NULL Character ) iaretinin yani "\0" simgesinin konumuna baklr.
Her seferinde arama yapmanza gerek kalmasn diye strlen( ) fonksiyonu gelitirilmitir. strlen( )
kendisine argman olarak gnderilen bir katarn boyutunu geri dndrr. Aadaki gibi
kullanlmaktadr:
#include<stdio.h>

#include<string.h>
int main( void )
{
printf( "Katar Uzunluu: %d\n", strlen("Merhaba") );
return 0;
}

* strcpy( ) ve strncpy( ) ile katar kopyalama


Bir katar, bir baka katara kopyalamak iin strcpy( ) fonksiyonunu kullanrz. Katarlar ayn
boyutta olmak zorunda deildir. Ancak kopya olacak katar, kendisine gelecek kelimeyi alacak
boyuta sahip olmaldr. Fonksiyon prototipi aadaki gibidir, geriye pointer dner.
char *strcpy( char[ ], char[ ] );

strcpy( ) fonksiyonunu bir rnekle grelim:


#include<stdio.h>
#include<string.h>
int main( void )
{
char kaynak[40]="Merhaba Dnya";
char kopya[30] = "";
strcpy( kopya, kaynak );
printf( "%s\n", kopya );
}

return 0;

strncpy( ) fonksiyonu, yine kopyalamak iindir. Fakat emsalinden farkl olarak, ka karakterin
kopyalanaca belirtilir. Protopi aada verilmitir:
char *strncpy( char[ ], char[ ], int );

Yukardaki rnei strncpy( ) fonksiyonuyla tekrar edelim:


#include<stdio.h>
#include<string.h>
int main( void )
{
char kaynak[40]="Merhaba Dnya";
char kopya[30] = "";
strncpy( kopya, kaynak, 9 );
printf( "%s\n", kopya );
}

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

Katar1 ve Katar2 birbirine eittir.


Katar1, Katar2'den byktr.

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;
}

Dilerseniz, strncat( ) fonksiyonunu da siz deneyebilirsiniz.

* strstr( ) fonksiyonuyla katar ii arama yapma


Bir katar iinde, bir baka katar aradnz durumlarda, strstr( ) fonksiyonu yardmnza yetiir.
strstr( ) fonksiyonu, bir katar iinde aradnz bir katar bulduu takdirde bunun bellekteki adresini
geriye dndrr. Yani dnen deer eidi bir pointer'dr. Eer herhangi bir eleme olmazsa geriye
bir sonu dnmez ve pointer null olarak kalr. Elbette insanlar iin hafza adreslerinin veya pointer
deerlerinin pek bir anlam olmuyor. Bir katar iinde arama yapyorsanz, aradnz yapnn katarn
neresinde olduunu tespit etmek iin aadaki kodu kullanabilirsiniz:
/* strstr( ) fonksiyon ornegi */
#include<stdio.h>
#include<string.h>
int main( void )
{
char adres[] = "Esentepe Caddesi Mecidiyekoy Istanbul";
char *ptr;
// 'adres' katari icinde, 'koy' kelimesini
// ariyoruz. Bu amacla strstr( ) fonksiyonunu
// kullaniyoruz. Fonksiyon buyuk-kucuk harf
// duyarlidir. Eger birden fazla eslesme varsa,
// ilk adres degeri doner. Hic eslesme olmazsa,
// pointer degeri NULL olur.
ptr = strstr( adres, "koy" );
if( ptr != NULL )
printf( "Balang notkas: %d\n", ptr - adres );
else
printf( "Eleme bulunamad.\n" );
return 0;
}

* strchr( ) ve strrchr( ) fonksiyonlar


strchr( ) ve strrchr( ) fonksiyonlar, tpk strstr( ) gibi arama iin kullanlr. Ancak strstr( )
fonksiyonu katar iinde bir baka katar arayabilirken, strchr( ) ve strrchr( ) fonksiyonlar katar
iinde tek bir karakter aramak iin kullanlr. strchr( ), karakterin katar iindeki ilk konumunu
gsterirken; strrchr( ) fonksiyonu, ilgili karakterin son kez getii adresi verir.
#include<stdio.h>
#include<string.h>
int main( void )
{
char adres[] = "Esentepe Caddesi Mecidiyekoy Istanbul";
char *ilk_nokta, *son_nokta;
ilk_nokta = strchr( adres, 'e' );
son_nokta = strrchr( adres, 'e' );
if( ilk_nokta != NULL ) {
printf( "Ilk gorundugu konum: %d\n", ilk_nokta - adres );
printf( "Son gorundugu konum: %d\n", son_nokta - adres );
}
else
printf( "Eleme bulunamad.\n" );
return 0;
}

* atoi( ) ve atof( ) ile katar dnm


Verilen katar, sayya evirmek gerekebilir. Eer elinizdeki metni, bir tam sayya ( int )
evirecekseniz, atoi( ) fonksiyonunu kullanmanz gerekir. ayet dnm sonunda elde etmek
istediiniz deiken tipi, virgll say ise ( float ), atof( ) fonksiyonu kullanlr. Her iki fonksiyon
stdlib.h ktphanesi iindedir. Bu fonksiyonlar kullanrken, #include<stdlib.h> komutunu program

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.

main( ) Fonksiyonuna Argman Aktarm


lediimiz btn derslerde main( ) fonksiyonu vard. main( ) fonksiyonuyla ilgili incelememizi
de, fonksiyonlarla ilgili dokuzuncu dersimizde yapmtk. Ancak main( ) fonksiyonuna hibir
zaman parametre aktarmadk; aksine parametre almayacan garantilemek iin srekli olarak
main( void ) eklinde yazmtk. Artk main( ) fonksiyonuna nasl parametre verileceini greceiz.
Aadaki kod, parametresi olan bir main( ) fonksiyonunu gstermektedir:
#include<stdio.h>
int main( int argc, int *arg[] )
{
int i;
for( i = 0; i < argc; i++ ) {
printf( "%d. argman: %s\n", i, arg[i] );
}
return 0;
}

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

Her iki iletim sisteminde elde edeceiniz sonu ayn olacaktr:


0.
1.
2.
3.
4.

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 altrmak iin u tarz bir komut verdiimizi dnelim:


$ ./hesapla 4 + 12

Program bu ekilde altrdnz zaman argmanlarn, parametrelere atanmas aadaki gibi olur:
arg[ 0 ]
./hesapla

arg[ 1 ] arg[ 2 ]
4
+

arg[ 3 ]
12

Btn fonksiyonlara, program iersinden argman aktarm yaparken; main( ) fonksiyonuna


program dndan deer gnderebiliyoruz. Unix komutlarnn hemen hemen hepsi bu ekildedir.
DOS komutlarnn birou da byle yazlmtr. main( ) fonksiyonun parametre alp almamas
gerektiine, ihtiyacnza gre sizin karar vermeniz gerekir.

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;
}

Soru 3: Aadaki gibi alp, kt retebilecek "ters_cevir" programn oluturunuz.


$ ./ters_cevir Merhaba Dunya Nasilsin?
abahreM aynuD ?nislisaN

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++ );

for( i = 0; i < boyut; i++ )


printf("%c", katar[ boyut - 1 - i ] );
printf(" ");

Yeni Deiken Tipi Oluturma


Kullandmz birok deiken tipi oldu. Tam saylar, karakterleri, virgll saylar, katarlar
grdk. Ancak kullanabileceimiz deiken tipleri bunlarla snrl deildir. Kendi deiken
tiplerimizi, yaratabiliriz. rnein boolean diye yeni bir tip yaratarak, bunun alabilecei deerleri
true ve false olarak belirleyebiliriz; nc bir ihtimal olmaz. Ya da mevsimler diye bir deiken
tipi belirleyip, alabilecei deerleri aylar olarak kstlayabiliriz. te bu tarz ilemleri yapmak iin
enum kullanlr. enum kelimesi, enumerator yani 'sayc', 'numaralandrmac'dan gelmektedir.
Hayat, rakamlarla ifade edilebilir. Bunun en bariz uygulamalarn programlama yaparken
grrsnz. Bir karakter olan A harfi, ASCII Tablo'da 65 saysna denk der; byk B harfiyse
66'dr ve bu byle devam eder. Bilgisayarnz iaretlerden, sembollerden, karakterlerden anlamaz.
Onun iin tek gereklik saylardr. te enum bu felsefeye hizmet ediyor. rnein doruyu
gstermek iin 1, yanl iinse 0' seersek; yeni bir deiken tipi belirlemi oluruz. Bilgisayar
dorunun ya da yanln ne olduunu bilmez, onun iin sadece 0 ve 1 vardr. Ancak insanlarn
yararna, okunurluu artan programlar ortaya kar. sterseniz, boolean diye tabir ettiimiz deiken
tipini oluturalm:
#include<stdio.h>
int main( void )
{
// Degisken tipinin nasil olacagini tanimliyoruz
enum boolean {
false = 0,
true = 1
};
// Simdi de 'dogru_mu' adinda bir degisken
// tanimliyoruz
enum boolean dogru_mu;
// Tanimladigimiz 'dogru_mu' degiskenine
// deger atayip, bir alt satirda da
// kontrol yapiyoruz.
dogru_mu = true;
if( dogru_mu == true )
printf( "Doru\n" );
return 0;
}

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;

// Degisken degeri karsilastiriliyor.


if( piksel == Kirmizi )
printf( "Krmz piksel\n" );
else if( piksel == Mavi )
printf( "Mavi piksel\n" );
else
printf( "Sar piksel\n" );
return 0;

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;
}

zel Deiken Tipleri ve Fonksiyonlar


enum konusu geniletilebilir. rnein enum tanmlamasn, global olarak yaparsanz, fonksiyon
parametresi olarak kullanabilirsiniz. ok basit bir fonksiyon oluturalm. Alaca deiken bilgisine
gre, ekrana ona dair bilgi yazdrlsn:
#include<stdio.h>
// Ay listesini olusturuyoruz. Ocak
// ayi 1 olacak sekilde, aylar sirayla
// numerik degerler aliyor.
enum ay_listesi {
ocak = 1, subat, mart, nisan,
mayis, haziran, temmuz, agustos,
eylul, ekim, kasim, aralik
};
// Degisken tanimlamasini kolaylastirmak
// icin typedef kullaniliyoruz. aylar diyerek
// tanimlama yapmak mumkun hale geliyor.
typedef enum ay_listesi aylar;
void ay_ismini_yazdir( aylar );
int main( void )
{
// aylar tipinde bir degisken
// yaratip, 'kasim' degerini atiyoruz.
aylar bu_ay = kasim;
// kasim, numerik olarak 11'i ifade edecektir.
printf( "%d. ay: ", bu_ay );
// fonksiyonumuzu cagiriyoruz.
ay_ismini_yazdir( bu_ay );
return 0;
}
// Kendisine verilen aylar tipindeki degiskene gore
// hangi ayin oldugunu ekrana yazmaktadir.
void ay_ismini_yazdir( aylar ay_adi )
{
switch( ay_adi ) {
case ocak: printf( "Ocak\n" );break;
case subat: printf( "ubat\n" );break;
case mart: printf( "Mart\n" );break;

case
case
case
case
case
case
case
case
case

nisan: printf( "Nisan\n" );break;


mayis: printf( "Mays\n" );break;
haziran: printf( "Haziran\n" );break;
temmuz: printf( "Temmuz\n" );break;
agustos: printf( "Austos\n" );break;
eylul: printf( "Eyll\n" );break;
ekim: printf( "Ekim\n" );break;
kasim: printf( "Kasm\n" );break;
aralik: printf( "Aralk\n" );break;

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

doum gnlerini soran bir program yazalm:


#include<stdio.h>
int main( void )
{
struct {
int yil;
int ay;
int gun;
} siz, kiz_kardes, erkek_kardes;
printf( "Doum gnnz giriniz> ");
scanf( "%d-%d-%d",
&siz.gun,
&siz.ay,
&siz.yil );
printf( "Kz kardeiniz> " );
scanf( "%d-%d-%d",
&kiz_kardes.gun,
&kiz_kardes.ay,
&kiz_kardes.yil );
printf( "Erkek kardeiniz> " );
scanf( "%d-%d-%d",
&erkek_kardes.gun,
&erkek_kardes.ay,
&erkek_kardes.yil );
return 0;
}

Eer yaplardan ( structures ) yararlanmasaydk; kiinin doum gn bilgilerini tutmak iin


toplamda 9 adet farkl deiken tanmlamak gerekecekti. Tanmlama zahmeti bir yana,
deikenlerin kartrlma ihtimali de ayr bir sknt yaratacakt. Sadece deiken olarak
dnmeyelim; nfus czdan bilgilerini soracamz bir program, yirminin zerinde deikene
ihtiya duyar. Bu kadar ok deiken barndrp, yaplar kullanmadan hazrlanacak bir program
grmek bile istemezsiniz.
Yaplar kullanmann bir dier avantaj, kopyalama konusundadr. rnein, sizin bilgilerinizi, erkek
kardeinize kopyalamak iin tek yapmanz gereken, "erkek_kardes = siz" yazmaktr. Bu basit ilem
ilgili btn deikenlerin kopyalamasn yapar.

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 );

printf( "Doum tarihi: ");


scanf( "%d-%d-%d",
&kisi.dogum_bilgileri.gun,
&kisi.dogum_bilgileri.ay,
&kisi.dogum_bilgileri.yil );
printf(
printf(
printf(
printf(

"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.

Yaplarda lk Deer Atama


Yaplarda da ilk deer atamas yapabilirsiniz. Aadaki rnek etiket kullanmadan oluturduunuz
yaplarda, ilk deer atamasnn nasl olduunu gstermektedir. 'kisi' isimli yap iersinde bulunan
isim ve boy deikenlerine srasyla Ali ve 167 deerleri atanmaktadr.
#include<stdio.h>
int main( void )
{
// kisi adinda bir yapi olusturulup
// baslangic degerleri 'Ali' ve '167'
// olacak sekilde atanir.
struct {
char isim[40];
int boy;
} kisi = { "Ali", 167 };
return 0;
}

Etiket kullanarak oluturduunuz yaplarda, ilk deer atamas deikenlerin tanmlanmas


aamasnda gerekleir. nce yapy kurar ve ardndan deiken tanmlarken, ilk deerleri atarsnz.
Kullanm aadaki kod iersinde grlmektedir:
#include<stdio.h>
int main( void )
{
// sahis_bilgileri adinda bir yapi
// olusturuyoruz
struct sahis_bilgileri {
char isim[40];
int boy;
};
// sahis_bilgileri yapisindan kisi adinda
// bir degisken tanimliyoruz. Tanimlama
// esnasinda atanacak ilk degerler belirleniyor.
struct sahis_bilgileri kisi = { "Ali", 167 };
return 0;
}

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

// 'dogum_tarihi' adinda bir yapi


// olusturuyoruz
struct dogum_tarihi {
int gun;
int ay;
int yil;
};
// Kisiye ait bilgileri tutmak
// icin 'sahis_bilgileri' adinda
// bir yapi kuruluyor.
struct sahis_bilgileri {
char isim[40];
int boy;
// Yapi icinde bir baska yapiyi
// kullanmak mumkundur. dogum_tarihi
// yapisindan 'tarih' adinda bir
// degisken tanimlaniyor.
struct dogum_tarihi tarih;
};
// Dizi elemanlarina ilk deger atamasi yapiyoruz. Dilerseniz
// klavyeden deger girmeyi tercih edebilirsiniz.
struct sahis_bilgileri kisi[3] = { "Ali", 170, { 17, 2, 1976 },
"Veli", 178, { 14, 4, 1980 },
"Cenk", 176, { 4, 11, 1983 } };
// Yapi dizisi yazdiriliyor:
for( i = 0; i < 3; i++ ) {
printf( "Kayt no.: %d\n", ( i + 1 ) );
printf( "Ad: %s\n", kisi[i].isim );
printf( "Boy: %d\n", kisi[i].boy );
printf( "Doum Tarihi: %d/%d/%d\n\n", kisi[i].tarih.gun,
kisi[i].tarih.ay,
kisi[i].tarih.yil );
}
return 0;
}

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.

Yap Dizilerine Pointer ile Eriim


Kambersiz dn olmaz. Ayn ekilde, dizilerden bahsettiimiz bir yerde pointer'lardan
bahsetmemek mmkn deil. Bir yap dizisinin balang adresini pointer'a atadnz takdirde,
elemanlara bu iareti zerinde de ulaabilirsiniz. Bir stteki rneimizi pointer'larla kullanalm:
#include<stdio.h>
int main( void )
{
int i;
// Dogum tarihi tutmak icin
// 'dogum_tarihi' adinda bir yapi
// olusturuyoruz
struct dogum_tarihi {
int gun;
int ay;
int yil;
};

// Kisiye ait bilgileri tutmak


// icin 'sahis_bilgileri' adinda
// bir yapi kuruluyor.
struct sahis_bilgileri {
char isim[40];
int boy;
// Yapi icinde bir baska yapiyi
// kullanmak mumkundur. dogum_tarihi
// yapisindan 'tarih' adinda bir
// degisken tanimlaniyor.
struct dogum_tarihi tarih;
};
struct sahis_bilgileri *ptr;
// Dizi elemanlarina ilk deger atamasi yapiyoruz. Dilerseniz
// klavyeden deger girmeyi tercih edebilirsiniz.
struct sahis_bilgileri kisi[3] = { "Ali", 170, { 17, 2, 1976 },
"Veli", 178, { 14, 4, 1980 },
"Cenk", 176, { 4, 11, 1983 } };
// Yapi dizisi yazdiriliyor:
for( i = 0, ptr = &kisi[0]; ptr <= &kisi[2]; ptr++, i++ ) {
printf( "Kayt no.: %d\n", ( i + 1 ) );
printf( "Ad: %s\n", ptr->isim );
printf( "Boy: %d\n", ptr->boy );
printf( "Doum Tarihi: %d/%d/%d\n\n", ptr->tarih.gun,
ptr->tarih.ay,
ptr->tarih.yil );
}
}

return 0;

Pointer'n tanmlamasn yaparken, 'sahis_bilgileri' ablonundan tretilen deikenlerin iaret


edileceini bildirmemiz gerekiyor. Yazm olduumuz "struct sahis_bilgileri *ptr;" kodu bundan
kaynaklanmaktadr. for dngsne gelirsek, kisi isimli yap dizisinin ilk elemannn adresini, ptr
iaretisine atadmz grmsnzdr. Her seferinde de, ptr deeri bir adres blou kadar
artmaktadr. Dngnn devam, adresin son dizi elemanndan kk olmasna baldr.
Kullandmz -> operatryse, pointer ile dizi elemanlarn gstermemizi salar. Bu cmleler size
muhtemelen kark gelecektir -ki bu kesinlike normal... nanyorum ki kodu incelerseniz, durumu
daha basit kavrarsnz.

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 )

struct sahis_bilgileri kisi;


kisi = bilgileri_al( );
bilgileri_goster( kisi );

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. )

Yaplarda typedef Kullanm


enum konusuna tekrar dnyoruz. Hatrlayacanz zere, typedef orada da gemiti. typedef
kullanarak her seferinde fazladan enum yazma zahmetinden kurtuluyorduk. typedef, yaplar iin de
kullanlmaktadr. Her defasnda tekrar tekrar struct yazmak yerine, bir kereye mahsus typedef
kullanarak bu zahmetten kurtulabilirsiniz. Aadaki gibi yazacanz kodla, tekrar tekrar struct
kelimesi kullanmanza gerek kalmayacaktr.
typedef struct sahis_bilgileri kisi_bilgileri;

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!

You might also like