Download as pdf or txt
Download as pdf or txt
You are on page 1of 529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

NDEKLER
Programlama ve C
Say Sistemleri
Genel Kavramler ve Terimler
Bir C Program Oluturmak
Veri Trleri
Bildirim ve Tanmlama
Deimezler
levler
leler
Bilinirlik Alan ve mr
Kontrol Deyimleri
if Deyimi
lev Bildirimleri
Tr Dnmleri
Dng Deyimleri
Koul leci
nilemci Komutlar - 1
Switch Deyimi
goto Deyimi
Rastgele Say retimi ve Kontrol Deyimlerine likin Genel Uygulamalar
Diziler
char Trden Diziler ve Yazlar
sizeof leci
Gstericiler
Gsterici leleri
Yazlarla lgili lem Yapan Standart levler
Gsterici Hatalar
void Trden Gstericiler
Dizgeler
Gsterici Dizileri
Gstericiyi Gsteren Gsterici
ok Boyutlu Diziler
exit, abort atexit levleri
Dinamik Bellek Ynetimi
Belirleyiciler ve Niteleyiciler
Yaplar
Tr simleri Bildirimleri ve typedef Belirleyicisi
Tarih ve Zaman ile lgili lem Yapan Standart levler
Birlikler
Numaralandrmalar
Bitsel leler
Bit Alanlar
Komut Satr Argmanlar
Dosyalar
Makrolar
nilemci Komutlar - 2
lev Gstericileri
zyinelemeli levler
Deiken Sayda Arguman Alan levler
Kaynaklar

1/529

3
15
25
31
33
39
45
53
73
93
101
102
119
127
137
159
165
175
185
189
199
215
226
229
235
265
280
283
291
301
307
311
321
323
341
359
387
397
411
421
427
441
445
451
485
495
505
519
525
529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

PROGRAMLAMA ve C
Yazlm Nedir

Yazlm (software), programlama ve programlamayla ilgili konularn geneline verilen


isimdir. Yazlm denince akla programlama dilleri bu diller kullanlarak yazlm kaynak
programlar ve oluturulan eitli dosyalar gelir.

Donanm Nedir

Donanm (hardware), bilgisayarn elektronik ksm, yapsna verilen isimdir.

Yazlmn Snflandrlmas

Yazlm uygulama alanlarna gre eitli gruplara ayrlabilir:

1. Bilimsel yazlmlar ve mhendislik yazlmlar


Bilimsel konularda ve mhendislik uygulamalarndaki problemlerin zlmesinde
kullanlan yazlmlardr. Bu tr yazlmlarda veri miktar greli olarak dktr ancak
matematiksel ve istatistiksel algoritmalar youn olarak kullanlr. Byle programlar
arlkl olarak hesaplamaya ynelik ilemler ierir ve bilgisayarn merkezi ilem birimini
(CPU) youn bir biimde kullanr. Elektronik devrelerin zmn yapan programlar,
istatistik analiz paketleri, bu tr programlara rnek olarak verilebilir.
2. Uygulama yazlmlar
Veri taban arlkl yazlmlardr. Genel olarak verilerin yaratlmas, ilenmesi ve
dosyalarda saklanmas ile ilgilidir. Bu tr programlara rnek olarak stok kontrol
programlar, mteri izleme programlar, muhasebe programlar verilebilir.
3. Yapay zeka yazlmlar
nsann dnsel ya da renmeye ynelik davranlarn taklit eden yazlmlardr. rnek
olarak robot yazlmlar, satran ya da bri oynatan programlar vs. verilebilir.
4. Grntsel yazlmlar
Grntsel ilemlerin ve algoritmalarn ok youn olarak kullanld programlardr. rnek
olarak oyun ve canlandrma (animasyon) yazlmlar verilebilir. Bu yazlmlar arlkl
olarak bilgisayarn grafik arabirimini kullanr.
5. Simlasyon yazlmlar
Bir sistemi bilgisayar ortamnda simle etmek iin kullanlan yazlmlardr.
6. Sistem yazlmlar
Bilgisayarn elektronik yapsn yneten yazlmlardr. Derleyiciler, haberleme
programlar, iletim sistemleri birer sistem yazlmdr. rnein bir metin ileme program
da bir sistem yazlmdr. Uygulama programlarna gre daha dk dzeyli ilem
yaparlar.

Programlama Dillerinin Deerleme ltleri

Kaynaklar u an halen kullanmda olan yaklak 1000 - 1500 programlama dilinin


varlndan sz ediyor. Neden bu kadar fazla programlama dili var? Bu kadar fazla
programlama dili olmasna karn neden halen yeni programlama dilleri tasarlanyor? Bir
programlama dilini dierine ya da dierlerine gre farkl klan zellikler neler olabilir? Bir
programlama dilini tanmlamak gerekirse hangi niteleyiciler kullanlabilir? Bu sorulara
yant verebilmek iin deerlendirme yapmaya olanak salayan ltler olmaldr. Aada
bu ltler ksaca inceleniyor:

3/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Seviye

Bir programlama dilinin seviyesi (level) o programlama dilinin insan algsna ya da


makineye yaknlnn lsdr. Bir programlama dili insan alglasna ne kadar yaknsa
o kadar yksek seviyeli (high level) demektir. Yine bir programlama dili bilgisayarn
elektronik yapsna ve alma biimine ne kadar yaknsa o kadar dk seviyeli (low
level) demektir.
Bilgisayarn ilemcisinin anlad bir "komut takm" (instruction set) vardr. lemci
yalnzca kendi komut takm iinde yer alan komutlar altrabilir. Programlama dilinde
yazlan metin, baz sreler sonunda bilgisayarn ilemcisinin komut takmnda yer alan
komutlara dntrlr.
Yksek seviyeli dillerle almak programc asndan kolaydr, iyi bir algoritma bilgisi
gerektirmez. Bu dillerde yalnzca nelerin yaplaca programa bildirilir ama nasl
yaplaca bildirilmez. Genel olarak programlama dilinin dzeyi ykseldike, o dilin
renilmesi ve o dilde program yazlmas kolaylar.
Makine dili bilgisayarn doal dilidir, bilgisayarn donanmsal tasarmna baldr.
Bilgisayarlarn gelitirilmesiyle birlikte onlara i yaptrmak iin kullanlan ilk diller, makine
dilleri olmutur. Bu yzden makine dillerine birinci kuak diller de denir.
Makine dilinin programlarda kullanlmasnda karlalan iki temel sorun vardr. Makine
dilinde yazlan kodlar dorudan makinenin ilemcisine, donanm paralarna verilen
komutlardr. Deiik bir CPU kullanldnda ya da bellek dzenlemesi farkl bir ekilde
yapldnda artk program almaz, programn yeniden yazlmas gerekir. nk makine
dili yalnzca belirli bir CPU ya da CPU serisine uygulanabilir. Makine dili tanabilir
(portable) deildir. Dier nemli bir sorun ise, makine dilinde kod yazmann ok zahmetli
olmasdr. Yazmann ok zaman alc ve uratrc olmasnn yan sra yazlan program
okumak ya da alglamak da o denli zordur. zellikle program boyutu bydnde artk
makine dilinde yazlan programlar gelitirmek, bytmek, iyice karmak bir hale gelir.
Balangta yalnzca makine dili vard. Bu yzden makine dilleri 1. kuak diller olarak da
isimlendirilir. Yazlmn ve donanmn tarihsel geliimi iinde makine dilinden, insan
alglamasna ok yakn yksek seviyeli dillere (4. kuak diller) kadar uzanan bir sre sz
konusudur.
1950'li yllarn hemen balarnda makine dili kullanmnn getirdii sorunlar ortadan
kaldrmaya ynelik almalar younlat. Bu yllarda makine dillerinde yazlan programlar
bilgisayarn ok snrl olan belleine ykleniyor, byle altrlyordu. lk nce makine
dilinin alglanma ve anlalma zorluunu ksmen de olsa ortadan kaldran bir adm atld.
Simgesel makine dilleri gelitirildi. Simgesel makine dilleri (Assembly Languages) makine
komutlarndan birka tanesini paketleyen baz ksaltma szcklerden, komutlardan
oluuyordu. Simgesel makine dillerinin kullanm ksa srede yaygnlat. Ancak simgesel
makine dillerinin makine dillerine gre ok nemli bir dezavantaj sz konusuydu. Bu
dillerde yazlan programlar makine dilinde yazlan programlar gibi bilgisayarn belleine
ykleniyor ancak programn altrlma aamasnda yorumlayc (interpreter) bir
program yardmyla simgesel dilin komutlar, bilgisayar tarafndan komut komut makine
diline evriliyor ve oluan makine kodu altrlyordu. Yani bilgisayar, program alma
aamasnda nce yorumlayarak makine diline eviriyor, daha sonra makine diline
evrilmi komutlar yrtyordu. Programlar bu ekilde altrldnda neredeyse 30 kat
yavalyordu.
Bu dnemde zellikle iki yorumlayc program ne kmt: John Mauchly'nin UNIVAC 1
iin yazd yorumlayc (1950) ve John Backus tarafndan 1953 ylnda IBM 701 iin
yazlan "Speedcoding" yorumlama sistemi. Bu tr yorumlayclar, makine koduna gre
ok yava alsalar da programclarn verimlerini artryorlard. Ama zellikle eski makine
dili programclar, yorumlayclarn ok yava olduklarn, yalnzca makine dilinde yazlan
programlara gerek program denebileceini sylyorlard.
Bu sorunun da stesinden gelindi. O zamanlar iin ok parlak kabul edilebilecek fikir
uydu: Kodun her altrlmasnda yazlan kod makine diline evrileceine, gelitirilecek
bir baka program simgesel dilde yazlan kodu bir kez makine diline evirsin ve artk
program ne zaman altrlmak istense, bilgisayar, yorumlama olmakszn yalnzca
makine kodunu altrsn. Bu fikri Grace Hopper gelitirmiti. Grace Hopper'n buluuna

4/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

"compiler" derleyici ismi verildi. (Grace Hopper ayn zamanda Cobol dilini gelitiren
ekipten biridir, bug(bcek) szcn ilk olarak Grace Hopper kullanmtr.) Artk
programclar, simgesel szcklerden oluan Assembly programlama dillerini kullanyor,
yazdklar programlar derleyici tarafndan makine koduna dntrlyor ve makine kodu
eski hzndan bir ey yitirmeksizin tam hzla alyordu. Assembly diller 2. kuak diller
olarak tarihte yerini ald.
Assembly dillerinin kullanlmaya balamasyla bilgisayar kullanm hzla artt. Ancak en
basit ilemlerin bile bilgisayara yaptrlmas iin birok komut gerekmesi, programlama
srecini hzlandrma ve kolaylatrma araylarn balatt, bunun sonucunda da daha
yksek seviyeli programlama dilleri gelitirilmeye baland.
Tarihsel sre iinde Assembly dillerinden daha sonra gelitirilmi ve daha yksek seviyeli
diller 3. kuak diller saylr. Bu dillerin hepsi algoritmik dillerdir. Bugne kadar gelitirilmi
olan yzlerce yksek seviyeli programlama dilinden pek az bugne kadar varlklarn
srdrebilmitir. 3. kuak dillerin hemen hemen hepsi ana dilden tretilmitir. 3.
kuak dillerin ilkleri olan bu dil halen varlklarn srdrmektedir:
FORTRAN dili (FORmula TRANslator) karmak matematiksel hesaplamalar gerektiren
mhendislik ve bilimsel uygulamalarda kullanlmak zere 1954 - 1957 yllar arasnda IBM
firmas iin John Backus tarafndan gelitirildi. FORTRAN dili, youn matematik
hesaplamalarn gerektii bilimsel uygulamalarda halen kullanlmaktadr. FORTRAN dilinin
FORTRAN IV ve FORTRAN 77 olmak zere iki nemli srm vardr. Doksanl yllarn
balarnda FORTRAN - 90 isimli bir srm iin ISO ve ANSI standartlar kabul edilmitir.
FORTRAN dili, 3. kuak dillerin en eskisi kabul edilir.
COBOL (COmmon Business Oriented Language) 1959 ylnda, Amerika'daki bilgisayar
reticileri, zel sektr ve devlet sektrndeki bilgisayar kullanclarndan oluan bir grup
tarafndan gelitirildi. COBOL'un gelitirilme amac, veri ynetiminin gerektii ticari
uygulamalarda kullanlacak tanabilir bir programlama dili kullanmakt. COBOL dili de
halen yaygn olarak kullanlyor.
ALGOL (The ALGOritmick Language) 1958 ylnda Avrupa'da bir konsorsiyum tarafndan
gelitirildi. IBM Firmas FORTRAN dilini kendi donanmlarnda kullanlacak ortak
programlama dili olarak benimsediinden, Avrupa'llar da seenek bir dil gelitirmek
istemilerdi. ALGOL dilinde gelitirilen birok tasarm zellii, modern programlama
dillerinin hepsinde kullanlmaktadr.
60'l yllarn balarnda programlama dilleri zerinde yaplan almalar yapsal
programlama kavramn gndeme getirdi. PASCAL dili 1971 ylnda akademik evrelere
yapsal programlama kavramn tantmak iin Profesr Niclaus Wirth tarafndan gelitirildi.
Dilin yaratcs, dile matematiki ve filozof Blaise Pascal'n ismini vermitir. Bu dil, ksa
zaman iinde niversitelerde kullanlan programlama dili durumuna geldi.
Pascal dilinin ticari ve endstriyel uygulamalar desteklemek iin sahip olmas gereken bir
takm zelliklerden yoksun olmas, bu dilin kullanmn kstlamtr. Modula ve Modula-2
dilleri Pascal dili temel alnarak gelitirilmitir.
BASIC dili 1960'l yllarn ortalarnda John Kemeney ve Thomas Kurtz tarafndan
gelitirildi. BASIC isminin "Beginner's All Purpose Symbolic Instruction Code"
szcklerinin ba harflerinden oluturulduu sylenir. Yksek seviyeli dillerin en eski ve
en basit olanlarndan biridir. Tm basitliine karn, birok ticari uygulamada
kullanlmtr. BASIC dili de ANSI tarafndan standartlatrlmtr. Ancak BASIC dilinin ek
zellikler ieren srmleri sz konusudur. rnein Microsoft firmasnn kartt Visual
Basic diline nesne ynelimli programlamaya ilikin birok zellik eklendi. Daha sonra bu
dil Visual Basic dot Net ismini ald. Ayrca BASIC dilinin baz srmleri uygulama
programlarnda -rnein MS Excel ve MS Word programlarnda- kullancnn zelletirme
ve otomatikletirme amacyla yazaca makrolarn yazlmasnda kullanlan programlama
dili olarak da genel kabul grd.
ADA dili ise Amerikan Savunma Departman (Department of Defence -DoD) destei ile
70'li yllardan balanarak gelitirildi. DoD, dnyadaki en byk bilgisayar
kullanclarndan biridir. Bu kurum farkl yazlmsal gereksinimleri karlamak iin ok
sayda farkl programlama dili kullanyordu ve tm gereksinmelerini karlayacak bir dil
arayna girdi. Dilin tasarlanmas amacyla uluslararas bir yarma dzenledi. Yarmay
kazanan irket (CII-Honeywell Bull of France) Pascal dilini temel alarak balatt

5/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

almalarnn sonucunda Ada dilini gelitirdi. Ada dilinin dokmanlar 1983 ylnda
yaymland. Ada ismi, dnr Lord Byron'un kz olan Lady Ada Lovelace'n ismine
gndermedir. Ada Lovelace delikli kartlar hesap makinelerinde ilk olarak kullanlan
Charles Babbage'in yardmcsyd. Charles Babbage hayat boyunca "Fark Makinesi"
(Difference Engine) ve "Analitik Makine" (Analytical Engine) isimli makinelerin yapm
zerinde alt ama bu projelerini gerekletiremeden ld. Yine de gelitirdii tasarmlar
modern bilgisayarlarn atas kabul edilir. Ada Lovelace, Charles Babbage'n makinesi iin
delikli kartlar ve kullanlacak algoritmalar hazrlyordu. Lovelace'in 1800'l yllarn
banda ilk bilgisayar programn yazd kabul edilir. Ada genel amal bir dildir, ticari
uygulamalardan roketlerin ynlendirilmesine kadar birok farkl alanda kullanlmaktadr.
Dilin nemli zelliklerinden biri, gerek zaman uygulamalarna (real-time applications /
embedded systems) destek vermesidir. Baka bir zellii de yksek modler yaps
nedeniyle byk programlarn yazmn kolaylatrmasdr. Ancak byk, karmak
derleyicilere gereksinim duymas; C, Modula-2 ve C++ dillerine kar rekabetini
zorlatrmtr.
ok yksek seviyeli ve genellikle algoritmik yap iermeyen programlarn grsel bir
ortamda yazld diller ise 4. kuak diller olarak isimlendirilirler. Genellikle 4GL (fourth
generation language) olarak ksaltlrlar. nsan algsna en yakn dillerdir. RPG dili 4.
kuak dillerin ilki olarak kabul edilebilir. zellikle kk IBM makinelerinin kullanclar
olan irketlerin, rapor retimi iin kolay bir dil istemeleri zerine IBM firmas tarafndan
gelitirilmitir.
Programlama dilleri dzeylerine gre baz gruplara ayrlabilir:
ok yksek dzeyli diller ya da grsel diller ya da ortamlar (visual languages):
Access, Foxpro, Paradox, Xbase, Visual Basic, Oracle Forms.
Yksek dzeyli diller.
Fortran, Pascal, Basic, Cobol.
Orta dzeyli programlama dilleri:
Ada, C. (Orta seviyeli diller daha az kaypla makine diline evrilebildiinden daha hzl
alr.)
Dk dzeyli programlama dilleri:
Simgesel makine dili (Assembly language).
Makine dili:
En aa seviyeli programlama dili. Saf makine dili tamamen 1 ve 0 lardan oluur.

Okunabilirlik

Okunabilirlik (readability) kaynak kodun abuk ve iyi bir biimde alglanabilmesi


anlamna gelen bir terimdir. Kaynak kodun okunabilirlii sz konusu olduunda
sorumluluk byk lde program yazan programcdadr. Fakat yine verimlilikte olduu
gibi dillerin bir ksmnda okunabilirlii glendiren yap ve aralar bulunduu iin bu
zellik bir lde programlama dilinin tasarmna da baldr. En iyi program kodu,
sanld gibi "en zekice yazlm fakat kimsenin anlayamayaca" kod deildir. Birok
durumda iyi programclar okunabilirlii hibir eye feda etmek istemezler. nk
okunabilir bir program kolay alglanabilme zelliinden dolay yllar sonra bile
gncelletirmeye olanak salar. Birok programcnn ortak kodlar zerinde alt geni
kapsaml projelerde okunabilirlik daha da nem kazanr.
C'de okunabilirlik en fazla vurgulanan kavramlardan biridir. lerideki birok blmde
okunabilirlik konusuna sk sk deinildiini greceksiniz.

6/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Tanabilirlik

Tanabilirlik (portability) bir sistem iin yazlm olan kaynak kodun baka bir sisteme
gtrldnde, hatasz bir biimde derlenerek, doru bir ekilde altrlabilmesi
demektir.
Tanabilirlik standardizasyon anlamna da gelir. Programlama dilleri (ISO International
Standard Organization) ve ANSI (American National Standard Institute) tarafndan
standardize edilirler. lk olarak 1989 ylnda standartlar oluturulan C Dili, dier
programlama dillerinden daha tanabilir bir programlama dilidir.

Verimlilik

Verimlilik (Efficiency) bir programn hzl almas ve daha az bellek kullanma zelliidir.
Programn alma hz ve kulland bellek miktar pek ok etkene baldr. phesiz
kullanlan algoritmann da hz ve kullanlan bellek zerinde etkisi vardr. Programn
altrld bilgisayarn da doal olarak hz zerinde etkisi vardr. Verimlilik bir
programlama dilinde yazlm bir programn altrldnda kulland bellek alan ve
alma hz ile ilgili bir kstas olarak ele alnabilir. Verimlilik zerinde rol oynayabilecek
dier etkenler sabit brakldnda, kullanlan programlama dilinin tasarmnn da verim
zerinde etkili olduu sylenebilir. Bu adan bakldnda C verimli bir dildir.

Kullanm Alan

Baz diller zel bir uygulama alan iin tasarlanrlar. Sistem programlama Yapay zeka
uygulamalar, simlasyon uygulamalar, veritaban sorgulamalar, oyun programlarnn
yazm amacyla tasarlanan ve kullanlan programlama dilleri vardr. Baz diller ise daha
geni bir kullanm alanna sahiptir. rnein veritaban sorgulamalarnda kullanlmak zere
tasarlanan bir dil mhendislik uygulamalarnda da kullanlabilir.
C dili de bir sistem programlama dili olarak domasna karn, gl yapsndan dolay
ksa bir sre iinde genel amal bir dil haline gelmitir. Oysa PASCAL, BASIC ok daha
genel amal dillerdir.
C ana uygulama alan "sistem programcl" olan bir dildir. Ancak neredeyse tm
uygulama alanlar iin C dilinde programlar yazlmtr.

Uygulama Alanlarna Gre Snflandrma

Programlama dillerini uygulama alanlarna gre de gruplayabiliriz:

1. Bilimsel ve mhendislik uygulama dilleri:


Pascal, C, FORTRAN.
C Programlama dili niversitelerdeki akademik almalarda da youn olarak kullanlr.
2. Veri taban dilleri:
XBASE, (Foxpro, Dbase, CA-Clipper), Oracle Forms, Visual Foxpro.
3. Genel amal programlama dilleri:
Pascal, C, Basic.
4. Yapay zeka dilleri:
Prolog, Lisp
.
5. Simlasyon dilleri
GPSS, Simula 67
6. Makro Dilleri (Scripting languages)
awk, Perl, Python, Tcl, JavaScript.
7. Sistem programlama dilleri:
Simgesel makine dilleri, BCPL, C, C++, occam.
Gnmzde sistem yazlmlarn neredeyse tamamnn C dili ile yazldn syleyebiliriz.

7/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

rnek vermek gerekirse UNIX iletim sisteminin % 80'i C dili ile geri kalan ise simgesel
makine dili ile yazlmtr. Bu iletim sistemi ilk olarak BELL Laboratuarlarnda
oluturulmutur. Kaynak kodlar gizli tutulmam, bylece eitli kollardan gelitirilmesi
mmkn olmutur. Daha sonra gelitirilen UNIX bazl iletim sistemi uygulamalarna
deiik isimler verilmitir.
C bilimsel ve mhendislik alanlarna kullanlabilen genel amal bir sistem programlama
dilidir.

Alt Programlama Yetenei

Bir btn olarak zlmesi zor olan problemlerin paralara ayrlmas ve bu paralarn ayr
ayr zlmesinden sonra paralar arasndaki balantnn salanmas programlamada sk
bavurulan bir yntemdir. Bir programlama dili buna olanak salayan aralara sahipse
programlama dilinin alt programlama yetenei vardr denilebilir. Alt programlama
yetenei bir programlama dilinin, program paralar halinde yazmay desteklemesi
anlamna gelir.
Alt programlama Yapsal Programlama Teknii'nin de ayrlmaz bir parasdr. Alt
programlamann getirdii baz nemli faydalar vardr. Alt programlar kaynak kodun
klmesini salar. ok yinelenen ilemlerin alt programlar kullanlarak yazlmas
alabilir programn kodunu kltr. nk alt programlar yalnzca bir kere, alabilir
kod iine yazlr. Program kodu alt programn olduu yere atlatlarak bu blgenin
defalarca altrlmas salanabilir.
Alt programlama alglamay kolaylatrr, okunabilirlii artrr, ayn zamanda kaynak
kodun test edilmesini kolaylatrr, kaynak kodun daha kolay gncelletirilmesini salar.
Alt programlamann en nemli faydalarndan biri de oluturulan alt programlarn birden
fazla projede kullanlabilmesidir (reusability).
C alt programlama yetenei yksek bir dildir. C'de alt programlara ilev (function) denir.
levler C dilinin yap talardr.

renme ve retme Kolayl

Her programlama dilini renmenin ve renilen programlama dilinde uygulama


gelitirebilmenin zorluk derecesi ayn deildir. Genel olarak programlama dillerinin dzeyi
ykseldike, bu programlama dilini renme ve bakalarna retme kolaylar. Bugn
yaygn olarak kullanlan yksek dzeyli programl dillerinin bu derece tutulmasnn nemli
bir nedeni de bu dillerin ok kolay renilebilmesidir. Ancak yksek dzeyli dilleri
renerek yetkin bir beceri dzeyi kazanmakta da ou zaman baka zorluklar vardr.
Byle diller ok sayda hazr arac barndrrlar. rnein yksek dzeyli bir programlama
ortamnda, GUI'ye ilikin hazr bir men ubuunun zelliklerini deitirmeye ynelik
onlarca seenek sunulmu olabilir. Bu durumda programc, her bir seenein anlamn
renmek durumunda kalr. Yani baz durumlarda programlama dilinin seviyesinin
ykselmesi programc asndan bir algsal kolaylk getirmekle birlikte, programcya
zellikle hazr aralara ynelik bir renme yk getirir.

Programlama Tekniklerine Verilen Destekler

Programlamann tarihsel geliim sreci iinde, baz programlama teknikleri


(paradigmalar) ortaya kmtr. Programlamann ilk dnemlerinde yazlan programlarn
boyutlar ok kk olduundan, program yazarken zel bir teknik kullanmaya pek gerek
kalmyordu. nk bir program tek bir programcnn her ynyle stesinden gelebilecei
kadar kkt ve basitti. Bir programda deiiklik yapmann ya da bir programa ekleme
yapmann ciddi bir maliyeti yoktu.
Bilgisayar donanmndaki teknik gelimeler, insanlarn bilgisayar programlarndan
beklentilerinin artmas, bilgisayar programlarn ounlukla grsel arayzler kullanmalar,
program boyutlarnn giderek bymesine yol at. Programlarn bymesiyle birlikte,
program yazmaya ynelik farkl teknikler, yntemler gelitirildi. Bu tekniklere rnek
olarak, "prosedrel programlama", "modler programlama", "nesne tabanl
programlama", "nesneye ynelmi programlama", "trden bamsz programlama"
verilebilir.
8/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

"Prosedrel programlama" ile "yapsal programlama" ou zaman ayn anlamda kullanlr.


Yapsal programlama bir programlama tekniidir. Bugn artk hemen hemen btn
programlama dilleri yapsal programlamay az ok destekleyecek ekilde
tasarlanmaktadr. Yapsal programlama fikri 1960'l yllarda gelitirilmitir. Yapsal
programlama teknii drt ana ilke zerine kuruludur:
1. Bl ve stesinden gel (divide and conquer)
Tek bir btn olarak yazlmas zor olan programlar, daha kk ve stesinden daha kolay
gelinebilecek paralara blnrler. Yani program, blnebilecek kk paralarna ayrlr
(functional decomposition). Bu paralar alt program, ilev, prosedr, vs. olarak
isimlendirilir. Alt programlamann salad faydalar daha nce aklanmt.
2. Veri gizleme (Data hiding)
Yapsal programlama tekniinde, programn dier paralarndan ulalamayan, yalnzca
belli bir bilinirlik alan olan, yani kodun yalnzca belli bir ksmnda kullanlacak deikenler
tanmlanabilir. Bu tr deikenler genel olarak "yerel deikenler" (local variables) olarak
isimlendirilirler. Deikenlerin bilinirlik alanlarnn kstlanabilmesi hata yapma riskini
azaltt gibi, programlarn daha kolay deitirilebilmesini, program paralarnn baka
programlarda tekrar kullanabilmesini de salar. Alt programlarn, daha geni ekliyle
modllerin, bir ii nasl yapt bilgisi, o alt programn ya da modln kullancsndan
gizlenir. Kullanc (client) iin alt programn ya da modln ii nasl yapt deil, ne i
yapt nemlidir.
3. Tek giri ve tek k (single entry single exit)
Yapsal programlama tekniini destekleyen dillerde her bir altprogram parasna girmek
iin tek bir giri ve tek bir k mekanizmas vardr. Bu ara programn yukardan aa
olarak ak ile uyum halindedir. Program paralarna ancak tek bir noktadan girilebilir.
4. Dngler, dier kontrol yaplar
Yapsal programlama tekniinde dngler ve dier kontrol deyimleri sklkla kullanlr.
Artk kullanmda olan hemen hemen btn programlama dilleri az ya da ok yapsal
programlama tekniini destekler.
Nesneye ynelimli programlama
Nesneye ynelimlilik (object orientation) de bir programlama tekniidir.
Yapsal programlama teknii 1960l yllarda gndeme gelmiken, nesneye ynelimli
programlama teknii 1980'li yllarda yaygnlamtr.
Bu teknik, kaynak kodlarn ok bymesi sonucunda ortaya kan gereksinim yznden
gelitirilmitir. C dilinin tasarland yllarda, akla gelebilecek en byk programlarn bile
kaynak kodlar ancak birka bin satrd. Bilgisayar donanmndaki gelimeler, kullanclarn
bilgisayar programlarndan beklentilerinin artmas ve grafik arayznn etkin olarak
kullanlmasyla, bilgisayar programlarnn boyutu ok byd. Kullanmda olan birok
programn bykl yzbin satrlarla hatta milyon satrlarla llmektedir.
Nesneye ynelmi programlama teknii, hereyden nce byk programlarn daha iyi
yazlmas iin tasarlanm bir tekniktir. C dilinin yaratld yllarda byle bir tekniin
ortaya kmas sz konusu deildi, nk programlar bugnk llere gre zaten ok
kkt.
Nesneye ynelmi programlama tekniinde, programa ilikin veri ile bu veriyi ileyen
kod, nesne isimli bir birim altnda birletirilir. Yani bu tekniin yap talar nesnelerdir. Bu
tekniin prosedrel programlamada en nemli fark, programcnn programlama dilinin
dzleminde deil de dorudan problemin kendi dzleminde dnmesi, program
kurgulamasdr. Bu da gerek hayata ilikin bir problemin yazlmda ok daha iyi
modellenmesini salar.
Nesne ynelimli programlama tekniinin yaygn olarak kullanlmaya balanmasyla birlikte
birok programlama dilinin bnyesine bu tekniin uygulanmasn kolaylatrc aralar
eklenerek, yeni srmleri oluturulmutur. rnein C++ dili, C diline nesne ynelimli
programlama tekniini uygulayabilmek iin baz eklemelerin yaplmasyla gelitirilmitir.

9/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Benzer amala Pascal diline eklemeler yaplarak Delphi dili, Cobol dilinin yenilenmesiyle
Oocobol, ada dilinin yenilenmesiyle ise ada 95 dilleri gelitirilmitir.
Baz programlama dilleri ise dorudan nesneye ynelmi programlama tekniini
destekleyecek ekilde tasarlanarak gelitirilmitir. Byle dillere saf nesne ynelimli diller
de denir. rnein Java, Eiffel, C#, saf nesne ynelimli dillerdir.
zetle, bir programlama dili hakknda sorulacak sorulardan belki de en nemlilerinden
biri, o programlama dilinin belirli bir programlama tekniini destekleyen aralara sahip
olup olmaddr.
C dili, var olan aralaryla prosedrel programlama tekniine tam destek veren bir dildir.

Giri / k Kolayl

Sral, indeksli ve rastgele dosyalara erime, veritaban kaytlarn geri alma,


gncelletirme ve sorgulama yeteneidir. Veritaban programlama dillerinin (DBASE,
PARADOX vs.) bu yetenekleri, dierlerinden daha stndr. Bu dillerin en tipik
zelliklerini oluturur. Fakat C giri k kolayl gl olmayan bir dildir. C'de veri
tabanlarnn ynetimi iin zel ktphanelerin kullanlmas gerekir.

C Nasl Bir Programlama Dilidir

ncelenen kstaslardan sonra C dili belirli bir yere oturtulabilir:


C orta seviyeli bir programlama dilidir. Dier yapsal programlama dillerine gre C dilinin
seviyesi daha dktr. C dili hem yksek seviyeli dillerin kontrol deyimleri, veri yaplar
gibi avantajlarna sahipken hem de bitsel ileler gibi makine kodu deyimlerini yanstan
ilelere sahiptir. Yani C dili hem makinenin algsna hem de insann alglamasna yakn
bir dildir. C makineye yeterince yakndr ama programcya da uzak deildir. Tercih
edilmesinin ana nedenlerinden biri budur.
Bir program C dili kullanarak yazmak, ayn program makine dilinde yazmaya gre ok
daha kolay olmasna karn, C'de yazlm bir programn verimi ayn oranda dmez. C
dili verim asndan bakldnda birok uygulama iin, dorudan makine diline tercih
edilebilir. Makina dili yerine C dilinde programlama yaplmas oluturulan programn
verimini ok drmez.
C dilinin ana uygulama alan "Sistem programlama" dr. Sistem programlama ne
demektir? Donanmn ynetilmesi, ynlendirilmesi ve denetimi iin yazlan, dorudan
makinenin donanmla ilikiye giren programlara sistem program denir. rnein, iletim
sistemleri, derleyiciler, yorumlayclar, aygt srcleri (device drivers), bilgisayarlarn
iletiimine ilikin programlar, otomasyon programlar, sistem programlardr.
C'den nce sistem programlar assembly dillerle yazlyordu. Gnmzde sistem
programlarnn yazlmasnda C dilinin neredeyse tek seenek olduu sylenebilir. Bugn
cep telefonlarndan uaklara kadar her yerde C kodlar alyor.
C algoritmik bir dildir. C dilinde program yazmak iin yalnzca dilin szdizimini ve
anlamsal yapsn bilmek yetmez genel bir algoritma bilgisi de gerekir.
C dier dillerle kyaslandnda tanabilirlii ok yksek olan bir dildir. nk 1989
ylndan bu yana genel kabul grm standartlara sahiptir.
C ifade gc yksek, okunabilirlik zellii gl bir dildir. C dilinde yazlan bir metnin
okunabilirliinin yksek olmas szel bir dil olmasndan, insann kulland dile yakn bir
dil olmasndan deildir.
C ok esnek bir dildir. Dier dillerde olduu gibi programcya kstlamalar getirmez.
Makinann olanaklarn programcya daha iyi yanstr.
C gl bir dildir, ok iyi bir biimde tasarlanmtr. C'ye ilikin ilelerin ve yaplarn bir
ou daha sonra baka programlama dilleri tarafndan da benimsenmitir.
C verimli bir dildir. C de yazlan programlar dilin dzeyinin dk olmas nedeniyle hzl
alr. Verimlilik konusunda assembly diller ile rekabet edebilir.
C doal bir dildir. C bilgisayar sistemi ile uyum iindedir.
C kk bir dildir. Yeni sistemler iin derleyici yazmak zor deildir.
C nin standart bir ktphanesi vardr. Bu ktphane ile sk yaplan ilemler iin ortak bir
arayz salanmtr.
C'nin eitimi dier bilgisayar dillerine gre daha zordur.

10/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

C dili UNIX iletim sistemi ile btnleme iindedir. UNIX iletim sisteminde kullanlan
baz aralar kullancnn C dilini bildiini varsayar.
Dier tm bilgisayar programlama dillerinde olduu gibi C dilinin de zayf taraflar vardr.
Esnek ve gl bir dil olmas programcnn hata yapma riskini artrr. C dilinde yazlan
kodlarda yaplan yanllklarn bulunmas dier dillere gre daha zor olabilir.

C Programlama Dilinin Tarihi

C dilinin UNIX iletim sisteminin bir yan rn olarak doduu sylenebilir. nce Unix
iletim sisteminin tarihine deinelim:
1965 ylnda MITde MAC isimli bir proje gerekletirildi. MAC bir bilgisayar sisteminin
zaman paylamn salayan ilk projelerden biriydi. Bu proje ile ayn bilgisayar 30 a kadar
kullanc tarafndan paylalabiliyordu 160 ayr yazcy kullanmak da mmknd. Bu
projenin baarsndan cesaret alan MIT, General Electric ve Bell Laboratuarlar ile bir
ortak giriim oluturararak zaman paylaml yeni bir sistem oluturma almasna
balad. Bu projeye MULTICS (Multiplexed Information and Computing Service) ismi
verildi. Bell Laboratuarlar projenin yazlm ksmndan sorumluydu. 1969 ylnda Bell
Laboratuarlar proje sresinin uzamas ve proje maliyetinin yksek olmas nedeniyle
projeden ayrld.
1969 ylnda Bell Laboratuarlarnda Ken Thompson nclnde bir grup yeni bir
alternatif arayna girdi. MULTICS projesinde alan Ken Thompson ve ekip arkada
Dennis Ritchie bu konuda bir hayli deneyim kazanmt.
Thompson ve ekibi, insan ve makine arasndaki iletiimi kolaylatracak bir iletim sistemi
tasarmna giriti. letim sisteminin omurgas yazldnda MULTICS'e gnderme
yaplarak iletim sistemine Unix ismi verildi.
Bu yllarda programclar PL/1, BCPL gibi yksek seviyeli dilleri kullanyorlard.
Thompson DEC firmasnn ana bellei yalnzca 8K olan PDP 7 isimli bilgisayar zerinde
alyordu. Thompson 1960 l yllarda Martin Richards tarafndan gelitirilen BCPL dilini
kullanmakta deneyimliydi. Kendi dilini tasarlarken Thompson, 1960 yllarnn ortalarnda
Martin Richards tarafndan gelitirilmi BCPL dilinden yola kt. (BCPL = Business
Common Programming Language). Bu dil de CPL = Cambridge Programming
Language'den tretilmitir. CPL'in kayna da tm zamanlarn en eski ve en etkili
dillerinden biri olan ALGOL 60'dr. ALGOL 60, Pascal, ADA, Modula2 dillerinin de
atasdr. Bu dillere bu yzden C dilinin kuzenleri de diyebiliriz. Aada ALGOL 60 dil ailesi
grlyor:

11/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Thompson gelitirdii bu dilin ismini B koydu. Dennis Ritchie, UNIX projesine katlnca B
dilinde programlamaya balad. B dili daha da gelitirilmiti ve artk daha yeni bir
teknoloji olan Dec PDP-11 bilgisayarlarda alyordu. Thompson, UNIX iletim sisteminin
bir ksmn B dilinde yeniden yazd. 1971 ylna gelindiinde B dilinin PDP-11 bilgisayarlar
ve UNIX iletim sisteminin gelitirilmesi iin ok uygun olmad iyice ortaya kt. Bu
yzden Ritchie, B programlama dilinin daha ileri bir srmn gelitirmeye balad.
Oluturduu dili ilk nce NB (new B) olarak isimlendirdi. Ama gelitirdii dil B dilinden
iyice kopmaya ve ayr bir karakter gstermeye balaynca dilin ismini de C olarak
deitirdi. 1973 ylnda UNIX iletim sisteminin byk bir ksm C dili ile yeniden yazld.
Ken Thompson ve Dennis Ritchie
Unix letim Sistemi zerinde
alrken (Yl: 1972)
C'nin evrimi ve gelimesi 70'li
yllarda da srd. Ancak uzun bir
sre C dili dar bir evrede
kullanld. Geni kitleler tarafndan
tannmas ve kullanlmaya
balamas 1978 ylnda Dennis
Ritchie ve Brian Kernighan
tarafndan yazlan "The C
Programming Language" kitab ile
olmutur. Bu kitap ayn zamanda yazlm konusunda yazlan en iyi eserlerden biri olarak
deerlendirilmektedir. C standartlarnn oluturulmasna kadar olan dnemde bu kitap
ounluun benimsedii genel kabul gren gayri resmi (de facto) bir standart grevi de
grmtr. Bu kitap ksaca K&R (Kernighan & Ritchie) olarak isimlendirilmektedir.
1970'li yllarda C programclarnn says azd ve bunlardan
ou UNIX kullanclaryd. Ama artk 80'li yllar gelince
C'nin kullanm UNIX snrlarn at, farkl iletim sistemleri
iin alan derleyiciler piyasaya kt. C dili de IBM
PC'lerde youn olarak kullanlmaya balad.
C'nin hzl bir biimde yaygnlamas baz sorunlar da
beraberinde getirdi. Derleyici yazan firmalar, referans
olarak Ritchie ve Kernighan'n kitabn esas alyorlard ama
sz konusu kitapta baz noktalar ok da ayrntl bir
biimde aklanmamt. zellikle hangi noktalarn C dilinin
bir zellii hangi noktalarn ise UNIX iletim sisteminin bir
zellii olduu o kadar ak olmad iin bir takm
karklklar ortaya kyordu. Bylece derleyici yazanlarn
rnlerinde de farkllklar ortaya kyordu. Ayrca kitabn
yaynlanmasndan sonra da dilde bir takm gelitirmeler,
iyiletirmeler, deiiklikler yapld iin, birbirinden ok
farkl derleyiciler piyasada kullanlmaya balanmt.

Hangi C

C tek bir programlama dili olmasna karn C'nin farkl srmlerinden sz etmek olasdr:

Geleneksel C

C dili ilk olarak 1978 ylnda yaymlanan Dennis Ritchie ve Brian Kernighan tarafndan
yazlm "The C Programming Language" isimli kitapta anlatlmt. 1980'li yllarda C dili
bu kitapta anlatlan genel geer kurallara gre kullanld, derleyici yazan firmalar bu
kurallar esas aldlar. Bu dnem iinde kullanlan derleyiciler arasnda baz kural ve yorum
farkllklar olsa da ana kurallar zerinde bir genel bir uzlama olduu sylenebilir. C
dilinin standartlatrlmas srecine kadar kullanlan bu srme "Geleneksel C (Traditional

12/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

C)" ya da "Klasik C (Classic C)" denmektedir. phesiz C dilinin bu dneminde derleyici


yazan firmalar uzlalm kurallarn dnda kendi zel eklentilerini de dile katmaktaydlar.

Standart C (1989)

C dilinin standart hale getirilmesinin dilin ticari kullanmnn yaygnlamasna yardmc


olacan dnen Amerikan Ulusal Standartlar Enstits (ANSI) C dili ve ktphanesi iin
bir standart oluturmas amacyla 1982 ylnda bir komite oluturdu. Jim Brody
bakanlnda alan ve X3J11 numarasyla anlan bu komitenin oluturduu standartlar
1989 ylnda kabul edilerek onayland. Bu standardn resmi ismi American National
Standard X3.159-1989 olmakla birlikte ksaca ANSI C diye anlmaktadr.
ANSI C almas tamamlandnda bu kez uluslararas bir standart oluturmak amacyla
P.J.Plaguer bakanlnda oluturulan bir grup (ISO/IEC JTC1/SC22/WG14) ANSI
standartlarn uluslararas bir standarda dntrd. Baz kk biimsel deiiklikler
yaplarak oluturulan bu standardn resmi ismi ISO/IEC 9899:1990' dr. Bu standart daha
sonra ANSI tarafndan da kabul edilmitir. Ortak kabul gren bu standarda Standard C
(1989) ya da ksaca C89 denmektedir.
Geleneksel C' den C89' a geite nemli deiiklikler olmutur.

Standart C (1995)

1995 ylnda Wg14 komitesi C89 standartlar zerinde iki teknik dzeltme ve bir eklenti
yaymlad. Bu dzeltme notlar ve eklentiler ok nemli deiiklikler olarak
grlmemektedir. Bu dzeltmelerle deitirilmi standartlara "C89 with amendment 1" ya
da ksaca C95 denmektedir

Standart C (1999)

ISO/IEC standartlar belirli aralklarla gzden geirilmekte, gncellenmektedir. 1995


ylnda Wg14 kurulu C standartlar zerinde kapsaml deiiklikler ve eklentiler yapmak
zere bir alma balatt. alma 1999 ylnda tamamland. Oluturulan yeni standardn
resmi ismi ISO/IEC 9899:1999'dur. Ksaca C99 olarak anlmaktadr. Bu standart resmi
olarak daha nceki tm srmlerin yerine gemitir. Derleyici yazan firmalar
derleyicilerini yava yava da olsa bu standarda uygun hale getirmektedirler. C99
standartlar C89/C95'e birok eklenti salamtr. Bunlardan bazlar
-

Sanal saylarn doal tr olarak eklenmesi


Daha byk bir tamsay trnn eklenmesi
Deiken uzunlukta diziler
Boolean (Mantksal) veri tr
ngilizce olmayan karakter setleri iin daha kapsaml destek
Gerek say trleri iin daha iyi destek
C++ tarz aklama satrlar
satr ii (inline) ilevler

C99 ile getirilen deiiklikler ve eklentiler C95'e gre daha fazla ve nemlidir. Ancak C
dilinin doal yaps deitirilmemitir.

C++ Dili

C++ dili de 1980 li yllarn balarnda Bjarne Stroustrup tarafndan AT&T Bell
Laboratuarlar'nda gelitirildi. C++ dili C'den ayr, tamamyla baka bir programlama
dilidir. Dilin tasarmcs Bjarne Stroustoup, C'nin orta seviyeli zelliklerine baz eklemeler
yaparak, bata nesne ynelimli programlama teknii olmak zere baka programlama
tekniklerini de destekleyen ayr bir dil oluturdu.
C++ dili de dinamik bir gelime sreci sonunda 1998 ylnda standart haline getirildi.
Oluturulan resmi standardn ismi ISO/IEC 14882:1998'dir.
C++ birden fazla programlama tekniini destekleyen (multi-paradigm) bir dildir. Temel
szdizimi byk lde C dilinden alnmtr. Ancak szdizim zellikleri birbirine benzese

13/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

de dilin aralarnn kullanlma biimi C'den olduka farkldr. C++, C ile karlatrldnda
ok daha byk ve karmak bir dildir.
C++, C dilini de kapsayan bir st dil olarak dnlebilir. Eer baz noktalara dikkat
edilirse hem C dilinde hem de C++ dilinde geerli olabilecek programlar yazlabilir. C
dilinin byle kullanmna "clean C" ("Temiz C") denmektedir.

Hangi C'yi Kullanmal

Bu karar verilirken, uygulamann gelitirilecei alan iin nasl bir C derleyicisinin olduu
phesiz nemlidir. Karar verilmesinde bir dier etken de yazlan kodun ne seviyede
tanabilir olmasnn istendiidir. Seeneklerin aadakiler olduu dnlebilir:
1. C99. C dilinin son srm. C dilinin tm zelliklerini iermektedir. Ancak baz
derleyiciler bu srm henz desteklememektedir.
2. C89. En fazla kullanlan srmdr. Bu srm kullanldnda genellikle C95 eklentileri
de kullanlmaktadr.
3. Geleneksel C. Yeni programlarn yazlmasnda artk kullanlmasa da, eskiden yazlan
programlarn bakmnda kullanmak gerekebilir.
4. Temiz C (Clean C). Yani C dilinin ayn zamanda C++ diline uyumlu olarak kullanlmas.
C99 srm, C89 ve Klasik C ile genel olarak yukarya doru uyumludur. Yani Klasik C
programlar ve C89 programlar, C99 dilinin kurallarna gre derlendiinde ya deiiklik
yapmak gerekmez ya da ok az deiiklik yapmak gerekir. Bu deiiklikler iin nilemci
program (preprocessor) kullanlabilir.
Gemie doru uyumlu program yazmaksa ou zaman mmkn deildir.

Objective C - Concurrent C

C dilinin kullanm yaygnlatktan sonra C dilinden baka diller de tretilmitir:


Objective C dili, NeXT firmas tarafndan OpenStep iletim sistemi iin uyarlanmtr.
NeXT firmas daha sonra Apple firmas tarafndan satn alnmtr. Objective C dilinin
Apple firmasnn yeni kuak iletim sistemi olan Rhapasody iin temel gelitirme arac
olmas planlanmaktadr.
"Concurrent C" dili, Bell Laboratuarlarndan Dr. Narain Gehani ve Dr. William D.Roome
tarafndan gelitirilmitir. Daha ok, paralel programlamada kullanlmaktadr.

14/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

SAYI SSTEMLER
Gnlk hayatta onluk say sistemi kullanlr. Onluk say sisteminde bir saynn deeri
aslnda her bir basamak deerinin 10 saysnn sleriyle arpmlarndan elde edilen
toplam deeridir. rnein:
1273 = (3 * 1) + (7 * 10 ) + (2 * 100) + (1 * 1000)
Ancak bilgisayar sistemlerinde btn bilgiler ikilik say sisteminde (binary system) ifade
edilir.
Genel olarak say sistemi kalksa o say sisteminde o kadar simge bulunur.
rnein onluk say sisteminde 10 adet simge vardr:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9
Ayn ekilde ikilik say sisteminde yalnzca iki adet simge bulunur. Yani yalnzca 0 ve 1.

Birimler

kilik sistemde her bir basamaa (digit) 1 bit denir. Bit kelimesi binary digit
szcklerinden tretilmitir.
rnein 1011 says 4 bittir yani 4 bit uzunluundadr.
11011001 says 8 bittir.
8 bitlik bir byklk bir byte olarak isimlendirilir.
Kilo, byklk olarak 1000 kat anlamna gelir. Ancak bilgisayar alannda Kilo, 2'nin
1000'e en yakn ss olan 210 yani 1024 kat olarak kullanlr. Aada daha byk
birimlerin listesi veriliyor:
1
1
1
1
1
1
1
1

kilobyte
megabyte
gigabyte
terabyte
petabyte
exabyte
zettabyte
yottabyte

1
1
1
1
1
1
1
1

KB
MB
GB
TB
PB
EB
ZB
YB

1024
1024
1024
1024
1024
1024
1024
1024

byte
KB
MB
GB
TB
PB
EB
ZB

210
220
230
240
250
260
270
280

byte
byte
byte
byte
byte
byte
byte
byte

zellikle sistem programclnda daha kk birimlere de isim verilir:


4 bit
8 bit
16 bit
32 bit
64 bit

1
1
1
1
1

Nybble
byte
word
double word
quadro word

kilik Say Sistemine likin Genel lemler

Tamsay deerlerini gstermek iin ikilik say sistemi iki farkl biimde kullanlabilir. Eer
yalnzca sfr ve pozitif tamsaylar gsteriliyorsa, bu biimde kullanlan ikilik say sistemine
iaretsiz (unsigned) ikilik say sistemi denir. kilik say sisteminin negatif tamsaylar da
gsterecek biimde kullanlmasna, iaretli (signed) ikilik say sistemi denir.

kilik Say Sisteminden Onluk Say Sistemine Dnm

kilik say sisteminde ifade edilen bir saynn onluk say sistemindeki karln
hesaplamak iin en sadan balanarak btn basamaklar tek tek ikinin artan sleriyle
arplr. rnein:

15/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

1 0 1 1 = 1 * 20 + 1 * 21 + 0 * 22 + 1 * 23 = 11
0010 1001 = (1 * 1) + (1 * 8) + (1 * 32) = 41

MSD ve LSD

kilik say sisteminde yazlan bir saynn en solundaki bit, yukardaki rnekten de
grld gibi en yksek saysal deeri katar. Bu bite en yksek anlaml bit (most
significant digit) denir. Bu bit iin ounlukla "MSD" ksaltmas kullanlr.
kilik say sisteminde yazlan bir saynn en sandaki bit, yine yukardaki rnekten de
grld gibi en dk saysal deeri katar. Bu bite en dk anlaml bit (least
significant digit) denir. Bu bit iin ounlukla LSD ksaltmas kullanlr. rnek:
0101 1101 says iin
MSD = 0
LSD = 1
kilik say sisteminde yazlan bir saynn belirli bir bitinden sz edildiinde, hangi bitten
sz edildiinin doru bir ekilde anlalmas iin basamaklar numaralandrlr.
8 bitlik bir say iin, saynn en sandaki bit yani (LSD) saynn 0. bitidir. Saynn en
solundaki bit (yani MSD) saynn 7. bitidir.

Onluk Say Sisteminden kilik Say Sistemine Dnm

Say srekli olarak ikiye blnr. Her blmden kalan deer (yani 1 ya da 0)
oluturulacak saynn sfrnc bitinden balanarak, basamaklarn oluturur. Bu ilem 0
deeri elde edilinceye kadar srdrlr.
rnek olarak 87 says ikilik say sisteminde ifade edilmek istensin:
87 / 2 = 43 (kalan 1) Saynn 0. biti 1
43 / 2 = 21 (kalan 1) Saynn 1. biti 1
21 / 2 = 10 (kalan 1) Saynn 2. biti 1
10 / 2 = 5 (kalan 0) Saynn 3. biti 0
5 / 2 = 2 (kalan 1) Saynn 4. biti 1
2 / 2 = 1 (kalan 0) Saynn 5. biti 0
1 / 2 = 0 (kalan 1) Saynn 6. biti 1
87 = 0101 0111
kinci bir yntem ise, onluk say sisteminde ifade edilen saydan srekli olarak ikinin en
byk ssn karmaktr. karlan her bir s iin ilgili basamaa 1 deeri yazlr. Bu
ilem 0 says elde edilene kadar srdrlr.
Yine 87 says ikilik say sisteminde ifade edilmek istensin:
87 - 64
23 - 16
7 - 4
3 - 2
1 - 1

=
=
=
=
=

23
7
3
1
0

0100
0101
0101
0101
0101

0000
0000
0100
0110
0111

87 = 0101 0111

Bire Tmleyen

Bire tmleyen (one's complement) saynn tm bitlerinin tersinin alnmasyla elde edilen
saydr. Yani bire tmleyen, saydaki 1 bitlerinin 0, 0 bitlerinin 1 yaplmasyla elde edilir.
Bir saynn bire tmleyeninin bire tmleyeni saynn yine kendisidir.

kiye Tmleyen

Bir saynn bire tmleyeninin 1 fazlas saynn ikiye tmleyenidir (two's complement).

16/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yani nce saynn bire tmleyeni yukardaki gibi bulunur. Daha sonra elde edilen sayya 1
eklenirse saynn ikiye tmleyeni bulunmu olur.
kiye tmleyeni bulmak iin daha ksa bir yol daha vardr:
Saynn en sandan balayarak ilk kez 1 biti grene kadar -ilk grlen 1 biti dahilsaynn ayns yazlr, daha sonraki tm basamaklar iin basaman tersi (Yani 1 iin 0, 0
iin 1) yazlr. rnein:
1110 0100 saysnn ikiye tmleyeni
0101 1000 saysnn ikiye tmleyeni

0001 1100 dr.


1010 1000 dr.

Bir saynn ikiye tmleyeninin ikiye tmleyeni saynn kendisidir.

8 Bitlik Alana Yazlabilen En Kk ve En Byk Deer


8 bitlik bir alana yazlacak en byk tam say tm bitleri 1 olan saydr:

1111 1111 = 255


8 bitlik bir alana yazlacak en kk tam say tm bitleri 0 olan say, yani 0'dr:
0000 0000 = 0

Negatif Saylarn Gsterimi

Negatif tamsaylarn da ifade edildii ikilik say sistemine "iaretli ikilik say sistemi"
(signed binary system) denir.
aretli ikilik say sisteminde negatif deerleri gstermek iin hemen hemen tm
bilgisayar sistemlerinde aadaki yntem uygulanr:
Saynn en soldaki biti iaret biti (sign bit) olarak kabul edilir. aret biti 1 ise say negatif,
0 ise say pozitif olarak deerlendirilir. kilik sistemde bir negatif say, ayn deerdeki
pozitif saynn ikiye tmleyenidir. rnek olarak, ikilik sistemde yazlan 27 says yine
ikilik sistemde yazlan 27 saysnn ikiye tmleyenidir.
Pozitif olan saylarn deeri, tpk iaretsiz say sisteminde olduu gibi elde edilir:
rnein, 0001 1110 iaretli ikilik say sisteminde pozitif bir saydr. Onluk say sisteminde
30 saysna eittir.
Negatif tamsaylarn deeri ancak bir dnmle elde edilebilir.
Saynn deerini hesaplamak iin ilk nce saynn ikiye tmleyeni bulunur. Bu saynn
hangi pozitif deer olduu bulunur. Elde edilmek istenen say, bulunan pozitif say ile ayn
deerdeki negatif saydr.
rnein, 1001 1101 saysnn onluk say sisteminde hangi sayya karlk geldiini
bulalm:
aret biti 1 olduuna gre say negatiftir.
1001 1101 saysnn ikiye tmleyeni 0110 0011, yani 99 deeridir.
O zaman 1001 1101 says -99'dur.
Onluk say sisteminde ifade edilen negatif saylarn iaretli ikilik say sisteminde yazlmas
iin aadaki yol izlenebilir:
nce saynn ayn deerli fakat pozitif olan ikilik sistemde ifade edilir. Daha sonra yazlan
saynn ikiye tmleyeni alnarak, yazmak istenilen say elde edilir.
rnein, ikilik sisteminde 17 deerini yazalm:
17 = 0001 0001
Bu saynn ikiye tmleyeni alnrsa
1110 1111

17/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

says elde edilir.


Say deeri ayn olan negatif ve pozitif saylar birbirinin ikiye tmleyenidir.
Bu saylarn ikilik say sisteminde toplamlar 0'dr.
aretli ikilik say sisteminde 1 byte'lk alana yazlabilecek en byk ve en kk saylar
ne olabilir?
En byk say kolayca hesaplanabilir. Saynn pozitif olmas iin, iaret bitinin 0 olmas ve
say deerini en byk hale getirmek iin dier btn bitlerinin 1 olmas gerekir, deil
mi? Bu say 0111 1111'dr. Bu saynn onluk say sistemindeki karl 127'dir. Peki ya
en kk negatif say katr, nasl ifade edilir?
0111 1111 saysnn ikiye tmleyenini alndnda 127 says elde edilir.
1000 0001 (- 127)
Bu saydan hala 1 kartlabilir:
1000 0000 (-128)
1000 0000, 1 byte alana yazlabilecek en kk negatif saydr.
1 byte alana yazlabilecek en byk say snr aldnda negatif blgeye geilir.
En byk pozitif tamsayya 1 toplandn dnelim:
0111 1111
1
1000 0000

(en byk pozitif tamsay = 127)


(en kk tamsay = -128)

aretli ikilik sistemde n byte alana yazlabilecek en byk tamsayya 1 eklendiinde n


byte alana yazlabilecek en kk tamsay elde edilir.
n byte alana yazlabilecek en kk tamsaydan 1 karldnda da n byte alana
yazlabilecek en byk tamsay elde edilir.
Yukarda aklamalara gre -1 saysnn iaretli ikilik say sisteminde 8 bitlik bir alanda
aadaki ekilde ifade edilir:
-1 = 1111 1111
Yani iaretli ikilik say sisteminde tm bitleri 1 olan say -1'dir.

18/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Onaltlk ve Sekizlik Say Sistemleri

Onaltlk say sisteminde (hexadecimal system) saylar daha youn olarak kodlanp
kullanabilir.Onaltlk say sisteminde 16 simge bulunur.
lk 10 simge onluk sistemde kullanlanlarla ayndr:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9
Daha sonraki simgeler iin alfabenin ilk 6 harfi kullanlr:
A = 10, B = 11, C = 12, D = 13, E = 14, F = 15
Onaltlk say sisteminde yazlm bir sayy onluk sistemde ifade etmek iin, en sadan
balanarak basamak deerleri onaltnn artan sleriyle arplr:
01AF

= (15 * 1)

+ (10 * 16) + (1 * 256) + (0

* 4096) = 431

Onluk say sisteminde yazlm bir sayy, onaltlk say sisteminde ifade etmek iin onluk
say sisteminden ikilik say sistemine yaplan dnme benzer yntem kullanlabilir. Say
srekli 16'ya blnerek, kalanlar soldan saa doru yazlr.
Uygulamalarda onaltlk say sisteminin getirdii nemli bir fayda vardr: Onaltlk say
sistemi ile ikilik say sistemi arasndaki dnmler kolay bir biimde yaplabilir:
Onaltlk say sistemindeki her bir basamak ikilik say sisteminde 4 bitlik (1 Nibble) alanda
ifade edilebilir:
0000
0001
0010
0011
0100
0101
0110
0111

0
1
2
3
4
5
6
7

1000
1001
1010
1011
1100
1101
1110
1111

8
9
A
B
C
D
E
F

rnek olarak, 2ADF saysn ikilik say sisteminde ifade edilmek istensin:
2
A
D
F

=
=
=
=

0010
1010
1101
1111

Bu durumda
2ADF = 0010 1010 1101 1111
kilik say sisteminden onaltlk say sistemine de benzer ekilde dnm yaplabilir:
nce bitler sadan balayarak drder drder ayrlr. En son drt bit eksik kalrsa sfr ile
tamamlanr. Sonra her bir drtlk grup iin dorudan onaltlk say sistemindeki karl
yazlr:
1010 1110 1011 0001 = AEB1
0010 1101 0011 1110 = 2D3E
Onaltlk say sisteminde yazlm iaretli bir saynn pozitif mi negatif mi olduunu
anlamak iin saynn en soldaki basamana bakmak yeterlidir. Bu basamak [8 - F]
aralnda ise say negatiftir.

19/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Aada baz nemli iaretli tamsaylar, ikilik, onaltlk say sistemlerinde ifade ediliyor:
kilik say sistemi
0000 0000 0000 0000
0000 0000 0000 0001
0111 1111 1111 1111
1000 0000 0000 0000
1111 1111 1111 1111

onaltlk say sistemi


0000
0001
7FFF
8000
FFFF

onluk say sistemi


0
1
32767
-32768
-1

Sekizlik Say Sistemi

Daha az kullanlan bir say sistemidir. Sekizlik say sisteminde 8 adet simge vardr:
0 1 2 3 4 5 6 7
Sekizlik say sisteminin her bir basama, ikilik say sisteminde 3 bit ile ifade edilir.
001
010
011
100
101
110
111

1
2
3
4
5
6
7

Sekizlik say sisteminin kullanlma nedeni de, ikilik say sistemine gre daha youn bir
ifade biimine olanak vermesi, ikilik say sistemiyle sekizlik say sistemi arasnda
dnmlerin ok kolay bir biimde yaplabilmesidir.

20/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Gerek Saylarn Bellekte Tutulmas

Bir gerek say aadaki gibi ifade edilebilir:

x= s * b * f k * b k
e

k =1

Yukardaki genel denklemde


x
b
e
p
fk

ifade edilecek gerek say


Kullanlan say sisteminin taban deeri (Tipik olarak 2, 8, 10 ya da 16)
stel deer. Bu deer format tarafndan belirlenen emin ve emax arasndaki bir deer
Ondalk ksm belirleyen basamak says
Say sistemindeki basamak deerleri. 0 fk b

Gerek saylarn ifadesinde, gerek say kabul edilmeyen baz gsterimler sz konusudur.
Bunlar:
sonsuz (infinity)
NaN (not a number)
deerleridir. Bu deerler iaretli olabilir.
Sistemlerin ounda, gerek saylar IEEE (Institute of Electrical and Electronics
Engineers) 754 standardna gre tutulur. (IEEE Standard for Binary Floating-Point
Arithmetic - ISO/IEEE std 754-1985).Bu standarda gre gerek saylar iin iki ayr format
belirlenmitir:
1. Tek duyarlkl gerek say format (single precision format)
Bu formatta gerek saynn gsterimi genel formle aadaki biimde uyarlanabilir:

24

x= s * 2 * f k * 2k
e

k =1

Bu formatta gerek say 32 bit (4 byte) ile ifade edilir.


32 bit ayr ksma ayrlmtr.
i. aret biti (sign bit) (1 bit)
Aada S harfi ile gsterilmitir.
aret biti 1 ise say negatif, iaret biti 0 ise say pozitiftir.
ii. stel ksm (exponent) (8 bit)
Aada E harfleriyle gsterilmitir.
iii. Ondalk ksm (fraction) (23 bit)
Aada F harfleriyle gsterilmitir.
SEEEEEEEEFFFFFFFFFFFFFFFFFFFFFFF
Aadaki formle gre saynn deeri hesaplanabilir :
V, gerek saynn deeri olmak zere:
EEEEEEEE = 255 ve FFF...F 0 ise V = NaN (Not a number)

21/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

rnek :
0 11111111 00001000000100000000000 (Say deil)
1 11111111 00010101010001001010101 (Say deil)
EEEEEEEE = 255 ve FFF...F = 0 ve S = 1 ise
EEEEEEEE = 255 ve FFF...F = 0 ve S = 0 ise

V = -sonsuz
V = +sonsuz

0 < EEEEEEEE < 255 ise


V = (-1)S * 2(E - 127) * (1.FFF...F)
nce saynn ondalk ksmnn bana 1 eklenir. Daha sonra bu say 2(E - 127) ile arplarak
noktann yeri ayarlanr. Noktadan sonraki ksm ikinin artan negatif sleriyle arplarak
elde edilir. rnekler:
0 10000000 00000000000000000000000 = +1 * 2(128
= 2 * 1.0
= 10.00
= 2

- 127)

0 10000001 10100000000000000000000 = +1 * 2(129


= 22 * 1.101
= 110.100000
= 6.5

- 127)

1 10000001 10100000000000000000000 = -1 * 2(129


= -22 * 1.101
= 110.100000
= -6.5

- 127)

0 00000001 00000000000000000000000 = +1 * 2(1


= 2-126

- 127)

* 1.0

* 1.101

* 1.101

* 1.0

EEEEEEEE = 0 ve FFF...F 0 ise


V = (-1)S * 2-126 * (0.FFF...F)
rnekler :
0 00000000 10000000000000000000000 = +1 * 2-126 * 0.1
0 00000000 00000000000000000000001 = +1 * 2-126 * 0.00000000000000000000001
= 2-149 (en kk pozitif deer)
EEEEEEEE = 0 ve FFF...F = 0 ve S = 1 ise V = -0
EEEEEEEE = 0 ve FFF...F = 0 ve S = 0 ise V = 0
2. ift duyarlkl gerek say format (double precision format)
Bu formatta gerek saynn gsterimi genel formle aadaki biimde uyarlanabilir:

53

x= s * 2 * f k * 2 k
e

k =1

Bu formatta gerek say 64 bit yani 8 byte ile ifade edilir.


64 bit ayr ksma ayrlmtr.

22/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

i. aret biti (sign bit) (1 bit)


Aada S harfi ile gsterilmitir.
aret biti 1 ise say negatif, iaret biti 0 ise say pozitiftir.
ii. stel ksm (exponent) (11 bit)
Aada E harfleriyle gsterilmitir.
iii. Ondalk ksm (fraction) (52 bit)
Aada F harfleriyle gsterilmitir.
SEEEEEEEEEEEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
Aadaki formle gre saynn deeri hesaplanabilir, V saynn deeri olmak zere:
EEEEEEEEEEE = 2047 ve FFF...F 0 ise V = NaN (Not a number)
EEEEEEEEEEE = 2047 ve FFF...F = 0 ve S = 1 ise V = -sonsuz
EEEEEEEEEEE = 2047 ve FFF...F = 0 ve S = 0 ise V = +sonsuz
0 < EEEEEEEEEEE < 2047 ise V = (-1)S * 2(EEEEEEEEEEE

- 1023)

* (1.FFF...F)

nce saynn ondalk ksmnn bana 1 eklenir. Daha sonra bu say 2(EEEEEEEEEEE-123) ile
arplarak noktann yeri ayarlanr. Noktadan sonraki ksm, ikinin artan negatif sleriyle
arplarak elde edilir.
EEEEEEEEEEE = 0 ve FFF...F 0 ise V = (-1)S * 2-126 * (0. FFF...F)
EEEEEEEEEEE = 0 ve FFF...F = 0 ve S = 1 ise V = -0
EEEEEEEEEEE = 0 ve FFF...F = 0 ve S = 0 ise V = 0

23/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

GENEL KAVRAMLAR ve TERMLER


Atomlar ve Trleri

Bir programlama dilinde yazlm kaynak dosyann (program) anlaml en kk


paralarna "atom" (token) denir. Bir programlama dilinde yazlm bir metin, atomlardan
oluur.
Bir kaynak dosya, derleyici program tarafndan ilk nce atomlarna ayrlr. Bu ileme
"atomlarna ayrma" (Tokenizing - Lexical analysis) denir. Farkl programlama dillerinin
atomlar birbirlerinden farkl olabilir.
Atomlar aadaki gibi gruplara ayrlabilir:

1. Anahtar Szckler

Anahtar szckler (keywords - reserved words) programlama dili tarafndan nceden


belirlenmi anlamlara sahip atomlardr. Bu atomlar kaynak dosya iinde baka bir anlama
gelecek biimde kullanlamazlar. rnein bu atomlarn deiken ismi olarak kullanlmalar
geerli deildir.
Standard ANSI C (C 89) dilinin 32 anahtar szc vardr:
auto break case char const continue default do double else enum extern
float for goto if int long register return short signed sizeof static
struct switch typedef union unsigned void volatile while
Derleyici yazan firmalar da kendi yazdklar derleyiciler iin ek anahtar szckler
tanmlayabilir.
Baz programlama dillerinde anahtar szcklerin kk ya da byk harf ile yazlmas bir
anlam fark yaratmaz. Ama C'de btn anahtar szckler kk harf olarak
tanmlanmtr. C byk harf kk harf duyarl olan (case sensitive) bir dildir. Ama
dier programlama dillerinin ounda byk - kk harf duyarl yoktur (case
insensitive).
C dilinde rnein bir deikene "register" isminin verilmesi geerli deildir. nk
"register" bir anahtar szcktr, C dili tarafndan ayrlmtr. Ama buna karn bir
deikene REGISTER, Register, RegisTER isimleri verilebilir, nk bunlar artk anahtar
szck saylmazlar.

2. simler

Deikenler, ilevler, makrolar, deimezler gibi yazlmsal varlklara programlama dili


tarafndan belirlenmi kurallara uyulmak kouluyla isimler verilebilir. Yazlmsal bir varla
verilen isme ilikin atomlar isimlerdir (identifier).
Her programlama dilinde olduu gibi C dilinde de kullanlan isimlerin geerliliini
belirleyen kurallar vardr.

3. leler

leler (operators) nceden tanmlanm bir takm ilemleri yapan atomlardr.


rnein +, -, *, / , >=, <= birer iletir.
Programlama dillerinde kullanlan ile simgeleri birbirinden farkl olabilecei gibi, ile
tanmlamalar da birbirinden farkl olabilir. rnein birok programlama dilinde s alma
ileci tanmlanmken C dilinde byle bir ile yoktur. C'de s alma ilemi ile ile deil bir
standart ilev (function) yardmyla yaplr.
C dilinde baz ileler iki karakterden oluur. Bu iki karakter bitiik yazlmaldr. Aralarna
boluk karakteri koyulursa ile anlam yitirilir.
C dilinin 45 tane ileci vardr.

4. Deimezler

Deimezler (constants) dorudan ileme sokulan, deiken bilgi iermeyen atomlardr.


rnein:

25/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

sayac = son + 10
gibi bir ifadede 10 deimezi dorudan son isimli deiken ile ileme sokulur.

5. Dizgeler

ki trnak iindeki ifadelere "Dizge" (string / string litaerals) denir. Dizgeler programlama
dillerinin ounda tek bir atom olarak alnr, daha fazla paraya blnemezler.
"STRNGLER DE BRER ATOMDUR"
ifadesi bir dizgedir.

6. Ayralar, Noktalama aretleri

Yukarda saylan atom snflarnn dnda kalan tm atomlar bu gruba sokulabilir.


Genellikle dier atomlar birbirinden ayrma amacyla kullanldklar iin ayra (separators,
punctuators, delimiters) olarak isimlendirilirler.

Bir C Programnn Atomlarna Ayrlmas:


Aada 1'den kullancnn klavyeden girdii bir tamsayya kadar olan tamsaylar
toplayan ve sonucu ekrana yazdran bir C program grlyor:
#include <stdio.h>
int main()
{
int number, k;
int total = 0;
printf("ltfen bir say girin\n");
scanf("%d", &number);
for(k = 1; k<= number; ++k)
total += k;
printf("toplam = %d\n", total);
}

return 0;

Bu kaynak kod aadaki gibi atomlarna ayrlabilir:


#
include
<
stdio.h
>
main
number
,
k
,
total
=
printf
(
"ltfen bir say girin\n"
,
&
number
)
;
for
(
k
=
1
;
k
total
+=
k
;
printf
(
"toplam = %d\n"
,

0
)

<=

;
toplam

Yukardaki atomlar aada gruplandrlyor:


Anahtar szckler:
include

int

for

return

simlendirilenler:
main

toplam

printf

26/529

;
;

scanf

{
scanf

int
(

"%d"

++

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

leler:
=

<=

++

+=

Deimezler:
0

Dizgeler:
("ltfen bir say girin\n"

"%d"

"toplam = %d\n"

Ayralar, noktalama iaretleri


<

>

Nesne

Bellekte yer kaplayan ve ieriklerine eriilebilen alanlara nesne (object) denir. Bir ifadenin
nesne olabilmesi iin bellekte bir yer belirtmesi gerekir. Programlama dillerinde nesnelere
isimleri kullanarak eriilebilir.
a = b + k;
rneinde a, b ve k birer nesnedir. Bu ifadede a nesnesine, b ve k nesnelerine ait
deerlerin toplam atanr.
sonuc = 100;
sonuc isimli nesneye 100 deimez deeri atanr.
Nesnelerin baz zelliklerinden sz edilebilir:
Nesnelerin isimleri (name) nesneyi temsil eden yazlmsal varlklardr. Nesnelere isimleri
programc tarafndan verilir. Her dil iin nesne isimlendirmede baz kurallar sz
konusudur.
vergi = 20000;
Burada vergi bir nesne ismidir.
Nesne ile deiken terimleri birbirine tam olarak edeer deildir. Her deiken bir
nesnedir ama her nesne bir deiken deildir. Deiken demekle daha ok, programcnn
isimlendirdii nesneler kastedilir. Peki programcnn isimlendirmedii nesneler de var
mdr? Evet, gstericiler konusunda da grlecei gibi, deiken olmayan nesneler de
vardr. Nesne kavram deiken kavramn kapsar.
Nesnelerin deerleri (value) ilerinde tuttuklar bilgilerdir. Baka bir deyile nesneler iin
bellekte ayrlan yerlerdeki 1 ve 0'larn yorumlan biimi, ilgili nesnenin deeridir. Bu
deerler programlama dillerinin kurallarna gre, istenildikleri zaman programc
tarafndan deitirilebilirler. C dilinde baz nesnelerin deerleri ise bir kez verildikten
sonra bir daha deitirilemez.
Nesnenin tr (type) derleyiciye o nesnenin nasl yorumlanaca hakknda bilgi verir. Bir
nesnenin tr onun bellekteki uzunluu hakknda da bilgi verir. Her trn bellekte ne
kadar uzunlukta bir yer kaplad programlama dillerinde nceden belirtilmitir. Bir
nesnenin tr, ayrca o nesne zerinde hangi ilemlerin yaplabilecei bilgisini de verir.
Tr, nesnenin ayrlmaz bir zelliidir. Trsz bir nesne kavram sz konusu deildir.
Trler ikiye ayrlabilir:

27/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

1. nceden tanmlanm veri trleri


nceden tanmlanm veri trleri (default types - built-in types, primitive types)
programlama dilinin tasarmnda var olan veri trleridir. rnein C dilinde nceden
tanmlanm 11 ayr veri tr vardr.
2. Programc tarafndan tanmlanan veri trleri
Programc tarafndan tanmlanan veri trleri (user defined types) programcnn yaratt
trlerdir. Programlama dillerinin ounda nceden tanmlanm trlerin yannda,
programcnn yeni bir tr oluturmasn salayan aralar vardr. rnein C dilinde yaplar,
birlikler, numaralandrma aralar ile, programc tarafndan yeni bir veri tr yaratlabilir.
Programlama dillerindeki tr tanmlamalar birbirlerinden farkl olabilir. rnein baz
programlama dillerinde Boolean isimli -mantksal doru ya da yanl deerlerini alan- bir
tr vardr. Ama C89 dilinde byle bir tr dorudan tanmlanmamtr.
Bilinirlik alan (scope), bir ismin, dilin derleyicisi ya da yorumlaycs tarafndan
tannabildii program alandr.
mr (storage duration - lifespan), programn altrlmas srasnda nesnenin varln
srdrd zaman parasdr.
Balant (linkage), nesnelerin program oluturan dier modllerde tannabilme
zelliidir.

fade

Deiken, ile ve deimezlerin bileimlerine ifade (expression) denir.


a + b / 2
c * 2,
d = h + 34
var1
geerli ifadelerdir.

Sol Taraf Deeri

Nesne gsteren ifadelere "sol taraf deeri" (left value - L value) denir. Bir ifadenin sol
taraf deeri olabilmesi iin mutlaka bir nesne gstermesi gerekir. Bir ifadenin sol taraf
deeri olarak isimlendirilmesinin nedeni o ifadenin atama ilecinin sol tarafna
getirilebilmesidir.
rnein a ve b nesneleri tek bana sol taraf deerleridir. nk bu ifadeler atama
ilecinin sol tarafna getirilebilirler. rnein :
a = 17
ya da
b = c * 2
denilebilir. Ama a + b bir sol taraf deeri deildir. nk
a + b = 25
denilemez.
Deikenler, her zaman sol taraf deeridirler. Deimezler, sol taraf deeri olamazlar.

Sa Taraf Deeri:

Daha az kullanlan bir terimdir. Nesne gstermeyen ifadeler sa taraf deeri (right value)
olarak isimlendirilirler. Tipik olarak, atama ilecinin sol tarafnda bulunamayan yalnzca

28/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

sa tarafnda bulunabilen ifadelerdir. Deimezler her zaman sa taraf deeri


olutururlar.
Bir ifade sol taraf deeri deilse sa taraf deeridir. Sa taraf deeri ise sol taraf deeri
deildir. Her ikisi birden olamaz. Yani atama ilecinin sa tarafna gelebilen her ifade sa
taraf deeri olarak isimlendirilmez. Sa taraf deeri, genellikle bir ifadenin nesne
gstermediini vurgulamak iin kullanlr.

Deimez fadeler

Yalnzca deimezlerden oluan bir ifadeye "deimez ifade" (constant expression) denir.
Bir deimez ifadede deikenler ya da ilev arlar yer alamaz:
10
3.5
10 + 20
ifadeleri deimez ifadelerdir.
Deimez ifadeler, derleme aamasnda derleyici tarafndan net saysal deerlere
dntrlebilir. C dilinin szdizim kurallar birok yerde deimez ifadelerin
kullanlmasn zorunlu klar.

Deyim

C dilinin cmlelerine deyim (statement) denir. C dilinde deyimler ";" ile sonlandrlr.
result = number1 * number2
bir ifadedir. Ancak
result = number1 * number2;
bir deyimdir. Bu deyim derleyicinin, number1 ve number2 deikenlerin deerlerinin
arplarak, elde edilen deerin result deikenine atanmasn salayacak ekilde kod
retmesine neden olur.
Baz deyimler yalnzca derleyiciye bilgi vermek amacyla yazlr, derleyicinin bir ilem
yapan kod retmesine yol amaz. Byle deyimlere bildirim deyimleri (declaration
statement) denir. Baz deyimler derleyicinin bir ilem yapan kod retmesini salar. Byle
deyimlere yrtlebilir deyimler (executable statement) denir.

29/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

BR C PROGRAMI OLUTURMAK
C dilinde yazlan bir programn altrlabilir hale getirilebilmesi iin, ounlukla aadaki
srelerden geilir:
1. Kaynak dosyann oluturulmas
Kaynak dosya, metin dzenleyici bir programda (text editr) yazlr. Kaynak dosya bir
metin dosyasdr. C dilinin kurallarna gre yazlan dosyalarn uzants, geleneksel olarak
".c" seilir.
2. Kaynak dosyann derleyici program (compiler) tarafndan derlenmesi:
Bir programlama dilinde yazlm program baka bir programlama diline eviren
programlara "evirici" (translator) denir. Dntrlmek istenen programn yazld dile
"kaynak dil" (source language), dnmn yapld dile ise "hedef dil" (target language)
denir. Hedef dil, makine dili ya da simgesel makine dili ise, byle evirici programlara
"derleyici" (compiler) denir.
Derleyici program kaynak dosyay alr, eviri ileminde eer baarl olursa bu kaynak
dosyadan bir "ama dosya" (object file) retir.
Derleyici programn derleme ilemini yapma srecine "derleme zaman " (compile time)
denir. Derleme ilemi baarszlk ile de sonulanabilir.
Bir derleyici program, kaynak metni makine diline evirme abasnda, kaynak metnin C
dilinin szdizim kurallarna uygunluunu da denetler.
Kaynak metinde dilin kurallarnn inendii durumlarda, derleyici program bu durumu
bildiren bir ileti (diagnostic message) vermek zorundadr. Derleyici programn verdii
ileti:
i) Bir "hata iletisi" (error message) olabilir. Bu durumda, derleyici programlar ounlukla
ama dosya retmeyi reddeder.
ii) Bir uyar iletisi olabilir (warning message). Bu durumda, derleyici programlar
ounlukla ama dosyay retir.
C standartlarna gre derleyici programlar, dilin kurallarnn inenmesi durumlarnn
dnda da, programcy mantksal hatalara kar korumak amacyla, istedikleri kadar
uyar iletisi retebilir.
Unix/Linux sistemlerinde oluturulan ama dosyalarn uzants ".o" dur. DOS ve Windows
sistemlerinde ama dosyalar ".obj" uzantsn alr.
Derleyici programlar, genellikle basit bir arayz ile iletim sisteminin komut satrndan
altrlacak biimde yazlr. Arayzn basit tutulmasnn nedeni baka bir program
tarafndan kolay kullanabilmesini salamak iindir. rnein, Microsoft firmasnn C/C++
derleyicisi aslnda "cl.exe" isimli bir programdr. UNIX sistemlerindeki GNU'nun gcc
derleyicisi ise aslnda gcc.exe isimli bir programdr.
Derleyici programlar daha kolay ynetmek iin, IDE (integrated development
environment) denilen gelitirme ortamlar kullanlabilir. IDE derleyici demek deil,
derleyiciyi altran ve program yazmay kolaylatran gelitirme ortamlardr. rnein
MinGW ve DevC++ derleyici deil, IDE programlardr. Bu programlar gcc derleyicisini
kullanmaktadr.
3. Daha nce elde edilmi ama dosyalar "balayc" (linker) program tarafndan
birletirilerek altrlabilir bir dosya elde edilir. UNIX sistemlerinde genellikle
altrlabilir dosyann uzants olmaz. Windows sistemlerinde altrlabilir dosyalarn
uzants ".exe" olarak seilir.

31/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

nilemci Program

C ve C++ dillerinde derleyici programdan daha nce kaynak kodu ele alan "nilemci"
(preprocessor) isimli bir program kullanlr. nilemci program ayr bir konu bal
altnda ele alnacak.

32/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

VER TRLER
Nesnelerin en nemli zelliklerinden biri, nesnenin trdr. Tr (type), nesnenin olmazsa
olmaz bir zelliidir. Tr olmayan bir nesneden sz etmek mmkn deildir. Derleyiciler
nesnelerle ve verilerle ilgili kod retirken, tr bilgisinden faydalanr. Derleyiciler nesnenin
tr bilgisinden, sz konusu veriyi bellekte ne ekilde tutacaklarn, verinin deerini elde
etmek iin veri alanndaki 1 ve 0 lar nasl yorumlayacaklarn, veriyi hangi ilemlere
sokabileceklerini renir.
Programlama dilleri asndan baktmz zaman trleri iki ayr gruba ayrabiliriz.

1. nceden Tanmlanm Trler

Programlama dilinin tasarmndan kaynaklanan ve dilin kurallarna gre varl gvence


altna alnm olan trlerdir. Her programlama dili programcnn dorudan kullanabilecei,
eitli zelliklere sahip veri trleri tanmlar. C dilinde de nceden tanmlanm 11 tane
veri tr vardr.

2. Programcnn Tanmlanm Olduu Trler

Programlama dillerinin ou, nceden tanmlanm veri trlerine ek olarak, programcnn


da yeni trler tanmlanmasna izin verir. Programcnn tanmlayaca bir nesne iin
nceden tanmlanm veri trleri yetersiz kalrsa, programc dilin belli szdizim (sentaks)
kurallarna uyarak kendi veri trn yaratabilir. C dilinde de programc yeni bir veri
trn derleyiciye tantabilir, tantt veri trnden nesneler tanmlayabilir.
Farkl programlama dillerindeki nceden tanmlanan veri trleri birbirlerinden farkl
olabilir. Daha nce renmi olduunuz bir programlama dilindeki trlerin aynsn C
dilinde bulamayabilirsiniz.
C dilinin nceden tanmlanm 11 veri tr vardr. Bu veri trlerinden 8 tanesi tamsay
trnden verileri tutmak iin, kalan 3 tanesi ise gerek say trnden verileri tutmak iin
tasarlanmtr. Biz bu trlere srasyla "tamsay veri trleri" (integer types) ve "gerek
say veri trleri" (floating types) diyeceiz.

Tamsay Veri Trleri

C dilinin toplam 4 ayr tamsay veri tr (integer types) vardr. Ancak her birinin kendi
iinde iaretli (signed) ve iaretsiz (unsigned) biimi olduundan toplam tamsay tr 8
kabul edilir.
aretli (signed) tamsay trlerinde pozitif ve negatif tam say deerleri tutulabilirken,
iaretsiz (unsigned) veri trlerinde negatif tamsay deerleri tutulamaz.
Aada C dilinin temel tamsay veri trleri tantlyor:
aretli karakter tr:
Bu veri trne ksaca signed char tr denir.
phesiz char szc ingilizce "character" szcnden ksaltlmtr, Trke "karakter"
anlamna gelir. Ancak bu trn ismi C'nin anahtar szckleri olan signed ve char
szckleri ile zdeleip, "signed char" olarak sylenir. aretli char trnden bir
nesnenin 1 byte'lk bir alanda tutulmas C standartlarnca gvence altna alnmtr.
1 byte'lk bir alan iaretli olarak kullanldnda bu alanda saklanabilecek deerler -128 /
127 deerleri arasnda olabilir.
aretsiz karakter tr:
aretsiz char trnn iaretli olandan fark 1 byte'lk alann iaretsiz olarak, yani
yalnzca 0 ve pozitif saylarn ifadesi iin kullanlmasdr. Bu durumda iaretsiz char
trnde 0 - 255 arasndaki tamsay deerleri tutulabilir.
Karakter tr:
33/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

aretli ya da iaretsiz olarak kullanlaca derleyicinin seimine bal olan bir trdr.
aretli ve iaretsiz ksa tamsay veri tr
short ve int szckleri C dilinin anahtar szcklerinden olduu iin bu tre genellikle short
int ya da ksaca short tr denir.
aretli veya iaretsiz short trnden bir nesne tanmland zaman, nesnenin bellekte
ka byte yer kaplayaca sistemden sisteme deiebilir. Sistemlerin ounda, short int
veri trnden yaratlan nesne bellekte 2 byte'lk bir yer kaplar. aretli short int trnden
bir nesne -32768 - +32767 aralndaki tamsay deerlerini tutabilirken, iaretsiz short
trnde tutulabilecek deerler 0 - 65535 aralnda olabilir.
aretli ve iaretsiz tamsay tr
Bu tre ksaca int tr denir.
aretli ve iaretsiz int trnden bir nesne tanmland zaman, nesnenin bellekte ka
byte yer kaplayaca sistemden sisteme deiebilir. ounlukla 16 bitlik sistemlerde, int
trnden veri 2 byte, 32 bitlik sistemlerde ise int trnden veri tr 4 byte yer kaplar.
16 bitlik sistem demekle ilemcinin yazma (register) uzunluunun 16 bit olduu anlatlr.
int veri trnn 2 byte uzunluunda olduu sistemlerde bu veri trnn say snrlar,
iaretli int tr iin -32768 - +32767, iaretsiz int veri tr iin 0 - +65535 arasnda olur.
int veri trnn 4 byte uzunluunda olduu sistemlerde bu veri trnn say snrlar,
iaretli int tr iin -2147483648 - +2147483647, iaretsiz int veri tr iin 0 +4.294.967.295 arasnda olur.
aretli ve iaretsiz uzun tamsay veri tr
long ve int szckleri C dilinin anahtar szcklerinden olduu iin bu tre genellikle long
int ya da ksaca long tr denir.
aretli veya iaretsiz long trnden bir nesne tanmland zaman, nesnenin bellekte ka
byte yer kaplayaca sistemden sisteme deiebilir. Sistemlerin ounda, long int veri
trnden yaratlan nesne bellekte 4 byte'lk bir yer kaplar. aretli long int trnden bir
nesne -2147483648- +2147483648 aralndaki tamsay deerlerini tutabilirken, iaretsiz
long trnde tutulabilecek deerler 0 +4.294.967.295 aralnda olabilir.

Gerek Say Trleri

C dilinde gerek say deerlerini tutabilmek iin 3 ayr veri tr tanmlanmtr. Bunlar
srasyla, float, double ve long double veri trleridir. Gerek say veri trlerinin hepsi
iaretlidir. Yani gerek say veri trleri iinde hem pozitif hem de negatif deerler
tutulabilir. Gerek saylarn bellekte tutulmas sistemden sisteme deiebilen zellikler
ierebilir. Ancak sistemlerin ounda IEEE 754 sayl standarda uyulur.
Sistemlerin hemen hepsinde float veri trnden bir nesne tanmland zaman bellekte 4
byte yer kaplar. 4 byte lk yani 32 bitlik alana zel bir kodlama yaplarak gerek say
deeri tutulur. IEEE 754 sayl standartta 4 byte lk gerek say format "single precision"
(tek duyarlk) olarak isimlendirilirken, 8 byte lk gerek say format "double precision"
(ift duyarlk) olarak isimlendirilmitir.
Sistemlerin hemen hepsinde double veri trnden bir nesne tanmland zaman bellekte
8 byte yer kaplar.
long double veri trnn uzunluu sistemden sisteme deiiklik gsterir. Bu tr,
sistemlerin ounda 8, 10, 12 byte uzunluundadr.

34/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Say sistemleri blmmzden, gerek saylarn n byte'lk bir alanda zel bir biimde
kodlandn hatrlayacaksnz. rnein IEEE 754 sayl standartta 4 ya da 8 byte lk alan
ayr paraya blnm, bu paralara zel anlamlar yklenmitir. rnein gerek
saynn 4 byte lk bir alanda tutulmas durumunda 1 bit, saynn iaretini tutmak iin
kullanlrken, 23 bit, saynn ondalk (fraction) ksmn tutar. Geriye kalan 8 bit ise,
noktann en saa alnmas iin gerekli bir arpm faktrn dolayl olarak tutar. Bu
durumda gerek saynn 8 byte'lk bir alanda kodlanmas durumunda, hem tutulabilecek
saynn bykl artarken hem de noktadan sonraki duyarlk da artar.
Aada C dilinin doal veri trlerine ilikin bilgiler bir tablo eklinde veriliyor:

35/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

TAMSAYI TRLER (INTEGER TYPES)


TR SM

UZUNLUK
(byte)

SINIR DEERLER

(DOS /UNIX)

signed char
unsigned char
char
signed short int
unsigned short int
signed int
unsigned int
signed long int
unsigned long int
_Bool (C 99)
signed long long int (C 99)
unsigned long long int(C 99)

1
1
1
2
2
2
4
2
4
4
4
1
8
8

-128 - 127
0 - 255
Derleyiciye bal
-32.768 / 32.767
0 / 65.535
-32.768 / 32.767
-2.147.483.648 - 2.147.483.647
0 / 65.535
0 / 4.294.967.295
-2.147.483.648 - 2.147.483.647
0 / 4.294.967.295
false / true
-9.223.372.036.854.775.808 / 9.223.372.036.854.775.807

0 / 18.446.744.073.709.551.615

GEREK SAYI TRLER (FLOATING TYPES)


TR SM

UZUNLUK
(byte)

float

double

long double
8/10/12
float _Complex (C 99)
double _Complex (C 99)
long double _Complex (C 99)
float _Imaginary (C 99)
double _Imaginary (C 99)
long double _Imaginary (C 99)

SINIR DEERLER
en kk pozitif deer
en byk pozitif deer
1.17 x 10-38
3.40 x 1038
(6 basamak duyarlk)
(6 basamak duyarlk)
2.22 x 10-308
1.17 x 10-308
(15 basamak duyarlk)
(15 basamak duyarlk)
tanabilir deil

Yukarda verilen tablo, sistemlerin ou iin geerli de olsa ANSI C standartlarna gre
yalnzca aadaki zellikler gvence altna alnmtr:
char tr 1 byte uzunluunda olmak zorundadr.
short veri trnn uzunluu int trnn uzunluuna eit ya da int tr uzunluundan
kk olmaldr.
long veri trnn uzunluu int trne eit ya da int trnden byk olmak zorundadr.
Yani
short <= int <= long
Derleyiciler genel olarak derlemeyi yapacaklar sistemin zelliklerine gre int trnn
uzunluunu ilemcinin bir kelimesi kadar alrlar. 16 bitlik bir ilemci iin yazlan tipik bir
uygulamada
char tr 1 byte

36/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

int tr 2 byte (ilemcinin bir kelimesi kadar)


short tr 2 byte (short = int)
long tr 4 byte (long > int)
alnabilir.
Yine 32 bitlik bir ilemci iin yazlan tipik bir uygulamada
char tr 1 byte
int tr 4 byte (ilemcinin bir kelimesi kadar)
short tr 2 byte (short < int)
long tr 4 byte (long = int)
alnabilir.
C dilinin en ok kullanlan veri trleri tamsaylar iin int tryken, gerek saylar iin
double veri trdr. Peki hangi durumlarda hangi veri trn kullanmak gerekir? Bunun
iin hazr bir reete vermek pek mmkn deil, zira kullanacamz bir nesne iin tr
seerken birok etken sz konusu olabilir. Ama genel olarak u bilgiler verilebilir:
Gerek saylarla yaplan ilemler tam saylarla yaplan ilemlere gre ok daha yavatr.
Bunun nedeni phesiz gerek saylarn zel bir ekilde belirli bir byte alanna
kodlanmasdr. Tamsaylarn kullanlmasnn yeterli olduu durumlarda bir gerek say
trnn kullanlmas, alan programn belirli lde yavalamas anlamna gelir. Bir
tamsay trnn yeterli olmas durumunda gerek say trnn kullanlmas programn
okunabilirliinin de azalmasna neden olurr.

37/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

BLDRM ve TANIMLAMA
Bildirim Nedir?

Bir kaynak dosya iinde yazlan geerli C deyimlerinin bir ksm, bir ilem yaplmasna
ynelik deil, derleyiciye derleme zamannda kullanaca bir bilgi vermeye yneliktir.
Byle deyimlere bildirim (declaration) deyimi denir. Derleyici geerli bir bildirim
deyiminin stnden getiinde bir bilgi alr ve ald bu bilgiyi yine derleme zamannda
kullanr.

Tanmlama Nedir?

Ancak baz bildirim deyimleri vardr ki, derleyici bu deyimlerden ald bilgi sonucunda,
bellekte bir yer ayrr. Tanmlama (definition), derleyicinin bellekte yer ayrmasn
salayan bildirim deyimleridir.

Deikenlerin Tanmlanmas

C dilinde bir deiken derleyiciye tantlmadan kullanlamaz. Derleyicinin sz konusu


deiken iin bellekte bir yer ayrmasn salamak iin, uygun bir szdizimi ile, deikenin
ismi ve tr derleyiciye bildirilir. Bildirim ilemi yoluyla, derleyiciler deikenlerin hangi
zelliklere sahip olduklarn anlar. Bylece bu deikenler iin programn alma
zamanna ynelik olarak bellekte uygun bir yer ayrma ilemi yapabilir.
C dilinde eer yaplan bir bildirim ilemi, derleyicinin bellekte bir yer ayrmasna neden
oluyorsa bu ileme tanmlama (definition) denir. Tanmlama nesne yaratan bir bildirimdir.
Programlama dillerinin ounda nesneler kullanlmadan nce derleyiciye tantlrlar.
Her tanmlama ilemi ayn zamanda bir bildirim ilemidir. Ama her bildirim ilemi bir
tanmlama olmayabilir. Baka bir deyile, tanmlama nesne yaratlmasn salayan bir
bildirim ilemidir.
C dilinde bir deikeni bildirimini yapmadan nce kullanmak geersizdir, derleme
ileminde hata (error) oluumuna yol aar.
Bir deikenin derleyiciye tantlmas, deikenin trnn ve isminin derleyiciye
bildirilmesidir. Derleyici bu bilgiye dayanarak deiken iin bellekte ne kadar yer
ayracan, deikenin iin ayrlan byte'lardaki 1 ve 0 larn nasl yorumlanaca bilgisini
elde eder.

Deiken Tanmlama leminin Genel Biimi


C'de bildirim ilemi aadaki ekilde yaplr :

<tr belirten szckler> <deiken ismi> <;>


Tanmlamann bir noktal virglle sonlandrldn gryorsunuz. Nasl normal dilde, nokta
cmleleri sonlandryorsa, C dilinde de noktal virgl atomu, C dilinin cmleleri olan
deyimleri sonlandrr. "Noktal virgl" atomu C dilinin cmlelerinin noktasdr. Bundan
sonra noktal virgl atomuna "sonlandrc atom" (terminator) diyeceiz. Noktal virgl
ayra trnden bir atomdur. C'de deyimler, ounlukla bu ayra ile birbirlerinden ayrlr.
a = x + 1; b = x + 2;
ifadelerinde bulunan noktal virgller bunlarn ayr birer deyim olduklarn gsterir. Eer
bir tek noktal virgl olsayd derleyici iki ifadeyi tek bir ifade gibi yorumlard.
a = x + 1

b = x + 2;

Yukardaki ifade tek bir ifade gibi yorumlanr ve derleyici buna geerli bir anlam veremez.

39/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Tr belirten anahtar szckler, C dilinin nceden tanmlanm veri trlerine ilikin anahtar
szcklerdir. Bu szcklerin kullanlmasyla, tanmlanacak deikenlerin, 11 temel veri
trnden hangisine ait olduu bildirilir. C dilinin nceden tanmlanm veri trlerine
ilikin, bildirim ileminde kullanlabilecek anahtar szckler unlardr:
signed, unsigned, char, short, int, long, float, double
Bu szcklerin hepsi anahtar szck olduundan kk harf ile yazlmaldr, C dilinin
byk harf kk harf duyarl (case sensitive) bir dil olduunu hatrlayalm. C dilinin tm
anahtar szckleri kk harf ile tanmlanmtr.
Tr belirten anahtar szckler aadaki izelgede listelenen seeneklerden biri olmaldr.
Keli ayra iindeki ifadeler kullanlmas zorunlu olmayan, yani seime bal olan
anahtar szckleri gsteriyor. Ayn satrdaki tr belirten anahtar szckler tamamen ayn
anlamda kullanlabilir:
1

iaretli char tr

2
3

iaretsiz char tr
iaretli ksa tamsay tr

iaretsiz ksa tamsay tr

iaretli tamsay tr

iaretsiz tamsay tr

iaretli uzun tamsay tr

iaretsiz uzun tamsay tr

9
10
11

float tr
double tr
long double tr

[signed] char
char
unsigned char
[signed] short [int]
[signed] short
short [int]
short
unsigned short [int]
unsigned short
[signed] int
int
signed
unsigned int
unsigned
[signed] long [int]
[signed] long
long [int]
long
unsigned long [int]
unsigned long
float
double
long double

Yukardaki tablodan da grld gibi, belirli trleri birden fazla ekilde ifade etmek
mmkndr.
char a;
signed char a;

int a;
signed int a;
signed a;

long a;
long int a;
signed long a;
signed long int a;

Yukarda ayn kolon zerindeki bildirimlerin hepsi, derleyici tarafndan birbirine edeer
olarak ele alnr.
Bildirim szdiziminde, deiken ismi olarak, C dilinin isimlendirme kurallarna uygun
olarak seilen herhangi bir isim kullanlabilir.
C dilinde isimlendirilen (identifiers) varlklar balca 6 grubu ierir. Deikenler
(variables) bunlardan yalnzca biridir. levler (functions), etiketler (labels), makrolar
(macros), yap ve birlik isimleri (structure and union tags), enum deimezleri (enum
constants) isimlerini programclardan alr.

40/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

C Dilinin simlendirme Kurallar


simlendirmede yalnzca 63 karakter kullanlabilir. Bunlar:
ngiliz alfabesinde yer alan 26 kk harf karakteri:
a,b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z
ngiliz alfabesinde yer alan 26 byk harf karakteri:
A,B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z
rakam karakterleri
0, 1, 2, 3, 4, 5, 6, 7, 8, 9
alttire (_) (underscore) karakteridir.
simlendirmelerde yukarda belirtilen karakterlerin dnda baka bir karakterin
kullanlmas geersizdir. rnein, boluk karakterleri, Trkeye zg (, , , , , , , ,
, , , ) karakterler, +, -, /, *, & ya da $ karakterleri bir isimde kullanlamaz.
Deiken isimleri rakam karakteriyle balayamaz. Harf karakteri ya da alttire karakteri
dnda, yukarda geerli herhangi bir karakterle balayabilir. Bu kural derleyicinin
deimezlerle isimleri birbirinden ayrmasn kolaylatrr.
Deiken isimleri alttire '_' karakteriyle balayabilir.
C'nin 32 anahtar szc isimlendirme amac ile kullanlamaz.

Uzun Deiken simleri

simler boluk ieremeyecei iin uygulamalarda genellikle boluk hissi vermek iin alttire
(underscore) karakteri kullanlr.
genel_katsayi_farki, square_total, number_of_cards
gibi.
simlendirmede baka bir seenek de her szcn ilk harfini byk, dier harfleri kk
yazmaktr:
GenelKatsayiFarki, SquareTotal, NumberOfCards
C dili standartlar isim uzunluu konusunda bir snrlama koymamtr. Ancak ismin ilk 31
karakterinin derleyici tarafndan dikkate alnmasn zorunlu klar. Ancak derleyicilerin
ou, ok daha uzun deiken isimlerini ileme sokabilirler. 31 karakterden daha uzun
isimler kullanldnda programc iin ok az da olsa yle bir risk sz konusudur:
Herhangi bir derleyici ilk 31 karakteri ayn olan iki farkl ismi ayn isim olarak ele alabilir.
C, byk harf kk harf duyarll olan bir dil olduu iin, isimlendirmelerde de byk
harf ile kk harfler farkl karakterler olarak ele alnr:
var, Var, VAr, VAR, vAR, vaR
deikelerinin hepsi ayr deikenler olarak ele alnr.

simlendirmede Nelere Dikkat Edilmeli?

simlendirme, yazlan programlarn okunabilirlii asndan da ok nemlidir. yi yazlm


olan bir programda kullanlan isimlerin dilin kurallarna gre uygun olmalarnn dnda,
baz baka zelliklere de sahip olmas gerekir:
1. Seilen isimler anlaml olmaldr.
41/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Verilen isimler, deikenin kullanm amac hakknda, okuyana bilgi vermelidir. ou


zaman, bir deikenin ismini x, y, z gibi alfabenin harflerinden semek kt bir tekniktir.
Tanmlanan deiken, iinde neyin deerini tutacaksa buna ynelik bir isim vermek, kodu
okuyann iini kolaylatrr, alglamasn hzlandrr.
Ancak geleneksel olarak dng deikenlerine i, j, k isimleri verilir.
2. simler farkl zelliklere sahip deikenlerin ait olduklar grubun ismi olarak
seilmemelidir.
rnein saya grevini stlenen bir deikenin ismini
counter
olarak semek yerine
prime_counter, valid_word_counter vs.
olarak semek ok daha iyidir. Zira programn iinde birden fazla saya bulunabilir.
Bunlarn isimleri, neyi saydklarna gre deiirse, kodu okuyan kiinin anlamlandrmas
ok daha kolaylar.
3. simlendirmede dil btnl olmaldr.
Yazlmda kullanlan temel dilin ngilizce olduunu kabul etmek zorundayz. Yazlm
projelerinde isimlendirme genellikle ngilizce tabanl yaplr. Ancak baz deikenlerin
isimlerinin ngilizce seilirken baz baka deikenlerin isimlerinin Trke seilmesi
programn okunabilirliine zarar verir.
4. C'de deiken isimleri, geleneksel olarak kk harf youn seilirler.
Tamam byk harflerle yazlm deiken isimleri daha ok simgesel deimezler iin
kullanlrlar.

Bildirim rnekleri
int x;
unsigned long int var;
double MFCS;
unsigned _result;
signed short total;
Tr belirten anahtar szcklerin yazlmasndan sonra ayn tre ilikin birden fazla
nesnenin bildirimi, isimleri arasna virgl atomu koyularak yaplabilir. Bildirim deyimi yine
noktal virgl atomu ile sonlandrlmaldr.
unsigned char ch1, ch2, ch3, ch4;
float FL1, Fl2;
unsigned total, subtotal;
int _vergi_katsayisi, vergi_matrahi;
Farkl trlere ilikin bildirimler virgllerle birbirinden ayrlamaz.
long x, int y;

/* Geersiz! */

signed ve unsigned szckleri tr belirten anahtar szck(ler) olmadan yalnz balarna


kullanlabilirler. Bu durumda int trden bir deikenin bildiriminin yapld kabul edilir:
signed x, y;
ile

42/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

signed int x, y;
tamamen ayn anlamdadr. Yine
unsigned u;
ile
unsigned int u;
Tamamen ayn anlamdadr.
Bildirim deyiminde, tr belirten anahtar szck birden fazla ise bunlarn yazm sras
nemli deildir. Ama okunabilirlik asndan nce iaret belirten anahtar szcn sonra
tr belirten anahtar szcn kullanlmas gelenek haline gelmitir. rnein :
signed long int
signed int long
long signed int
long int signed
int long signed
int signed long

x;
x;
x;
x;
x;
x;

bildirimlerinin hepsi geerlidir. Seimlik olan anahtar szckler zellikle kullanlmak


isteniyorsa birinci yazm biimi okunabilirlik asndan tercih edilmelidir.

Bildirimlerin Kaynak Kod indeki Yerleri

C dilinde genel olarak 3 yerde deiken bildirimi yaplabilir :


1. Bloklarn iinde
2. Tm bloklarn dnda.
3. levlerin parametre deikeni olarak, ilev parametre ayralarnn iinde.
lev parametre ayralar iinde yaplan bildirimler, baka bir szdizim kuralna uyar. Bu
bildirimleri "ilevler" konusunda ayrntl olarak ele alacaz.
C dilinde eer bildirim bloklarn iinde yaplacaksa, bildirim ilemi bloklarn ilk ilemi
olmak zorundadr. Baka bir deyile bildirimlerden nce, bildirim deyimi olmayan baka
bir deyimin bulunmas geersizdir.
Bir bildirimin mutlaka ilevin ana blounun banda yaplmas gibi bir zorunluluk yoktur.
Eer i ie bloklar varsa iteki herhangi bir bloun banda da yani o bloun ilk ilemi
olacak biimde, bildirim yaplabilir. rnekler :
{

int var1, var2;


char ch1, ch2, ch3;
var1 = 10;
float f;
/* Geersiz */

}
Yukardaki rnekte var1, var2, ch1, ch2, ch3 deikenlerinin tanmlanma yerleri
dorudur. Ancak f deikeninin bildirimi geersizdir. nk bildirim deyiminden nce
bildirim deyimi olmayan baka bir deyim yer alyor. Bu durum geersizdir.
Ayn program paras u ekilde yazlm olsayd bir hata sz konusu olmazd :

43/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

int var1, var2;


char ch1, ch2, ch3;
var1 = 10;
{ float f; }

}
Bu durumda artk f deikeni de kendi blounun banda tanmlanm olur.
C dilinde tek bana bir sonlandrc atom bir deyim oluturur. Ve byle bir deyime, bo
deyim (null statement) denir. C szdizimine gre oluan bu deyim yrtlebilir bir
deyimdir. Dolaysyla aadaki kod parasnda y deikeninin tanmlamas derleme
geersizdir.
{
}

int x;;
int y;

/* Geersiz! */

Yukardaki kod parasnda x deikeninin bildiriminden sonra yer alan sonlandrc atom
yrtlebilir bir deyim olarak ele alnr. Bu durumda y deikeninin bildirimi geersizdir.
Ayn ekilde ii bo bir blok da C dilinde bir yrtlebilir deyim olarak ele alnr. Bu yazm,
sonlandrc atomun tek bana kullanlmasna tamamen edeerdir. Aadaki kod
paras da geersizdir:
{

int x;
{ }
int y;

/* Geersiz! */

Bir ya da birden fazla deyimin bir blok iine alnmasyla elde edilen yap C dilinde bileik
deyim (compound statement) ismini alr. Bileik deyimler de yrtlebilir deyimlerdir.
Aadaki kod paras da geersizdir:
{
}

{int x;}
int y;

/* Geersiz */

[C++ dilinde blok iinde bildirimi yaplan deikenlerin blok balarnda bildirilmeleri zorunlu deildir. Yani
C++'da deikenler bloklarn iinde herhangi bir yerde bildirilebilir.]

Tanmlanan Deikenlere lkdeer Verilmesi

Bir deiken tanmlandnda bu deikene bir ilkdeer verilebilir (initialize). Bu zel bir
szdizim ile yaplr:
int a = 20;
lkdeer verme deyimi bir atama deyimi deildir, bir bildirim deyimidir. Bu deyim ile,
programn alma zamannda bir deikenin nceden belirlenen bir deer ile hayata
balamas salanr. Yukardaki bildirimi gren derleyici a deikenini 20 deeri ile
balatacak bir kod retir. lkdeer verme deyiminde atama ilecinin sa tarafnda
kullanlan ifadeye "ilkdeer verici" (initializer) denir.
Bir bildirim deyimi ile birden fazla deikene de ilkdeer verilebilir:
int a = 10, b = 20, c = 30;

44/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yukardaki deyimle a deikenine 10, b deikenine 20, c deikenine 30 ilkdeerleri


veriliyor.
lkdeer verme deyimi bir atama deyimi deildir:
void func()
{
int a;
a = 20;
int b; /* Geersiz! */
/****/
}
Yukardaki kod parasnda b deikeninin tanm geersizdir. nk b deikeninin
tanmndan nce blok iinde yrtlebilir bir deyim yazlmtr. Ancak aadaki kod
geerlidir:
void func()
{
int a = 20;
int b; /* Geerli! */
/****/
}

45/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

DEMEZLER
Veriler ya nesnelerin iinde ya da dorudan deimez (sabit - constant) biiminde
bulunur. Deimezler nesne olmayan, programc tarafndan dorudan saysal byklk
olarak girilen verilerdir. Deimezlerin saysal deerleri derleme zamannda tam olarak
bilinir. rnein:
x = y + z;
ifadesi bize y ve z iindeki deerlerin toplanacan ve sonucun x deikenine
aktarlacan anlatr. Oysa
d = x + 10;
ifadesinde x deikeni iinde saklanan deer ile 10 says toplanmtr. Burada 10 says
herhangi bir deikenin iindeki deer deildir, dorudan say biiminde yazlmtr.

Deimezlerin Trleri

Nesnelerin trleri olduu gibi deimezlerin de trleri vardr. Nesnelerin trleri bildirim
yaplrken belirlenir. Deimezlerin trlerini ise derleyici, belirli kurallara uyarak
deimezlerin yazl biimlerinden saptar. Deimezlerin trleri nemlidir, nk C
dilinde deimezler, deikenler ve ileler bir araya getirilerek ifadeler (expressions)
oluturulur. C'de ifadelerin de tr vardr. fadelerin trleri, ierdikleri deimez ve
deikenlerin trlerinden elde edilir.

Tamsay Deimezleri

Tamsay deimezlerinin (integer constants) deerleri tamsaydr.


Bir tamsay deimezi
signed int
unsigned int
signed long
unsigned long
trlerinden olabilir.
Bir tamsay deimezinin tr, yazmnda kullanlan say sistemine ve deimezin ald
soneke gre belirlenir.

Tamsay Deimezlerinin Onluk Onaltlk ve Sekizlik Say


Sistemlerinde Yazm

Varsaylan yazm onluk say sistemidir.


Onaltlk say sisteminde yazm:
0Xbbb..
ya da
0xbbb..

biimindedir. Burada b karakterleri onaltlk say sistemindeki basamaklar gsteriyor.


9'dan byk basamak deerleri iin A, B, C, D, E, F karakterleri ya da a, b, c, d, e, f
karakterleri kullanlr.
Sekizlik say sisteminde yazm:
0bbbb..

47/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

biimindedir.
Burada b karakterleri sekizlik say sistemindeki basamaklar (0 1 2 3 4 5 6 7) gsteriyor.

Tamsay Deimezlerinin Ald Sonekler

Bir tamsay deimezi, hangi say sisteminde yazlrsa yazlsn,


u, U, l ya da L soneklerini alabilir.
u ya da U sonekleri tamsay deimezinin iaretsiz tamsay trnden olduunu belirler.
l ya da L sonekleri tamsay deimezinin long trden olduunu belirler.
l soneki 1 karakteri ile grsel bir karkla neden olabileceinden, 'L' soneki
kullanlmaldr. Bir karakter deimezi hem u, U soneklerinden birini hem de l, L
soneklerinden birini alabilir. Bu durumda soneklerin yazm srasnn bir nemi yoktur.

Tamsay Deimezlerinin Trleri

Tamsay deimezinin tr aadaki tabloya gre belirlenir:


Yazm biimi
bb...b
0xbb...b
0bb...b
bb...bU
0bb...bU
0Xbb...bU
bb...bL
0bb..bL
0xbb..bL
bb...bUL
0bb..bUL
0xbb..bUL

tr
signed int
signed long
unsigned long
signed int
unsigned int
signed long
unsigned long
unsigned int
unsigned long
signed long
unsigned long
unsigned long

Yukardaki tablo yle yorumlanmaldr: Belirli bir yazm iin verilen trlerden, yukardan
aa doru olmak zere, tama olmakszn ilgili deeri tutabilecek ilk tr, deimezin
trdr. Aadaki rnekleri inceleyin:
int trnn ve long trnn 2 byte olduu sistemler iin (DOS) rnekler
Deimez
456
59654
125800
3168912700
0X1C8
0XE906
0X1EB68
0XBCE1C53C
0710
0164406
0365550
027470342474
987U
45769U
1245800U
3589456800U
0X3DBU

int tr 2 byte long tr 4 byte


(DOS)
signed int
signed long
signed long
unsigned long
signed int
unsigned int
signed long
unsigned long
signed int
unsigned int
signed long
unsigned long
unsigned int
unsigned int
unsigned long
unsigned long
unsigned int

48/529

int tr ve long tr 4 byte


(Windows - Unix)
signed int
signed int
signed int
unsigned long
signed int
signed int
signed int
unsigned long
signed int
signed int
signed int
unsigned long
unsigned int
unsigned int
unsigned int
unsigned int
unsigned int

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

0XB2C9U
0X130268U
0XD5F2C3A0U
01733U
0131311U
04601150U
032574541640U
25600L
3298780970L
0X6400L
0Xc49F672AL
062000L
030447663452L
890765UL
0XD978DUL
03313615UL

unsigned int
unsigned long
unsigned long
unsigned int
unsigned int
unsigned long
unsigned long
signed long
unsigned long
signed long
unsigned long
signed long
unsigned long
unsigned long
unsigned long
unsigned long

unsigned int
unsigned int
unsigned int
unsigned int
unsigned int
unsigned int
unsigned int
signed long
unsigned long
signed long
unsigned long
signed long
unsigned long
unsigned long
unsigned long
unsigned long

Karakter Deimezleri

Karakter deimezleri tipik olarak char trden nesnelere atanan deimezlerdir. Karakter
deimezleri C'de farkl biimlerde bulunabilir.
i. Bir karakterin grnts tek trnak (single quote) iinde yazlrsa derleyici tarafndan
dorudan karakter deimezi olarak ele alnr. rnek :
'a'
'J'
''
':'
'8'
'<'
Yukardaki atomlarn her biri birer karakter deimezidir.
C'de tek trnak iinde yazlan char trden deimezler, aslnda o karakterin (kullanlan
sistemin karakter kodundaki (rnein ASCII)) kod numarasn gsteren bir tamsaydr.
char ch;
ch = 'a';
/***/
ASCII karakter kodlamasnn kullanldn dnelim. Bu rnekte aslnda ch isimli char
trden bir deikene 'a' karakterinin ASCII tablosundaki kod numaras olan 97 deeri
aktarlr. Tek trnak iindeki karakter deimezlerini grnce aslnda onlarn kk birer
tamsay olduu bilinmelidir. Yukardaki rnekte istenirse ch deikenine aadaki gibi bir
atama yaplabilir:
ch = 'a' + 3;
Bu durumda ch deikenine saysal olarak 100 deeri atanr. Bu tamsay da ASCII
tablosundaki 'd' karakterinin kod numarasdr.

Ters Bl Karakter Deimezleri

Karakter deimezlerinin dier yazmlarnda tek trnak iinde ters bl '\' karakteri ve
bunu izleyen baka karakter(ler) kullanlr. ngilizce de bu biimlere "escape sequence"
denir.

49/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Tek trnak iindeki ters bl karakterinden sonra yer alan baz karakterler ok kullanlan
baz karakterlerin yerlerini tutar. Bunlarn listesi aada veriliyor:

nceden Tanmlanm Ters Bl Karakter Deimezleri


'\0'
'\a'
'\b'
'\t'
'\n'
'\v'
'\f'
'\r'
'\"'
'\''
'\?'
'\\'

Tanm
sonlandrc karakter (null character)
an sesi (alert)
geri boluk (back space)
tab karakteri (tab)
aa satr (new line)
dey tab (vertical tab)
sayfa ileri (form feed)
satr ba (carriage return)
ift trnak (double quote)
tek trnak (single quote)
soru iareti (question mark)
ters bl (back slash)

ASCII No
0
7
8
9
10
11
12
13
34
39
63
92

Kullanllarna bir rnek :


char ch;
ch = '\a';

Onaltlk Say Sisteminde Yazlan Karakter Deimezleri

Tek trnak iinde ters bl ve 'x' karakterlerinden sonra onaltlk (hexadecimal) say
sisteminde bir say yazlrsa bu sistemin kulland karakter setinde, o saysal deerin
gsterdii kod numaral karakter deimezidir.
'\x41' /* 41H kod numaral karakterdir. */
'\xff' /* FFH kod numaral karakterdir. */
'\x1C' /* 1C kod numaral karakterdir. */
Aada harf isimli char trden deikene 41H deeri atanyor:
char harf;
harf = '\x41';
Bu da onluk say sisteminde 65 deeridir. ASCII karakter setinin kullanldn varsayalm.
65 kod nolu ASCII karakteri 'A' karakteridir. Dolaysyla harf isimli deikene 'A' atanm
olur.

Sekizlik Say Sisteminde Yazlan Karakter Deimezleri

Tek trnak iinde ters bl karakterinden sonra sekizlik say sisteminde bir deer
yazlrsa, bu kullanlan karakter setindeki o saysal deerin gsterdii kod numaral
karaktere iaret eden bir karakter deimezidir. Tek trnak iindeki ters bl karakterini
izleyen sekizlik sistemde yazlm say basamaktan uzun olmamaldr. Sekizlik
sistemde yazlan saynn banda sfr rakam olma zorunluluu yoktur.
'\012' /* 10 numaral ASCII karakteri, Tam say deeri 10 */
'\16'
/* 14 numaral ASCII karakteri. Tam say deeri 14 */
'\123' /* 83 numaral ASCII karakteri. Tam say deeri 83 */
Program iinde kullanmna bir rnek:

50/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

char a, b;
a = '\xbc' ;
b = '\012';

/* onaltlk say sisteminde yazlm karakter deimezi */


/* sekizlik say sisteminde yazlm karakter deimezi */

rnein, 7 numaral ASCII karakteri olan an sesi karakteri, deimez olarak ayr
biimde de yazlabilir:
'\x7'
'\07'
'\a'

/* hex gsterimli karakter deimezi */


/* oktal gsterimli karakter deimezi */
/* nceden belirlenmi ters bl karakter deimezi */

Burada tercih edilecek biim son biim olmaldr. Hem tanabilir bir biimdir hem de
okunabilirlii daha iyidir. Baka karakter setlerinde an sesi karakteri 7 sra numaral
karakter olmayabilir, ama nceden belirlenmi ters bl karakter deimezi eklinde ifade
edersek hangi sistem olursa olsun an sesi karakterini verir. Ayrca kodu okuyan an sesi
karakterinin 7 numaral ASCII karakteri olduunu bilmeyebilir, ama '\a' nn an sesi
karakteri olduunu bilir.
Karakter deimezleri konusunu kapatmadan nce karakter setleri konusunda da biraz
bilgi verelim:
Gnmzde en ok kullanlan karakter seti ASCII karakter setidir. ASCII (American
Standard Code for Information Interchange) szcklerinin ba harflerinden oluan bir
ksaltmadr. ASCII karakter kodunda karakterler 7 bitlik bir alanda kodlanmtr. Baz
bilgisayarlar ise 8 bit alana geniletilmi kodlama kullanrlar ki bu sette 128 yerine 256
karakter temsil edilebilir.
Farkl bilgisayarlar farkl karakter kodlamas kullanabilir. rnek olarak IBM mainframe leri
daha eski olan EBCDIC kodlamasn kullanr. Unicode ismi verilen daha gelitirilmi bir
karakter kodlamas vardr ki karakterler 2-4 byte'lk alanda temsil edildikleri iin bu
kodlamada dnyada var olan tm karakterlerin yer almas hedeflenmitir. Gelecekte
birok makinenin bu karakter kodlamasn destekleyecek biimde tasarlanaca
dnlyor.

Karakter Deimezleri Nerede Kullanlr

Karakter deimezleri tamsay deimezleridir. Ancak C'de daha ok bir yaz bilgisi ile
ilgili kullanrlar. Yazlar karakter deimezleri ile deerlerini alabilecekleri gibi, bir yaznn
deitirilmesi amacyla karakter deimezleri kullanlabilir.

Karakter Deimezleri int Trdendir

C'de karakter deimezleri int trden olarak ele alnr ve ileme sokulur. Bu konu "tr
dnmleri" blmnde ele alnacak.

Gerek Say Deimezleri

Gerek say deimezleri (floating constants) deerleri gerek say olan deimezlerdir.
C dilinde bir gerek say deimezi float, double ya da long double trden olabilir. C89
standartlarna gre bir gerek say deimezi yalnzca onluk say sistemi kullanlarak
yazlabilir.

float Trden Deimezler


Nokta ieren,'f' ya da 'F' soneki alm deimezler, float trdendir. rnein:
1.31F
10.F
-2.456f
float trden deimezlerdir.

51/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

double Trden Deimezler


Nokta ieren 'f' ya da 'F' soneki almam deimezler ile float tr snrn ya da
duyarln am deimezler double trden deimezler olarak deerlendirilir. rnein:
-24.5 double trden deimezdir.

long double Trden Deimezler


long double trden deimezler noktal ya da stel biimdeki saylarn sonuna 'l' ya da
'L' getirilerek elde edilir:
1.34L
10.2L
long double trden deimezlerdir.

Gerek Say Deimezlerinin stel Biimde Yazlmas

Gerek say deimezleri stel biimde (scientific notation) yazlabilir. Bunun iin
deimezin sonuna 'e' ya da 'E' eki getirilir. Bu, saynn on zeri bir arpanla
arpldn gsterir. 'E' ya da 'e' karakterlerini '+', '-' ya da dorudan bir rakam
karakteri izleyebilir.
2.3e+04f
1.74e-6F
8.e+9f
burada e, 10 'un ss anlamna gelir:
1.34E-2f ile 0.0134
-1.2E+2F ile 120.f
ayn deimezlerdir.

52/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

LEVLER
lev Nedir?

C'de alt programlara ilev (function) denir. ngilizcedeki "function" szc bu balamda
matematiksel anlamyla deil dier programlama dillerinde ya da ortamlarnda kullanlan,
"alt program", "prosedr", szcklerinin karl olarak kullanlr.
Bir ilev, bamsz olarak altrlabilen bir program parasdr.

Program levlere Blerek Yazmann Faydalar

Bir program alt programlara yani ilevlere blerek yazmak baz faydalar salar:
1. Programn kaynak kodu klr. Bylece oluturulmas hedeflenen alabilir dosya da
(rnein .exe uzantl dosya) klr.
2. Kaynak dosyann okunabilirlii artar. Okunabilirliin artmas, kodu yazann ve okuyann
iini kolaylatrr. Bylece proje gelitirme sresinin azalmas ynnde kazanm salanm
olur.
3. Belirli kod paralarnn programn farkl yerlerinde yinelenmesi, programda yaplacak
olas bir deiikliin maliyetini artrr. Programn farkl yerlerinde, kodun kullanld yere
bal olarak deiiklikler yapmak gerekir. Kaynak dosyalarda byle deiiklikler yapmak
hem zaman alcdr hem de risklidir. nk bir deiikliin yaplmasnn unutulmas
durumunda ya da deiiklik yaplmamas gereken bir yerde kodun deitirilmesi
durumunda program yanl alabilir. Oysa ortak kod paralar ilevler eklinde
paketlendiinde, yalnzca ilevlerde deiiklik yaplmasyla, istenen deiiklik
gerekletirilmi olur.
4. Programda hata arama daha kolay gerekletirilir. Projelerdeki hata arama maliyeti
azalr.
5. Yazlan ilevler baka projelerde de kullanlabilir. Alt programlar tekrar kullanlabilir
(reusable) bir birim olutururlar. Bylelikle de projelerdeki kodlama giderlerini azaltrlar.
levler C'nin temel yap talardr. altrlabilen bir C program en az bir C ilevinden
oluur. Bir C programnn oluturulmasnda ilev saysnda bir kstlama yoktur.
levlerin onlar aran ilevlerden aldklar girdileri ve yine onlar aran ilevlere
gnderdikleri ktlar vardr. levlerin girdilerine aktel parametreler (actual parameters)
ya da argmanlar (arguments) denir. levlerin ktlarna ise geri dn deeri (return
value) diyoruz.
Bir ilev balca iki farkl amala kullanlabilir:
1. lev, almas sresince belli ilemleri yaparak belirli amalar gerekletirir.
2. lev, almas sonunda retecei bir deeri kendisini aran ileve gnderebilir.

levlerin Tanmlanmas ve arlmas

Bir ilevin ne i yapacann ve bu ii nasl yapacann C dilinin szdizimi kurallarna


uygun olarak anlatlmasna, yani o ilevin C kodunun yazlmasna, o ilevin tanm
(definition) denir. lev tanmlamalar C dilinin szdizimi kurallarna uymak zorundadr.
Bir ilev ars (call / invocation) ise o ilevin kodunun almaya davet edilmesi
anlamna gelir. lev ar ifadesi karlnda derleyici, programn akn ilgili ilevin
kodunun bulunduu blgeye aktaracak ekilde bir kod retir. Programn ak ilevin kodu
iinde akp bu kodu bitirdiinde, yani ilevin almas bittiinde, programn ak yine
ilevin arld noktaya geri dner. Bir ileve yaplacak ar da yine baz szdizimi
kurallarna uymaldr.

53/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

levlerin Geri Dn Deerleri

Bir ilevin yrtlmesi sonunda onu aran ileve gnderdii deere, ilevin geri dn
deeri (return value) denir. Her ilev bir geri dn deeri retmek zorunda deildir. Bir
ilev yapaca bir ile ilgili olarak bir geri dn deeri retir ya da retmez.
levlerin geri dn deerleri farkl amalar iin kullanlabilir:
1. Baz ilevler zaten tek bir deeri elde etmek, tek bir deeri hesaplamak amacyla
tanmlanrlar. Elde ettikleri deeri de kendilerini aran ilevlere geri dn deeri olarak
iletirler. Bir kpn hacim deerini bulan bir ilev tanmladmz dnelim. Byle bir
ilev, hacmini bulaca kpn kenar uzunluunu arld yerden alr, bu deeri
kullanarak hacim deerini hesap eder, hesap ettii deeri darya geri dn deeri
olarak iletebilir.
2. Her ilevin amac bir deer hesaplamak deildir. Baz ilevler ise arlmalaryla
kendilerine sorulan bir soruya yant verirler. rnein bir saynn asal olup olmadn
snayan bir ilev tanmlandn dnelim. lev arld yerden, asalln snayaca
deeri alr. Tanmnda bulunan baz kodlar ile saynn asal olup olmadn snar. Saynn
asal ya da asal olmamasna gre darya iki farkl deerden birini geri dn deeri
olarak gnderebilir. Bu durumda ilevin geri dn deeri, hesap edilen bir deer deil,
sorunun yant olarak yorumlanacak bir deerdir.
3. Baz ilevler ise ne bir deeri hesaplamak ne de bir soruya yant vermek iin
tanmlanrlar. Tanmlanma nedenleri yalnzca bir i yapmaktr. Ancak ilevin yapmas
istenen iin, baaryla yaplabilmesi konusunda bir garanti yoktur. rnein bir dosyay
amak iin bir ilev tanmlandn dnelim. lev arld yerden alacak dosyann
ismi bilgisini alyor olabilir. Ancak dosyann alabilmesi eitli nedenlerden dolay
gvence altnda deildir. arlan ilev istenen dosyay ya aar ya aamaz. lev geri
dn deeriyle yapt iin baars hakknda bilgi verir. Bu durumda ilevin geri dn
deeri, hesap edilen bir deer deil, yaplmas istenen iin baars konusunda verilen bir
bilgi olarak yorumlanr.
4. Baz ilevler hem belli bir amac gerekletirirler hem de buna ek olarak amalarn
tamamlayan bir geri dn deeri retirler. Bir yaz iinde bulunan belirli bir karakteri
silecek bir ilev tasarlandn dnelim. levin varlk nedeni yaznn iinden istenen
karakterleri silmektir. arld yerden, silme yapaca yazy ve silinecek karakterin ne
olduu bilgisini alr ve iini yapar. Ancak iini bitirdikten sonra yazdan ka karakter silmi
olduunu geri dn deeri ile arld yere bildirilebilir.
5. Baz ilevlerin ise hi geri dn deerleri olmaz.
i) levin amac yalnzca bir ii gerekletirmektir, yapt iin baars gvence altndadr.
rnein yalnzca ekran silme amacyla tasarlanm olan bir ilevin geri dn deerine
sahip olmas gereksizdir. Sistemlerin ounda kt ekrannn silinmesi konusunda bir
baarszlk riski yoktur.
ii) lev darya bir deer iletir ancak deeri iletme iini geri dn deeri ile deil de
baka bir arac kullanarak gerekletirir.
levlerin geri dn deerlerinin de trleri sz konusudur. levlerin geri dn deerleri
herhangi bir trden olabilir. Geri dn deerlerinin trleri, ilevlerin tanmlanmas
srasnda belirtilir.

levlerin Tanmlanmas

levlerin kodunun yazlmas iin tanmlama (definition) terimi kullanlr. C'de ilev
tanmlama ileminin genel biimi yledir:
[Geri dn deerinin tr] <ilev ismi> ([parametreler])
{
/***/
}

54/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yukardaki gsterimde bulunmas zorunlu szdizim elemanlar asal ayra iinde,


bulunmas zorunlu olmayan szdizim elemanlar ise keli ayra iinde belirtilmitir.
Tanmlanan ilevler en az bir blok iermelidir. Bu bloa ilevin ana blou denir. Ana blok
iinde istenildii kadar i ie blok yaratlabilir. Aadaki ilev tanmndan func isimli
ilevinin parametre almad ve geri dn deerinin de double trden olduu anlalr.
double func()
{
}
Yukardaki tanm inceleyin. nce ilevin geri dn deerinin trn gsteren anahtar
szck yazlr. Bildirim ve tanmlama konusunda anlatlan C'nin doal trlerini belirten
anahtar szck(ler) ile ilevin hangi trden bir geri dn deeri rettii belirtilir.
Yukarda tanmlanan func isimli ilevin geri dn deeri double trdendir.
Daha sonra ilevin ismi yazlr. levin ismi C dilinin isimlendirme kurallarna uygun
olarak seilmelidir. Geleneksel olarak ilev isimleri de, deiken isimleri gibi kk harf
youn olarak seilirler. lev ismini izleyen, alan ve kapanan ayralara ilevin parametre
ayralar denir. Bu ayracn iinde, ilevin parametre deikenleri denen deikenlerin
bildirimi yaplr. func isimli ilevin parametre ayracnn iinin bo braklmas bu ilevin
parametre deikenine sahip olmadn gsteriyor. Parametre ayracn alan ve kapanan
kme ayralar, yani bir blok izliyor. te bu bloa da ilevin ana blou (main block)
denir. Bu bloun iine ilevin kodlar yazlr.

void Anahtar Szc

Tanmlanan bir ilevin bir geri dn deeri retmesi zorunlu deildir. lev tanmnda bu
durum geri dn deerinin trnn yazld yere void anahtar szcnn yazlmasyla
anlatlr:
void func()
{
}
Yukarda tanmlanan func ilevi geri dn deeri retmiyor. Geri dn deeri
retmeyen ilevlere void ilevler denir.
lev tanmnda geri dn deerinin tr bilgisi yazlmayabilir. Bu durum, ilevin geri
dn deeri retmedii anlamna gelmez. Eer geri dn deeri tr bilgisi yazlmaz
ise, C derleyicileri tanmlanan ilevin int trden bir geri dn deerine sahip olduunu
varsayar. rnein:
func()
{
}
Yukarda tanmlanan func ilevinin geri dn deerinin tr int trdr. Yani ilevin
yukardaki tanmyla
int func()
{
}
tanm arasnda derleyici asndan bir fark yoktur. Geri dn deerinin trnn
yazlmamas gemie doru uyumluluk iin korunan bir kuraldr. int trne geri dnen bir
ilevin tanmnda int szcnn yazlmas tavsiye edilir.
[C++ dilinde ilev tanmnda geri dn deerinin trnn yazlmas zorunludur.]

55/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

levlerin Tanmlanma Yerleri

C dilinde bir ilev tanm iinde bir baka ilev tanmlanamaz. Yani isel ilev
tanmlamalarna izin verilmez. rnein aadaki gibi bir tanmlama geersizdir, nk
func ilevi tanmlanmakta olan foo ilevinin iinde tanmlanyor:
double foo()
{
/***/
int func() /* Geersiz */
{
/***/
}
/***/
}
Tanmlamann aadaki biimde yaplmas gerekirdi:
double foo()
{
/***/
}
int func()
{
/***/
}

levlerin Geri Dn Deerlerinin Oluturulmas

C dilinde ilevlerin geri dn deerleri return deyimi (return statement) ile oluturulur.
return deyiminin iki ayr biimi vardr:
return;
Ya da return anahtar szcn bir ifade izler:
return x * y;
return anahtar szcnn yanndaki ifadenin deeri, geri dn deeri olarak, ilevi
aran kod parasna iletilir.
return ifadesinin deiken iermesi bir zorunluluk deildir. Bir ilev bir deimez deerle
de geri dnebilir.
return 1;
return deyiminin bir baka ilevi de iinde bulunduu ilevi sonlandrmasdr. Bir ilevin
kodunun yrtlmesi srasnda return deyimi grldnde ilevin almas sona erer.
int func()
{
/**/
return x * y;
}
Yukardaki rnekteki func ilevinde return anahtar szcnn yannda yer alan x * y
ifadesi ile oluturulan return deyimi, func ilevini sonlandryor, func ilevinin bir geri
dn deeri retmesini salyor.

56/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Baz programclar return ifadesini bir ayra iinde yazarlar. Bu ayra return deyimine ek
bir anlam katmaz. Yani
return x * y;
gibi bir deyim
return (x * y);
biiminde de yazlabilir. Okunabilirlik asndan zellikle uzun return ifadelerinde ayra
kullanm salk verilir.
return (a * b - c * d);
Bir ilevin tanmnda ilevin geri dn deeri tr yazlmsa, bu ilevin tanm iinde
return deyimiyle bir geri dn deeri retilmelidir. Bu mantksal bir gerekliliktir. Ancak
return deyimiyle bir geri dn deeri retilmemesi derleme zaman hatasna neden
olmaz. Bu durumda ilevin almas ilevin ana blounun sonuna gelindiinde sona erer ,
ilev arld yere bir p deeri iletir. Bu da istenmeyen bir durumdur. C
derleyicilerinin ou, geri dn deeri retecei yolunda bilgi verilen bir ilevin return
deyimiyle bir deer retmemesini mantksal bir uyar iletisiyle iaretler.
"Warning: Function func should return a value"
Geri dn deeri retmeyen ilevlerde, yani void ilevlerde, return anahtar szc
yannda bir ifade olmakszn tek bana da kullanlabilir:
return;
Bu durumda return deyimi iinde yer ald ilevi, geri dn deeri oluturmadan
sonlandrr.
C dilinde ilevler yalnzca tek bir geri dn deeri retebilir. Bu da ilevlerin kendilerini
aran ilevlere ancak bir tane deeri geri gnderebilmeleri anlamna gelir. Ancak,
ilevlerin birden fazla deeri ya da bilgiyi kendilerini aran ilevlere iletmeleri
gerekiyorsa, C dilinde bunu salayacak baka aralar vardr. Bu aralar daha sonraki
blmlerde ayrntl olarak greceksiniz.

main levi

main de dier ilevler gibi bir ilevdir, ayn tanmlama kurallarna uyar. C programlarnn
almas, ismi main olan ilevden balar. C programlar zel bir ilem yaplmamsa,
main ilevinin almasnn bitiiyle sonlanr. main ilevine sahip olmayan bir kaynak
dosyann derlenmesinde bir sorun kmaz. Ancak balama (linking) aamasnda balayc
main ilevinin bulunmadn grnce balama ilemini gerekletiremez. Balayc
programlar bu durumda bir hata iletisi verir.
int main()
{
return 0;
}
Biiminde tanmlanm bir main ilevi de int trden bir deer dndrmelidir. main
ilevinin rettii geri dn deeri, programn almas bittikten sonra iletim sistemine
iletilir.
Geleneksel olarak, main ilevinin 0 deerine geri dnmesi programn sorunsuz bir ekilde
sonlandrld anlamna gelir. main ilevinin 0 dnda bir deere geri dnmesi ise, kodu
okuyan tarafndan programn baarszlkla sona erdirildii biiminde yorumlanr. Yani baz
nedenlerle yaplmak istenenler yaplamam, bu nedenle main ilevi sonlandrlmtr.

57/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

main ilevi geri dn deeri reteceini bildirmi olmasna karn return deyimiyle belirli
bir deeri geri dndrmezse, main ilevinden de bir p deeri gnderilir.
Derleyicilerin ou, main ilevinin geri dn deeri retmemesi durumunda da bir
mantksal uyar iletisi retir.
Dier taraftan main ilevi de void bir ilev olarak tanmlanabilir:
void main()
{
}
Ancak bir szdizimi hatas olmamasna karn main ilevinin void bir ilev olarak
tanmlanmas doru kabul edilmez.

levlerin arlmas

C dilinde bir ilev ars (function call - function invocation), ismi ilev ar ileci olan
bir ile ile yaplr. lev ar ileci olarak () atomlar kullanlr. arlacak ilevin ismi bu
ileten nce yazlr.
func();
Yukarda deyim ile func isimli ilev arlr.
Bir ilev arld zaman programn ak, ilevin kodunun yrtlmesi iin bellekte
ilevin kodunun bulunduu blgeye atlar. levin kodunun altrlmas ilemi bittikten
sonra da ak yine aran ilevin kalnan yerinden srer.
Bir ilevin geri dn deeri varsa, ilev ar ifadesi, ilevin geri dn deerini retir.
Geri dn deeri reten bir ileve yaplan ar ifadesi sz konusu ilevin rettii geri
dn deerine edeerdir.
levin geri dn deeri bir deikene atanabilecei gibi dorudan aritmetik ilemlerde
de kullanlabilir. rnein:
sonuc = hesapla();
Burada hesapla ilevine yaplan ar ifadesiyle retilen geri dn deeri, sonuc isimli
deikene atanr. Bir baka deyile bir ilev ar ifadesinin rettii deer, ilgili ilevin
rettii (eer retiyorsa) geri dn deeridir. Yukardaki rnekte nce hesapla() ilevi
arlr, daha sonra ilevin kodunun altrlmasyla elde edilen geri dn deeri sonuc
deikenine atanr.
lev ar ifadeleri nesne gstermez yani sol taraf deeri (L value) deildir. Yani C
dilinde aadaki gibi bir atama deyimi geersizdir:
func() = 5;

/* Geersiz */

levlerin geri dn deerleri sa taraf deeridir.


sonuc = func1() + func2() + x + 10;
gibi bir ifade geerlidir. arlm olan func1 ve func2 ilevleri altrlarak retilen geri
dn deerleri ile x deikeni iindeki deer ve 10 deimezi toplanr. fadeden elde
edilen deer, sonuc isimli deikene atanr.

lev arlarnn Yeri

levler, ancak tanmlanm ilevlerin iinden arlabilirler. Bloklarn dndan ilev


arlamaz.
[C++ dilinde blok dnda yazlan ilkdeer verme deyimlerinde ilkdeer verici (initializer) ifade bir ilev ars
olabilir.]

58/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

aran ilev ile arlan ilevin her ikisi de ayn ama kod (object code) iinde bulunmak
zorunda deildir. aran ilev ile arlan ilev farkl ama kodlar iinde bulunabilir.
nk derleme ilemi srasnda bir ilevin arldn gren derleyici, ama kod iine
arlan ilevin adn ve ar biimini yazar. aran ilev ile arlan ilev arasnda
balant kurma ilemi, balama aamasnda balayc program (linker) tarafndan yaplr.
Bu nedenle tanmlanan bir ilev iinde, tanml olmayan bir ilev arlsa bile derleme
aamasnda bir hata olumaz. Hata balama aamasnda oluur. nk balayc arlan
ilevi bulamaz.

lev Parametre Deikenlerinin Tanmlanmas

levler arldklar yerlerden alacaklar bilgileri, ilev ar ifadeleri ile alrlar. Bir ilevin
formal parametreleri (formal parameters) ya da parametre deikenleri, ilevlerin
kendilerini aran ilevlerden aldklar girdileri tutan deikenleridir. Bir ilevin parametre
says ve bu parametrelerin trleri gibi bilgiler, ilevlerin tanmlanmas srasnda
derleyiciye bildirilir. lev ars ile gnderilen argman ifadelerin deerleri, ilevin ilgili
parametre deikenlerine kopyalanr.
rnein bir kpn hacmini hesaplayan ilev, arld yerden bir kpn kenar
uzunluunu alacana gre, bu deerin kopyalanmas iin, bir parametre deikenine
sahip olmas gerekir. Benzer ekilde iki saydan daha byk olann bulan bir ilevin iki
tane parametre deikenine sahip olmas gerekir.
C dilinde ilevlerin tanmlanmasnda kullanlan iki temel biim vardr. Bu biimler
birbirlerinden ilev parametrelerinin derleyicilere tantlma ekli ile ayrlrlar. Bu
biimlerden birincisi eski biim (old style) ikincisi ise yeni biim (new style) olarak
adlandrlr.
Eski biim hemen hemen hi kullanlmaz, ama C standartlarna gre halen geerlidir. Bu
biimin korunmasnn nedeni gemie doru uyumluluun salanmasdr. Kullanlmas
gereken kesinlikle yeni biimdir. Ancak eski kodlarn ya da eski kaynak kitaplarn
incelenmesi durumunda bunlarn anlalabilmesi iin eski biimin de renilmesi gerekir.

Eski Biim

Eski biimde (old style), ilevin parametre deikenlerinin yalnzca isimleri, ilev
parametre ayralar iinde yazlr. Eer parametre deikenleri birden fazla ise aralarna
virgl atomu koyulur. Daha sonra bu deikenlerin bildirimi yaplr. Bu bildirimler daha
nce rendiimiz, C dilinin bildirim kurallarna uygun olarak yaplr. rnek:
double alan(x, y)
double x, y;
{
return x * y;
}
Yukarda tanmlanan alan ilevinin iki parametre deikeni vardr ve bu parametre
deikenlerinin isimleri x ve y'dir. Her iki parametre deikeni de double trdendir.
levin geri dn deeri double trdendir.
int func (a, b, c)
int a;
double b;
long c;
{
/***/
}
Bu rnekte ise func ilevi parametre deikenine sahiptir. Parametre deikenlerinin
isimleri a, b ve c'dir. smi a olan parametre deikeni int trden, b olan double trden ve
ismi c olan ise long trdendir.

59/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Eski biim, yeni biime gre uzundur. nk ilev ayralarnn iinde ismi yer alan
parametre deikenleri alt satrlarda yeniden bildirilir.

Yeni Biim

Yeni biimde (new style), eski biime gre hem daha ksadr hem de okunabilmesi eski
biime gre ok daha kolaydr.
Yeni biimde ilev parametre deikenlerinin bildirimi ilev ayralarnn iinde yalnzca bir
kez yaplr. Bu biimde, ilevin ayralarnn iine parametre deikenin tr ve yanna da
ismi yazlr. Eer birden fazla ilev parametre deikeni varsa bunlar virgllerle ayrlr,
ancak her bir deikenin tr bilgisi yeniden yazlr. rnek :
int func(int x, int y)
{
/***/
}
double foo(double a, int b)
{
/***/
}
lev parametre deikenleri ayn trden olsa bile her defasnda tr bilgisinin yeniden
yazlmas zorunludur. rnein:
int foo (double x, y)
{
/***/
}

/* Geersiz */

bildirimi hataldr. Doru tanmlama aadaki biimde olmaldr:


int foo (double x, double y)
{
/***/
}
[C++ dilinde eski biim ilev tanmlamalar geerli deildir.]

Parametre Deikenine Sahip Olmayan levler

Her ilev parametre deikenine sahip olmak zorunda deildir. Baz ilevler istenen bir ii
yapabilmek iin dardan bilgi almaz. Parametre deikenine sahip olmayan bir ilevin
tanmnda, ilev parametre ayracnn ii bo braklr. lev parametre ayracnn iine void
anahtar szcnn yazlmas durumunda da ilevin parametre deikenine sahip
olmad sonucu kar.
int foo()
{
/***/
}
ile
int foo(void)
{
/***/
}

60/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

tamamen ayn anlamdadr

Argmanlarn Parametre Deikenlerine Kopyalanmas

Bir ilevin parametre deikenleri, o ilevin arlma ifadesiyle kendisine gnderilen


argmanlar tutacak olan yerel deikenlerdir. rnek:
void func(int a)
{
/***/
}
int main()
{
int x = 10;
/***/
func (x);
}

return 0;

Yukardaki rnekte main ilevi iinde, func isimli ilev arlyor ve arlan ileve x isimli
deikenin deeri argman olarak geiliyor. lev ars, programn alma zamannda,
programn aknn func ilevinin kodunun bulunduu yere sramasna neden olur. func
ilevindeki a isimli parametre deikeni iin bellekte bir yer ayrlr ve a parametre
deikenine argman olan ifadenin deeri, yani x deikeninin deeri atanr. Yani
int a = x;
ileminin derleyicinin rettii kod sonucu otomatik olarak yapld sylenebilir.
int main()
{
int x = 100, y = 200, z;
z = add(x, y);
/***/
return 0;
}
int add(int a, int b)
{
return a + b;
}
Yukarda tanmlanan add ilevi arldnda programn ak bu ileve gemeden nce, x
ve y deikenlerinin iinde bulunan deerler, add ilevinin parametre deikenleri olan a
ve b'ye kopyalanr.

lev ar fadelerinin Kullanmlar

1. Geri dn deeri retmeyen bir ileve yaplan ar, genellikle kendi bana bir deyim
oluturur. Byle bir ileve yaplan ar, bir ifadenin paras olarak kullanlmaz. lev
arsn genellikle sonlandrc atom izler;

61/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

void func()
{
/***/
}
int main()
{
func();
return 0;
}
2. Geri dn deeri reten ilevlerin rettii deerlerin kullanlmas zorunlu deildir.
Ancak baz ilevlerin geri dn deerlerinin kullanlmamas mantksal bir yanllk
olabilir. ki saynn toplam deerine geri dnen bir ilev tanmlandn dnelim. Byle
bir ilev arld yerden iki deer alarak bunlarn toplam deerine geri dnyor olsun.
Byle bir ilevin varlk nedeni bir deer hesaplamaktr. levin hesaplad deer
kullanlmyorsa ilev bo yere arlm, ilevin kodu bo yere alm olur.
Ancak baz ilevler bir i yaptklar gibi yaptklar ile ilgili tamamlayc bir bilgiyi de geri
dndrr. Byle bir ilev yalnzca yapt i iin arlabilir. Yani ilevi aran kod paras
ilevin geri dndrd deer ile ilgilenmeyebilir.
rnein foo() ilevi int trden bir deeri geri dn deeri reten ilev olsun.
a = foo();
Yukardaki ifadede foo ilevinin geri dn deeri a isimli deikene atanr. Bu ilev bir
kez arlmasna karn artk geri dn deeri a deikeninde tutulduu iin, bu geri
dn deerine ilev yeniden arlmadan istenildii zaman ulalabilir. Ancak:
foo();
eklinde bir ilev ar ifadesinde geri dn deeri bir deikende saklanmaz. Bu
duruma geri dn deerinin kullanlmamas (discarded return value) denir.
3. Sk karlalan durumlardan biri de, bir ilev arsyla elde edilen geri dn deerinin
bir baka ilev arsnda argman olarak kullanlmasdr. Aadaki rnei inceleyin:
int add(int a, int b)
{
return a + b;
}
int square(int a)
{
return a * a;
}
int main()
{
int x = 10;
int y = 25;
int z = square(add(x, y));
}

return 0;

Yukarda tanmlanan add ilevi, iki tamsaynn toplam deeri ile geri dnerken, square
ilevi ise dardan ald deerin karesi ile geri dnyor. main ilevi iinde yaplan

62/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

square(add(x, y));
ars ile add ilevinin geri dn deeri square ilevine argman olarak geiliyor.
4. Bir ilevin rettii geri dn deeri bir baka ilevin return deyiminde return ifadesi
olarak kullanlabilir. Bir baka deyile, bir ilev geri dn deerini bir baka ilevi
ararak oluturabilir. ki saynn karelerinin toplamna geri dnen sum_square isimli bir
ilev tanmlanmak istensin:
int sum_square(int a, int b)
{
return add(square(a), square(b));
}
Tanmlanan sum_square ilevi daha nce tanmlanm add ilevine yaplan arnn
rettii geri dn deeri ile geri dnyor. add ilevine gnderilen argmanlarn da,
square ilevine yaplan arlardan elde edildiini gryorsunuz.

levlerin Kendi Kendini armas

Bir ilev kendisini de arabilir. Kendisini aran bir ileve zyinelemeli ilev (recursive
function) denir. Bir ilev kendini neden arr? Byle ilevlerle hedeflenen nedir? Bu konu
ileride ayr bir balk altnda ele alnacak.

63/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Standart C levleri

Standard C ilevleri, C dilinin standartlatrlmasndan sonra, her derleyicide bulunmas


zorunlu hale getirilmi ilevlerdir. Yani derleyicileri yazanlar standart C ilevlerini kendi
derleyicilerinde mutlaka tanmlamak zorundadrlar. Bu durum C dilinin tanabilirliini
(portability) artran ana etmenlerden biridir.
Bir ilevin derleyiciyi yazanlar tarafndan tanmlanm ve derleyici paketine eklenmi
olmas, o ilevin standart C ilevi olduu anlamna gelmez. Derleyiciyi yazanlar
programcnn iini kolaylatrmak iin ok eitli ilevleri yazarak derleyici paketlerine
eklerler. Ama bu tr ilevlerin kullanlmas durumunda, oluturulan kaynak kodun baka
bir derleyicide derlenebilmesi ynnde bir gvence yoktur, yani artk kaynak kodun
tanabilirlii azalr. rnein printf ilevi standart bir C ilevidir. Yani printf ilevi her
derleyici paketinde ayn isimle bulunmak zorundadr.
Standart C ilevlerinin derlenmi kodlar zel ktphanelerin iindedir. Balk dosyalar
iinde, yani uzants .h biiminde olan dosyalarn iinde standart C ilevlerinin bildirimleri
bulunur. lev bildirimi konusu ileride ayrntl bir biimde incelenecek.
Ktphaneler (libraries), derlenmi dosyalardan oluur. DOS iletim sisteminde
ktphane dosyalarnn uzants .lib, UNIX iletim sisteminde ise .a (archive) biimindedir.
WINDOWS altnda uzants .dll biiminde olan dinamik ktphaneler de bulunur.
Derleyicileri yazanlar tarafndan kaynak kodu yazlm standart C ilevleri nce derlenerek
.obj haline getirilirler ve daha sonra ayn gruptaki dier ilevlerin .obj halleriyle birlikte
ktphane dosyalarnn iine yerletirilirler. Standart C ilevleri balama aamasnda,
balayc (linker) tarafndan alabilir (.exe) kod iine yazlrlar. Tmleik alan
derleyicilerde balayclar, ama kod iinde bulamadklar ilevleri, yerleri nceden
belirlenmi ktphaneler iinde arar. Oysa komut satrl uyarlamalarda (command line
version) balayclarn hangi ktphanelere bakaca komut satrnda belirtilir.

Neden Standart levler

Baz ilevlerin bulunmasnn dilin standartlar tarafndan gvence altna alnmas ile
aadaki faydalar salanm olur.
i) Baz ilemler iin ortak bir arayz salanm olur.
Mutlak deer hesaplayan bir ilevi yazmak ok kolaydr. Ancak standart bir C ilevi olan
abs ilevinin kullanlmasyla ortak bir arayz salanr. Her kaynak kod kendi mutlak deer
hesaplayan ilevini tanmlam olsayd, tanmlanan ilevlerin isimleri, parametrik yaplar
farkl olabilirdi. Bu durum da kod okuma ve yazma sresini uzatrd.
ii) Baz ileri gerekletirecek ilevlerin kodlar sistemden sisteme farkllk gsterebilir. Bu
da kaynak dosyann tanabilirliini azaltr. Bu ilemleri yapan standart ilevlerin
tanmlanm olmas kaynak kodun baka sistemlere tanabilirlii artrr.
iii) Baz ilevlerin yazlmas belirli bir alanda bilgi sahibi olmay gerektirebilir. rnein bir
gerek saynn bir baka gerek say ssn hesaplayan bir ilevi verimli bir ekilde
yazabilmek iin yeterli matematik bilgisine sahip olmak gerekir.
iv) Sk yaplan ilemlerin standart olarak tanmlanm olmas, programcnn yazaca kod
miktarn azaltr. Bylece proje gelitirme sresi de ksalr.
v) Derleyicilerin salad standart ilevler ok sayda programc tarafndan kullanlm
olduu iin ok iyi derecede test edilmilerdir. Bu ilevlerin tanmlarnda bir hata olma
olasl, programcnn kendi yazaca ilevlerle kyaslandnda ok dktr.
yi bir C programcsnn C dilinin standart ilevlerini ok iyi tanmas ve bu ilevleri yetkin
bir ekilde kullanabilmesi gerekir.

64/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

printf levi

printf standart bir C ilevidir. printf ilevi ile ekrana bir yaz yazdrlabilecei gibi, bir
ifadenin deeri de yazdrlabilir.
Deikenlerin iindeki deerler aslnda bellekte ikilik sistemde tutulur. Bir deikenin
deerinin ekrana, hangi say sisteminde ve nasl yazdrlaca programcnn isteine
baldr. Deikenlerin deerlerinin ekrana yazdrlmasnda standart printf ilevi kullanlr.
printf aslnda ok ayrntl zelliklere sahip bir ilevdir. imdilik iinize yarayacak kadar
ayrnty reneceksiniz. printf ilevlerle ilgili yukarda aklanan genel kurallara uymaz.
printf ilevi deiken sayda parametreye sahip bir ilevdir. Bir ilevin ka tane parametre
deikeni varsa o ilev arldnda, ileve o kadar argman geilmelidir, deil mi? Oysa
printf ilevine istenen sayda argman geilebilir. Bu ileve ka tane argman geilirse
ilevin o kadar sayda parametre deikenine sahip olaca dnlebilir. Bu nasl oluyor?
Deiken sayda parametreye sahip ilevler ileri bir konu olduundan, bu konu ancak
sonraki blmlerde ele alnacak.
printf ilevine ilk gnderilen argman genellikle ift trnak iinde yer alan bir yazdr. ift
trnak iinde yer alan byle yazlara dizge (string) denir. Dizgeler konusu ileride ayr bir
blmde ele alnacak.
printf ilevine argman olarak geilen dizge iinde yer alan tm karakterler ekrana
yazlr. Ancak printf ilevi dizge iindeki % karakterini ve bunu izleyen belirli sayda
karakteri ekrana yazmaz. lev, dizge iindeki % karakterlerini yanndaki belirli sayda
karakter ile birlikte formatlama karakterleri (conversion specifiers) olarak yorumlar.
Formatlama karakterleri, ift trnaktan sonra yazlan argmanlarla bire bir eletirilir.
Formatlama karakterleri nceden belirlenmitir, kendileriyle elenen bir ifadenin deerinin
ekrana ne ekilde yazdrlaca bilgisini ileve aktarrlar. Bu format bilgisi
*
*
*
*
*
*

Argman olan ifadenin hangi trden olarak yorumlanaca


fadenin deerinin ekrana hangi say sistemi kullanlarak yazlaca
fadenin ka karakterlik bir alana yazdrlaca
Pozitif tamsaylarn yazmnda '+' karakterinin yazdrlp yazdrlmayaca
Gerek saylarn yazmnda stel notasyonun kullanlp kullanlmayaca
Gerek saylarn yazmnda noktadan sonra ka basaman yazlaca

gibi aklamalardr. Aadaki program inceleyin:


#include <stdio.h>
int main()
{
int x = 25;
double pi = 3.1415;
printf("x = %d\npi = %lf\n", x, pi);
return 0;
}
main ilevi iinde yaplan
printf("x = %d\npi = %lf\n", x, pi);
arsnda ileve gnderilen birinci argman olan ift trnak iindeki yazda iki ayr format
dizgesi kullanlyor: %d ve %lf.
%d format karakterleri ikinci argman olan x ile, %lf format karakterleri ise 3. argman
olan pi ile eleniyor. Format karakterleri ile elenen ifadelerin deerleri, istenen
formatlama zellikleri ile ekrana yazlr. rnein yukardaki aryla ekrana
x = 25
pi = 3.14150

65/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

yazs yazdrlr.
Aada formatlama karakterlerinden bazlarnn anlam veriliyor. printf ilevi ileride
ayrntl olarak ele alnacak.
Format
karakteri
%d
%ld
%x

%X

%lx
%u
%o
%f
%lf
%e
%c
%s

Anlam
Bir ifadeyi int trden yorumlayarak, elde ettii deeri onluk say sisteminde
yazar.
Bir ifadeyi long trden yorumlayarak, elde ettii deeri onluk say sisteminde
yazar.
Bir ifadeyi unsigned int trden yorumlayarak, elde ettii deeri onaltlk say
sisteminde yazar. Basamak sembolleri olarak a, b, c, d, e, f (kk)
harflerini kullanr.
Bir ifadeyi unsigned int trden yorumlayarak, elde ettii deeri onaltlk say
sisteminde yazar. Basamak simgeleri olarak A, B, C, D, E, F (byk)
harflerini kullanr.
Bir ifadeyi unsigned long trnden yorumlayarak, onaltlk say sisteminde
yazar.
Bir ifadeyi unsigned int trnden yorumlayarak, onluk say sisteminde yazar.
Bir ifadeyi unsigned int trnden yorumlayarak, sekizlik say sisteminde
yazar
float ve double trlerinden ifadelerin deerlerini onluk say sisteminde
yazar.
double ve long double trlerinden ifadelerin deerlerini onluk say sisteminde
yazar.
Gerek saylar stel biimde yazar.
char veya int trnden bir ifadeyi bir karakterin sra numaras olarak
yorumlayarak, ilgili karakterin grnts ekrana yazdrr.
Verilen adresteki yazy ekrana yazdrr.

Yukardaki tabloda grld gibi double tr hem %f format karakteri hem de %lf
format karakteri ile yazdrlabilir. Ama %lf okunabilirlii artrd iin daha ok tercih
edilir.
Yukardaki tabloya gre unsigned int trnden u isimli deikenin deeri aadaki
ekillerde yazdrabilir:
#include <stdio.h>
int main()
{
unsigned int u = 57054;
printf("u = %u\n", u); /* u deerini onluk sistemde yazar */
printf("u = %o\n", u); /* u deerini sekizlik sistemde yazar */
printf("u = %X\n", u); /* u deerini onaltlk sistemde yazar */
return 0;
}
long trden bir ifadenin deerini yazdrrken d, o, u ya da x karakterlerinden nce l
karakteri kullanlr:

66/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
int main()
{
long int lo = 23467;
unsigned long int unlo = 65242;
printf("unlo
printf("unlo
printf("unlo
printf("unlo
}

=
=
=
=

%ld\n",
%lu\n",
%lo\n",
%lX\n",

lo);
unlo);
unlo);
unlo);

/*
/*
/*
/*

onluk sistemde yazar */


onluk sistemde yazar */
sekizlik sistemde yazar */
onaltlk sistemde yazar */

return 0;

Yukardaki rneklerde unsigned int trden bir ifadenin deerinin printf ileviyle sekizlik ya
da onaltlk say sisteminde yazdrlabileceini grdnz. Peki iaretli trden bir
tamsaynn deeri sekizlik ya da onaltlk sistemde yazdrlamaz m? Yazdrlrsa ne olur?
Sz konusu iaretli tamsay pozitif olduu srece bir sorun olmaz. Saynn iaret biti 0
olduu iin saynn nicel bykln etkilemez. Yani doru deer ekrana yazlr, ama
say negatifse iaret biti 1 demektir. Bu durumda ekrana yazlacak saynn iaret biti de
nicel bykln bir paras olarak deerlendirilerek yazlr. Yani yazlan deer doru
olmaz.
% karakterinin yannda nceden belirlenmi bir format karakteri yoksa , % karakterinin
yanndaki karakter ekrana yazlr.
Yzde karakterinin kendisini ekrana yazdrmak iin format karakteri olarak %% kullanlr:
printf("%%25\n");

scanf levi

scanf ilevi, klavyeden her trl bilginin giriine olanak tanyan standart bir C ilevidir.
scanf ilevi de printf ilevi gibi aslnda ok ayrntl, geni kullanm zellikleri olan bir
ilevdir. Ancak bu noktada scanf ilevi yzeysel olarak ele alnacak.
scanf ilevinin de birinci parametresi bir dizgedir. Ancak bu dizge yalnzca klavyeden
alnacak bilgilere ilikin format karakterlerini ierir. printf ilevinde olduu gibi scanf
ilevinde de bu format karakterleri nceden belirlenmitir. % karakterinin yannda yer
alrlar. scanf ilevinin kulland format karakterlerinin printf ilevinde kullanlanlar ile
hemen hemen ayn olduu sylenebilir. Yalnzca gerek saylara ilikin format
karakterlerinde nemli bir farkllk vardr. printf ilevi %f format ile hem float hem de
double trden verileri ekrana yazabilirken scanf ilevi %f format karakterini yalnzca
float trden veriler iin kullanr. double tr iin scanf ilevinin kulland format
karakterleri %lf eklindedir. scanf ilevinin format ksmnda format karakterlerinden
baka bir ey olmamaldr. printf ilevi ift trnak iindeki format karakterleri dndaki
karakterleri ekrana yazyordu, ancak scanf ilevi format karakterleri dnda dizge iine
yazlan karakterleri ekrana basmaz, bu karakterler tamamen baka anlama gelir. Bu
nedenle ilevin nasl altn renmeden bu blgeye format karakterlerinden baka bir
ey koymayn. Buraya konulacak bir boluk bile farkl anlama gelir.

67/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
int main()
{
int x, y;
printf("iki say girin : ");
scanf("%d%d", &x, &y);
printf("%d + %d = %d\n", x, y, x + y);
return 0;
}
Yukardaki rnekte, program kullanan kiiye deer girmesinin beklendiini syleyen bir
yaz, printf ileviyle ekrana yazdrlyor. Bu i scanf ilevi ile yaplmazd. scanf ilevi ile
ekrana bir yaz yazdrmak mmkn deildir. scanf yalnzca giri amacyla tanmlanm bir
ilevdir, k ilemi yapmaz.
scanf("%d%d", &x, &y);
ars ile programn alma zamannda klavyeden girilecek deerler x ve y
deikenlerine aktarlr. x ve y deikenleri iin onluk say sisteminde klavyeden giri
yaplr. Giri arasna istenildii kadar boluk karakteri konulabilir. Yani ilk sayy girdikten
sonra SPACE, TAB ya da ENTER tuuna bastktan sonra ikinci deer girilebilir. rnein:
5 60
biiminde bir giri, geerli olaca gibi;
5
60
biiminde bir giri de geerlidir. scanf ilevine gnderilecek dier argmanlar & adres
ileci ile kullanlr. & bir gsterici ilecidir. Bu ileci gstericiler konusunda reneceksiniz.

Klavyeden Karakter Alan C levleri

Sistemlerin hemen hemen hepsinde klavyeden karakter alan ayr C ilevi bulunur. Bu
ilevlerin biri tam olarak standarttr ama dier ikisi sistemlerin hemen hemen hepsinde
bulunmasna karn standart C ilevi deildir. imdi bu ilevleri inceleyelim:

getchar levi

Standart bu ilevin parametrik yaps aadaki gibidir:


int getchar(void);
levin geri dn deeri klavyeden alnan karakterin, kullanlan karakter seti
tablosundaki sra numarasn gsteren int trden bir deerdir. getchar ilevi klavyeden
karakter almak iin enter tuuna gereksinim duyar.
Aada yazlan programda nce getchar ileviyle klavyeden bir karakter alnyor daha
sonra alnan karakter ve karakterin saysal deeri ekrana yazdrlyor.

68/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
int main()
{
char ch;
ch = getchar();
printf("\nKarakter olarak ch = %c\nASCII numaras ch = %d\n", ch, ch);
}

return 0;

getchar derleyicilerin ounda stdio.h balk dosyas iinde bir makro olarak tanmlanr.
Makrolar ile ileride tanacaksnz.

getch levi

Standart olmayan bu ilevin parametrik yaps ounlukla aadaki gibidir:


int getch(void);
getch standart bir C ilevi olmamasna karn neredeyse btn derleyici paketleri
tarafndan sunulur. Standart getchar ilevi gibi getch ilevi de klavyeden alnan
karakterin kullanlan karakter setindeki sra numarasyla geri dner. Sistemlerin ounda
bu ilevin getchar ilevinden iki fark vardr:
1. Baslan tu ekranda grnmez.
2. Sistemlerin ounda ENTER tuuna gereksinim duymaz.
Yukarda verilen programda getchar yerine getch yazarak program altrrsanz fark
daha iyi grebilirsiniz.
getch ilevi zellikle tu bekleme ya da onaylama amacyla kullanlr:
printf("devam iin herhangi bir tua basn...\n");
getch();
Burada klavyeden alnan karakterin ne olduunun bir nemi olmad iin ilevin geri
dn deeri kullanlmyor. Derleyici paketlerinin hemen hepsinde bu ilevin bildirimi
standart olmayan conio.h isimli balk dosyasnda olduundan, ilevin arld dosyaya
conio.h balk dosyas eklenmelidir:
#include <conio.h>
Bu ilem nilemci komutlar blmnde ayrntl ekilde ele alnacak.

getche levi

Standart olmayan bu ilevin parametrik yaps ounlukla aadaki gibidir:


int getche(void);
getche ngilizce get char echo szcklerinden ksaltlmtr. getche ilevi de baslan tuun
karakter setindeki sra numarasyla geri dner ve sistemlerin ounda enter tuuna
gereksinim duymaz. Ama klavyeden alnan karakter ekranda grnr.
Sistemlerin ounda
getchar
getch
getche

enter tuuna gereksinim duyar


enter tuuna gereksinim duymaz
enter tuuna gereksinim duymaz

69/529

alnan karakter ekranda grnr.


alnan karakter ekranda grnmez
alnan karakter ekranda grnr.

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Ekrana Bir Karakterin Grntsn Yazan C levleri

C dilinde ekrana bir karakterin grntsn basmak iin baz standart C ilevleri
kullanlabilir:

putchar levi

Bu standart ilevin parametrik yaps aadaki gibidir:


int putchar(int ch);
putchar standart bir C ilevidir. Btn sistemlerde bulunmas zorunludur. Parametresi
olan karakteri ekranda imlecin bulunduu yere yazar. rnein:
#include <stdio.h>
int main()
{
char ch;
ch = getchar();
putchar (ch);
}

return 0;

Yukardaki kodda putchar ilevinin yapt i printf ilevine de yaptrlabilirdi;


printf("%c", ch);
ile
putchar(ch)
tamamen ayn ii grr.
putchar ilevi ile '\n' karakterini yazdrldnda printf ilevinde olduu gibi imle sonraki
satrn bana geer. putchar ilevi ekrana yazlan karakterin ASCII karl ile geri dner.
putchar ilevi derleyicilerin ounda stdio.h balk dosyas iinde bir makro olarak
tanmlanmtr.

putch levi

Standart olmayan bu ilevin parametrik yaps ounlukla aadaki gibidir:


int putch(int ch);
putch standart bir C ilevi deildir. Dolaysyla sistemlerin hepsinde bulunmayabilir. Bu
ilevin putchar ilevinden tek fark '\n' karakterinin yazdrlmas srasnda ortaya kar.
putch, '\n" karakterine karlk yalnzca LF(line feed) (ASCII 10) karakterini yazar. Bu
durum imlecin bulunduu kolonu deitirmeksizin aa satra gemesine yol aar.

70/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yorum Satrlar

Kaynak dosya iinde yer alan nilemci ya da derleyici programa verilmeyen aklama
amal yazlara yorum satrlar (comment lines) denir.
Yorum satrlar /* atomuyla balar */ atomuyla sonlanr. Bu iki atom ile, bu iki atom
arasnda kalan tm karakterler, nilemci programn kaynak kodu ele almasndan nce
tek bir boluk karakteriyle yer deitirir. Yorum satrlar herhangi sayda karakter
ierebilir. rnek:
/* Bu bir aklama satrdr */
Yorum satrlar birden fazla satra ilikin olabilir:
/*

bu satirlar
kaynak koda dahil
deildir.

*/
Bir dizge ya da bir karakter deimezi iinde yorum satr bulunamaz:
#include <stdio.h>
int main()
{
printf("/* bu bir yorum satiri degildir */");
return 0;
}
Yukardaki programn derlenip altrlmasyla, ekrana
/* bu bir yorum satr deil */
yazs yazdrlr.
Bir yorum satrnn kapatlmasnn unutulmas tipik bir hatadr.
#include <stdio.h>
int main()
{
int x = 1;
int y = 2;
x = 10;
y = 2;

/* x'e 10 deeri atanyor


/* y'ye 20 deeri atanmyor */

printf("x = %d\n", x);


printf("y = %d\n", y);
return 0;
}
[C++ dilinde yorum satr oluturmann bir baka biimi daha vardr.
Yorum satr // karakterleriyle balar, bulunulan satrn sonuna kadar srer. Yorum satrn sonlandrlmas
bulunulan satrn sonu ile olur, yorum satrn sonlandracak ayr bir karakter bulunmaz. rnek:
//Geerli bir Aklama satr
Bu biim C89 standartlarna gre geerli deildir ancak C99 standartlaryla C'ye de eklenmitir.]

71/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

e Yorum Satrlar

ie yorum satrlar (nested comment lines) oluturmak geerli deildir:


/*
*/

/*
*/

Yukardaki rnekte birinci */ atomundan sonraki kod paras kaynak dosyaya dahildir.
Ancak derleyicilerin ou uygun ayarlarn seilmesiyle i ie yorum satrlarna izin verir.
ie yorum satrlarna gereksinim, zellikle bir yorum satrnn kopyalanarak baka bir
yorum satr iine yaptrlmas durumunda oluur. Bazen de, yorum satr iine alnmak
istenen kod parasnn iinde de bir baka yorum satr olduundan, isel yorum satrlar
oluur.

Yorum Satrlar Neden Kullanlr

Yorum satrlar ou zaman kaynak kodun okunabilirliini artrmak iin kullanlr. Kaynak
koddan dorudan karlamayan bilgiler aklama satrlaryla okuyucuya iletilebilir.
Bazen de yorum satrlar bir kaynak dosyann blm balklarn oluturmak amacyla
kullanlr.
Kaynak kodun aka verdii bir bilgiyi, yorum satryla aklamak programn
okunabilirliini bozar.

72/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

LELER
le Nedir

leler, nesneler veya deimezler zerinde nceden tanmlanm birtakm ilemleri


yapan atomlardr. leler, mikroilemcinin bir ilem yapmasn ve bu ilem sonunda da
bir deer retilmesini salar. Programlama dillerinde tanmlanm olan her bir ile en az
bir makine komutuna karlk gelir.
Benzer ilemleri yapmalarna karlk programlama dillerinde ile atomlar birbirlerinden
farkllk gsterebilir.
C programlama dilinde ifadeler ounlukla ileleri de ierirler.
c = a * b / 2 + 3
++x * y-a >= b

/* 4 ile vardr ifadedeki srasyla =, *, /, +


/* 3 ile vardr, ifadedeki srasyla ++, *, -/* 1 ile vardr. >= */

*/
*/

Terim Nedir

lelerin ileme soktuklar nesne veya deimezlere terim (operand) denir. C'de ileler
aldklar terim saysna gre gruba ayrlabilir.

i) Tek terimli ileler (unary operators)


rnein ++ ve -- ileleri tek terimli ilelerdir.
ii) ki terimli ileler (binary operators)
Aritmetiksel ileler olan toplama '+' ve blme '/' ileleri rnek olarak verilebilir.
iii) terimli ile (ternary operator)
C'de terimli tek bir ile vardr. Bu ilecin ismi "koul ileci" dir(conditional operator).
leler konumlarna gre yani teriminin ya da terimlerinin neresinde bulunduklarna gre
de gruplanabilir:
1. Sonek Konumundaki leler (postfix operators)
Bu tip ileler terimlerinin arkasna getirilirler.
rnein sonek ++ ileci (x++)
2. nek Konumundaki leler (prefix operators)
Bu tip ileler terimlerinin nne getirilirler.
rnein mantksal deil ileci (!x)
3. Araek Konumundaki leler (infix operators)
Bu tip ileler terimlerinin aralarna getirilirler.
rnein aritmetik toplama ileci (x + y)

lelerin Deer retmesi

leler, yaptklar ilemin sonucunda bir deer retir. lelerin rettii deer, ayn ifade
iinde var olan bir baka ilece terim olabilir. fade iinde en son deerlendirilen ilecin
rettii deer ise ifadenin deeri olur. Bir ifadenin deeri, ifade iinde yer alan ilelerin
rettii deerlere gre saptanr.
lelerin en nemli zellii, yaptklar ilemin sonucu olarak bir deer retmeleridir.
Programc, bir ifade iinde ilelerin rettii deeri kullanr ya da kullanmaz. lelerin
rettii deer aadaki biimlerde kullanlabilir:
i. lecin rettii deer bir baka deikene aktarlabilir:
x = y + z;

73/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yukardaki rnekte y + z ifadesinin deeri, yani + ilecinin rettii deer, x deikenine


aktarlr.
ii. retilen deeri bir ileve argman olarak gnderilebilir:
func(y + z);
Yukardaki rnekte func ilevine argman olarak y + z ifadesinin deeri, yani toplama
ilecinin rettii deer gnderiliyor.
iii. retilen deer return deyimi ile ilevlerin geri dn deerlerinin oluturulmasnda
kullanlabilir:
int func()
{
return (y + z)
}
Yukarda func isimli ilevinin geri dn deeri y + z ifadesinin deeri yani + ilecinin
rettii deerdir.
lelerin rettii deerin hi kullanlmamas C szdizimi asndan bir hataya neden
olmaz. Ancak byle durumlarda derleyiciler ounlukla bir uyar iletisi vererek
programcy uyarr. rnein:
int main()
{
int x = 20;
int y = 10;
x + y;
}

return 0;

Yukardaki kod parasnda yer alan


x + y
ifadesinde '+' ileci bir deer retir. '+' ilecinin rettii deer terimlerinin toplam deeri,
yani 30'dur. Ancak bu deer kullanlmyor. Byle bir ilemin bilinli olarak yaplma
olasl dktr. Borland derleyicilerinde verilen uyar iletisi u ekildedir:
warning : "code has no effect!"
(uyar : "kodun etkisi yok")

lelerin ncelii

C dilinde ifadelerin trleri ve deerleri sz konusudur. Bir ifadenin deerini derleyici u


ekilde saptar: fade iindeki ileler ncelik sralarna gre deer retir, retilen
deerler, ifade iindeki ncelii daha az olan ilelere terim olarak aktarlr. Bu ilemin
sonunda tek bir deer elde edilir ki bu da ifadenin deeridir.
int x = 10;
int y = 3;
int z = 15;
printf("%d\n", z % y / 2 + 7 -x++ * y);

74/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yukardaki kod parasnda printf ilevi arsyla


x % y / 2 + 7 -x++ * y
ifadesinin deeri ekrana yazdrlr. Yazdrlan deer nedir? fade iindeki ileler ncelik
sralarna gre deer retir, retilen deerler, dier ilelerin terimi olur. En son kalan
deer ise ifadenin deeri, yani ekrana yazdrlan deer olur.
Her programlama dilinde ilelerin birbirlerine gre ncelii sz konusudur. Eer ncelik
kavram sz konusu olmasayd, ilelerin neden olaca ilemlerin sonular makineden
makineye, derleyiciden derleyiciye farkl olurdu.
C'de toplam 45 ile vardr. Bu ileler 15 ayr ncelik seviyesinde yer alr.
C dilinin ile ncelik tablosu blm sonunda verilmitir.
Bir ncelik seviyesinde eer birden fazla ile varsa, bu ilelerin ayn ifade iinde yer
almas durumunda, ilelerin soldan saa m sadan sola m ncelikle ele alnaca da
tanmlanmaldr. Buna, ncelik yn (associativity) denir. Ekteki tablonun 4. stunu ilgili
ncelik seviyesine ilikin ncelik ynn belirtiyor. Tablodan da grld gibi her ncelik
seviyesi soldan saa ncelikli deildir. 2, 13 ve 14. ncelik seviyelerinin sadan sola
ncelik ynne sahip olduunu (right associative) gryorsunuz. Dier btn ncelik
seviyeleri soldan saa ncelik seviyesine (left associative) sahiptir.
Bir simge, birden fazla ile olarak kullanlabilir. rnein, ekteki tabloyu incelediinizde
'*' simgesinin hem arpma ileci hem de bir gsterici ileci olan ierik alma ileci olarak
kullanldn greceksiniz. Yine '&' (ampersand) simgesi hem bitsel ve ileci hem de
gstericilere ilikin adres ileci olarak kullanlr.

lelerin Yan Etkileri

C dilinde ilelerin ana ilevleri, bir deer retmeleridir. Ancak baz ileler, terimi olan
nesnelerin deerlerini deitirir. Yani bu nesnelerin bellekteki yerlerine yeni bir deer
yazlmasna neden olurlar. Bir ilecin, terimi olan nesnenin deerini deitirmesine ilecin
yan etkisi (side effect) denir. Yan etki, bellekte yaplan deer deiiklii olarak tanmlanr.
rnein atama ilecinin, ++ ve -- ilelerinin yan etkisi vardr. Bu ileler, terimleri olan
nesnelerin bellekteki deerlerini deitirebilir.

leler zerindeki Kstlamalar

Programlama dilinin kurallarna gre, baz ilelerin kullanmlaryla ilgili birtakm


kstlamalar sz konusu olabilir. rnein ++ ilecinin kullanmnda, ilecin teriminin nesne
gsteren bir ifade olmas gibi bir kstlama sz konusudur. Eer terim olan ifade bir nesne
gstermiyorsa, yani sol taraf deeri deilse, derleme zamannda hata oluur.
Kstlama, ilecin terim ya da terimlerinin trleriyle de ilgili olabilir. rnein kalan (%)
ilecinin terimlerinin bir tamsay trnden olmas gerekir. Kalan ilecinin terimleri gerek
say trlerinden olamaz. Terimin gerek say trlerinden birinden olmas geersizdir.

lelerin Yaptklar lere Gre Snflandrlmas

Aada ileler yaptklar ilere gre snflanyor:

Aritmetik ileler (arithmetic operators)


Bu ileler aritmetik baz ilemlerin yaplmasna neden olur. Toplama, karma, arpma,
artrma, eksiltme ileleri ile iaret ileleri, aritmetik ilelerdir.
Karlatrma ileleri (relational operators)
Bu ilelere ilikisel ileler de denir.
Bu ileler bir karlatrma ilemi yaplmasn salar. Byktr, byk ya da eittir,
kktr, kk ya da eittir, eittir, eit deildir ileleri karlatrma ileleridir.
Mantksal ileler (logical operators)

75/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Bu ileler, mantksal ilemler yapar. Mantksal ve, mantksal veya, mantksal deil
ileleri bu gruba girer.
Gsterici ileleri (pointer operators)
Bu ileler, adresler ile ilgili baz ilemlerin yaplmasn salar. Adres ileci, ierik ileci ile
keli ayra ileci bu gruba girer.
Bitsel ilem yapan ileler (bitwise operators)
Bu ileler, bitsel dzeyde baz ilemlerin yaplmasn salar. Bitsel deil ileci, bitsel
kaydrma ileleri, bitsel ve, veya, zel veya ileleri bu gruba giren ilelerdir.
Atama ileleri (assignment operators)
Bir nesneye atama yaplmasn salayan ilelerdir. Atama ileci ve ilemli atama ileleri
bu gruba girer.
zel amal ileler (special purpose operators)
Bunlar farkl ilerin yaplmasn salayan ve farkl amalara hizmet eden ilelerdir. Koul
ileci, sizeof ileci, tr dntrme ileci bu gruba giren ilelerdir.
lk grup, programlama dillerinin hepsinde vardr. Bitsel ilem yapan ileler ve
gsterici ileleri yksek seviyeli programla dillerinde genellikle bulunmaz. Programlama
dillerinin ou, kendi uygulama alanlarnda kolaylk salayacak birtakm zel amal
ilelere de sahip olabilir.

Aritmetik leler

Aritmetik ileler, basit artimetiksel ilemler yapan ilelerdir.

Toplama (+) ve karma(-) leleri

ki terimli, araek konumundaki (binary infix) ilelerdir. Dier btn programlama


dillerinde olduklar gibi, terimlerinin toplamn ya da farkn almak iin kullanrlar. Yani
rettikleri deer, terimlerinin toplam ya da fark deerleridir.
Bu ilecin terimleri herhangi bir trden nesne gsteren ya da gstermeyen ifadeler
olabilir. Terimlerinin ayn trden olmas gibi bir zorunluluk da yoktur. le ncelik
tablosunun 4. seviyesinde bulunurlar. ncelik ynleri soldan saadr. Her iki ilecin de
yan etkisi yoktur. Yani bu ileler terimlerinin bellekte sahip olduklar deerleri
deitirmez.
Toplama ve karma ileleri olan + ve ilelerini tek terimli + ve ileleriyle
kartrmamak gerekir.

aret leci Olan ve +

Bu ileler, tek terimli, nek konumundaki (unary prefix) ilelerdir. aret ileci eksi (-),
teriminin deerinin ters iaretlisini retir. Yani derleyici, iaret eksi ilecinin kullanlmas
durumunda terim olan deeri -1 ile arpacak ekilde kod retir. Bu ilecin terimi herhangi
bir trden nesne gsteren ya da gstermeyen ifade olabilir. le ncelik tablosunun ikinci
seviyesinde bulunurlar. ncelik yn sadan soladr. lecin bir yan etkisi yoktur, yani
terimi olan nesnenin bellekteki deerini deitirmez.
"aret eksi" ilecinin rettii, bir nesne deildir, bir sa taraf deeridir. Aadaki ifade
matematiksel olarak doru olmasna karn C dilinde doru deildir, derleme zamannda
hata oluumuna neden olur:
int x;
-x = 5;

76/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

x bir nesne olmasna kar x ifadesi bir nesne deil, x nesnesinin deerinin ters iaretlisi
olan deerdir.
-x ve 0 - (x) edeer ifadelerdir.
-x ifadesi bir sol taraf deeri deildir, bu ifadeye bir atama yaplamaz.
aret ileci art (+), yalnzca matematiksel benzerlii salamak asndan C diline
eklenmi bir iletir. Derleyici tarafndan, tek terimli, nek konumunda bir ile olarak ele
alnr. Terimi olan ifade zerinde herhangi bir etkisi olmaz. Teriminin deeriyle ayn
deeri retir. +x ifadesi ile 0 + (x) ifadeleri edeerdir.
#include <stdio.h>
int main()
{
int x = -5;
x = -x - x;
printf("x = %d\n", x);
return 0;
}
x = -x x;
Yukardaki ifadede 3 ile vardr. Soldan saa bu ileleri sayalm: Atama ileci '=',
iaret ileci eksi '-', karma ileci '-'. fadenin deerinin hesaplanmasnda ile
nceliklerine gre hareket edilir. nce ikinci seviyede bulunan eksi iaret ileci deer '5'
deerini retir. retilen 5 deeri karma ilecinin terimi olur. Yaplan kartma
ileminden retilen deer 10'dur. Bu deer de atama ilecinin terimi olur, bylece x
deikenine 10 deeri atanr.

arpma (*) ve Blme (/) leleri

ki terimli, araek konumundaki ilelerdir. arpma ilecinin rettii deer, terimlerinin


arpmdr. Blme ilecinin rettii deer ise sol teriminin sa terimine blmnden elde
edilen deerdir. Bu ilelerin terimleri herhangi bir trden olabilir. Terimlerinin ayn
trden olmas gibi bir zorunluluk yoktur. le ncelik tablosunun 3. seviyesinde
bulunurlar. ncelik ynleri soldan saadr. Her iki ilecin de yan etkisi yoktur.
Blme ilecinin kullanmnda dikkatli olmak gerekir. lecin her iki terimi de tamsay
trlerinden ise ilecin rettii deer de bir tamsay olur. Yani bir tamsayy baka bir
tamsayya blmekle bir gerek say elde edilmez.
C programlama dilinde * simgesi ayn zamanda bir gsterici ileci olarak da kullanlr.
Ama ayn simge kullanlmasna karn bu iki ile hibir zaman birbirine karmaz nk
aritmetik arpma ileci iki terimli iken gsterici ileci tek terimlidir.

Kalan (%)leci

ki terimli, araek konumunda bir iletir. Terimlerinin her ikisi de tamsay trlerinden
(char, short, int, long) olmak zorundadr. Herhangi bir teriminin gerek say trnden
olmas geersizdir. lecin rettii deer, sol teriminin sa terimine blmnden kalandr.
lecin yan etkisi yoktur. rnein:
k = 15 % 4;
/* burada k ya 3 deeri atanr*/
x = 2 % 7;
/* burada x e 2 deeri atanr*/
int c = 13 - 3 * 4 + 8 / 3 - 5 % 2;
Burada c deikenine 2 deeri atanr. nk ilem u ekilde yaplr:

77/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

c = 13 - (3 * 4) + (8 / 3) - (5 % 2)
c = 13 - 12 + 2 - 1;
c = 2;
Aadaki programda 3 basamakl bir saynn birler, onlar ve yzler basamaklar ekrana
yazdrlyor:
#include <stdio.h>
int main()
{
int x;
printf("3 basamakli bir sayi girin: ");
scanf("%d", &x);
printf("birler basamagi = %d\n", x % 10);
printf("onlar basamagi = %d\n", x % 100 / 10);
printf("yuzler basamagi = %d\n", x / 100);
}

return 0;

Artrma (++) ve Eksiltme (--) leleri

Artrma (++) ve eksiltme (--) ileleri C dilinin en ok kullanlan ilelerindendir. Tek


terimli ilelerdir. nek ya da sonek durumunda bulunabilirler. ++ ileci terimi olan
deikenin deerini 1 artrmak, -- ileci de terimi olan deikenin deerini 1 eksiltmek
iin kullanlr. Dolaysyla yan etkileri sz konusudur. Terimleri olan nesnenin bellekteki
deerini deitirirler. Bu iki ile de 2. ncelik seviyesinde bulunduundan dier aritmetik
ilelerden daha yksek ncelie sahiptir. 2. ncelik seviyesine ilikin ncelik yn
sadan soladr.
Yaln olarak kullanldklarnda, yani bulunduklar ifade iinde kendilerinden baka hibir
ile olmakszn kullanldklarnda nek ya da sonek durumlar arasnda hibir fark
yoktur. ++ ileci terimi olan nesnenin deerini 1 artrr, -- ileci terimi olan nesnenin
deerini 1 eksiltir. Bu durumda
++c;

ve

c++ ;

deyimleri tamamen birbirine denk olup


c = c + 1;
anlamna gelirler.
--c; ve c--;
deyimleri tamamen birbirine denk olup
c = c - 1;
anlamna gelir.
Bir ifade iinde dier ilelerle birlikte kullanldklarnda, nek ve sonek biimleri arasnda
farkllk vardr: nek durumunda kullanldnda, ilecin rettii deer, artrma ya da
eksiltme yapldktan sonraki deerdir. Yani terimin artrlm ya da azaltlm deeridir.
Sonek durumunda ise ilecin rettii deer, artrma ya da eksiltme yaplmadan nceki
deerdir. Yani terimi olan nesnenin artrlmam ya da azaltlmam deeridir. Nesnenin
deeri ifadenin tm deerlendirildikten sonra artrlr ya da eksiltilir.

78/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

x = 10;
y = ++x;
Bu durumda:
++x 11
ve y = 11 deeri atanr.
x = 10;
y = x++;
Bu durumda
x++ => 10
ve y deikenine 10 deeri atanr.
Aadaki program inceleyin:
#include <stdio.h>
int main()
{
int a = 10;
int b = ++a;
printf("a = %d b = %d\n", a, b);
a = 10;
b = a++;
printf("a = %d b = %d\n", a, b);
return 0;
}
Yukardaki birinci printf ars ifadesi ekrana
11 11
deerlerini yazdrrken ikinci printf ars ekrana
11 10
deerlerini yazdrr. Aadaki rnei inceleyin:
#include <stdio.h>
int main()
{
int x = 10;
int y = 5;
int z = x++ % 4 * --y;
printf("z = %d\n", z);
printf("x = %d\n", x);
printf("y = %d\n", y);
}

return 0;

Yukarda kodu verilen main ilevinde ilem sras u ekilde olur:

79/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

z
z
z
z
y
x

= x++ % 4 * 4;
= 10 % 4 * 4;
= 2 * 4;
= 8;
=> 4
=> 11

Aadaki rnei derleyerek altrn:


#include <stdio.h>
int func(int x)
{
return ++x;
}
int
{

main()
int a = 10;
int b = func(a++);
printf("a = %d\n", a);
printf("b = %d\n", b);
return 0;

80/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

C Standartlarnda Kullanlan Baz nemli Terimlere likin


Aklama

C ve C++ standartlarnda sklkla kullanlan ve derleyicinin kodu yorumlama biimi


hakknda bilgi veren nemli terimler vardr:

Davran

Derleyicinin belirli bir kod parasn yorumlama ve anlamlandrma biimine "derleyicinin


davran" (behavior) denir.

Tanmsz Davran

C'de ve C++'da baz ifadeler, derleyiciden derleyiciye deiebilen fakat standartlarda


ak olarak belirtilmemi olan yorumlama farllklarna yol aabilir. Byle ifadelerden
kanmak gerekir. Bu tr ifadelerde derleyicinin davranna "tanmsz davran"
(undefined behavior) denir. Programcnn byle ifadeler yazmas programlama hatas
olarak kabul edilir. nk eer bir ifade tanmsz davran olarak belirleniyorsa bir
sistemde programn altrlmas sonucunda nasl bir durumla karlalacann hibir
gvencesi yoktur. Tanmsz davrana yol aan kodlar szdizimi asndan geerlidir.
rnein bir ifadede bir deiken ++ ya da - ilecinin terimi olarak kullanlmsa ayn
ifadede o deiken artk bir kez daha yer almamaldr. Yer alrsa artk tanmsz
davrantr.

Belirlenmemi Davran

Kaynak kodun derleyici tarafndan farkl yorumlanabildii fakat bu konuda seeneklerin


snrl olduu durumlara belirlenmemi davran (unspecified behavior) denir. Derleyiciler
belirsiz davranlarda hangi seenein seilmi olduunu belgelemek zorunda deildir.
phesiz programcnn belirsiz davrana yol aacak ifadelerden kanmas gerekir.

Derleyiciye zg Davran

C dilinin baz zellikleri, esneklik salamak amac ile standartlarda derleyici yazanlarn
seimlerine braklmtr. rnein int trnn uzunluunun ne olduu, varsaylan char
trnn signed m unsigned m olduu, i ie yorumlamalarn kabul edilip edilmedii
tamamen derleyici yazanlara baldr. Derleyiciler, bu zelliklerin nasl seildiklerini
belgelemek zorundadr. Bu tr davrana derleyiciye zg davran (implementation
dependent behaviour) denir. Bu davran zellikleri pekok derleyicide menlerden
deitirilebilmektedir.

Bulgu letileri

C standartlar temel olarak derleyiciyi yazanlar iin bir klavuz biimindedir. Derleyici
sorunlu bir kodla karlatnda uygun dntrme ilemlerini yapamyorsa sorunun
nedenine ilikin bir bildirimde bulunmak zorundadr. Standartlarda derleyicilerin sorunu
programcya bildirme durumuna "bulgu iletisi" (diagnostic message) denmektedir.
Standartlar iinde belirtilmi olan szdizimsel ve anlamsal kurallarn inendii
durumlarda bir uyar iletisi verilmelidir. Bu iletinin uyar (warning) ya da hata (error)
biiminde olmas, derleyicinin isteine braklmtr.
Ancak derleyicilerin hemen hepsinde uyarlar, derleyiciler tarafndan giderilebilecek kk
yanllar iin, hata ise daha byk yanllar iin verilir.
rnein bir gstericiye farkl trden bir adresin dorudan atanmas C'nin kurallarna
aykrdr. Bu durumda derleyici standartlara gre bir ileti vermelidir. Aslnda standartlara
gre, uyar ya da hata iletisi verilebilir, ama C derleyicilerinin hemen hepsi uyar iletisi
verir.
Standartlarda baz kurallarn inenmesi durumunda derleyicinin aka bir ileti
vermeyebilecei belirtilmitir (nodiagnostic required). Aslnda C standartlarnda belirtildii
gibi kural inenmeleri durumunda derleyicinin ilemi baar ile bitirip bitirmeyecei
aka belirtilmemitir. Yani standartlara gre derleyici, doru bir program
derlemeyebilir, yanl bir program derleyebilir.

81/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Ancak C++ standartlarnda durum byle deildir. Dilin kuralna uymayan kodlarda
derleyici bir ileti vermeli, derleme ilemini baarszlk ile sonulanmaldr.
Derleyiciler, standartlarda belirtilen zelliklerin dnda da baz zelliklere sahip olabilir.
Bu tr zelliklere derleyicilerin eklentileri denir. Derleyicilerin eklentilerini kullanmak
tanabilirlii azaltr.

++ ve -- leleriyle lgili Tanmsz Davranlar

++ ve -- ilelerinin baz kullanmlar, tanmsz davran zellii gsterir. Byle kodlardan


saknmak gerekir.
1. Bir ifadede bir nesne ++ ya da -- ilelerinin terimi olmusa, o nesne o ifadede bir kez
daha yer almamaldr. rnein aadaki ifadelerin hepsi tanmsz davran zellii
gsterirler:

int x = 20, y;
int a = 5;
y = ++x + ++x;
y = ++x + x
a = ++a;

/* tanmsz davran */
/* tanmsz davran */
/* tanmsz davran */

"Koul ileci", "mantksal ve ileci", "mantksal veya ileci" ve "virgl" ileciyle oluturulan
ifadelerde bir sorun yoktur. Bu ilelerle ilgili nemli bir kurala ileride deineceiz.
2. Bir ilev arlrken ileve gnderilen argmanlarn birinde bir nesne ++ ya da -ilecinin terimi olmusa, bu nesne, ileve gnderilen dier argman olan ifadelerde
kullanlmamaldr.
Argman olan ifadelerin, ilevlerin ilgili parametre deikenlerine kopyalanmasna ilikin
sra, standart bir biimde belirlenmemitir. Bu kopyalama ilemi, baz sistemlerde soldan
saa baz sistemlerde ise sadan soladr. Aadaki rnei inceleyin:
int a = 10;
void func(int x, int y)
{
/***/
}
int main()
{
func (a, a++);
}

/* Tanmsz davran */

/***/

Karlatrma leleri (ilikisel ileler)

C programlama dilinde toplam 6 tane karlatrma ileci vardr:


<
>
<=
>=

kktr ileci (less than)


byktr ileci (greater than)
kktr ya da eittir ileci (less than or equal)
byktr ya da eittir ileci (greater than or equal)

==
!=

eittir ileci (equal)


eit deildir ileci (not equal)

Bu ilelerin hepsi, iki terimli, araek konumundaki (binary infix) ilelerdir.

82/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

lk drt ile, ile ncelik tablosunun 6. seviyesinde bulunurken dier iki karlatrma
ileci ncelik tablosunun 7. seviyesinde bulunur. Yani karlatrma ileleri, kendi
aralarnda iki ncelik grubu oluturur. Karlatrma ileleri, aritmetik ilelerden daha
dk ncelikli seviyededir.
Dier programlama dillerinin ounda bool ya da boolean (Matematiki George Bool'un
isminden) ismi verilen bir mantksal veri tr de doal bir veri tr olarak programcnn
kullanmna sunulmutur. Byle dillerde bool veri tr, yalnzca mantksal doru ya da
mantksal yanl deerlerini alabilen bir trdr. Bu dillerde karlatrma ilelerinin
rettii deerler ise bu trdendir. rnein C++ ya da Java dillerinde durum byledir.
C dilinde karlatrma ileleri, oluturduklar nermenin doruluu ve yanllna gre
int trden 1 ya da 0 deerini retir. nerme doru ise 1 deeri retilirken, nerme
yanl ise 0 deeri retilir. Bu ilelerin rettii deerler de tpk aritmetik ilelerin
rettii deerler gibi kullanlabilir.
Aadaki signum isimli ilevin tanmn inceleyin:
int signum(int val)
{
return (val > 0) - (val < 0);
}
signum ilevine gnderilen argman 0'dan byk bir deerse ilev +1 deerine,
argman 0'dan kk bir deerse ilev -1 deerine, argman 0 deeriyse ilev, 0
deerine geri dnyor. signum ilevinin geri dn deeri, karlatrma ilelerinin deer
retmesinden faydalanlarak elde ediliyor.
Baz programlama dillerinde
(val > 0) - (val < 0);
gibi bir ilem hata ile sonulanr. nk rnein Pascal dilinde
val > 0
ifadesinden elde edilen deer doru (True) ya da yanl (False) dir. Yani retilen deer
bool ya da boolean trndendir. Ama C doal bir dil olduu iin karlatrma ilelerinin
rettikleri deer bool tr ile kstlanmamtr. C'de mantksal veri tr yerine int tr
kullanlr. Mantksal bir veri trnn tamsay tryle ayn olmas C'ye esneklik ve doallk
kazandrmtr. C dilinde yazlan birok kalp kod, karlatrma ilelerinin int trden 1 ya
da 0 deeri retmesine dayanr. rnein
x = y == z;
Yukardaki deyim, C dili iin son derece doaldr ve okunabilirlii yksektir. Bu deyimin
yrtlmesiyle x deikenine ya 1 ya da 0 deeri atanr. Karlatrma ileci, atama
ilecinden daha yksek ncelik seviyesine sahip olduuna gre nce karlatrma ileci
olan '==' deer retir, ilecin rettii deer bu kez atama ilecinin terimi olur. Bu
durumda y deikeninin deerinin z deikenine eit olup olmamasna gre x deikenine
1 ya da 0 deeri atanr.
Karlatrma ilecinin kullanlmasnda baz durumlara dikkat edilmelidir:
int x = 12;
5 < x <

83/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yukardaki ifade matematiksel adan doru deildir. nk 12 deeri 5 ve 9 deerlerinin


arasnda deildir. Ancak ifade C kodu olarak ele alndnda doru olarak deerlendirilir.
nk 6. seviyede olan kktr (<) ilecine ilikin ncelik yn soldan saadr. nce
soldaki '<' ileci deer retecek ve rettii deer olan 1 sadaki '<' ilecinin terimi
olur. Bu durumda
1 < 9
ifadesi mantksal olarak doru olduu iin 1 deeri elde edilir.

Mantksal leler

Bu ileler, terimleri zerinde mantksal ilem yapar. Terimlerini doru (true) ya da yanl
(false) olarak yorumladktan sonra ileme sokar. C'de ncelikleri farkl seviyede olan
mantksal ile vardr:
(!) mantksal deil ileci (logical not)
(&&) mantksal ve ileci (logical and)
(||) mantksal veya ileci (logical or)
Ancak "mantksal ve", "mantksal veya" ileleri, bilinen anlamda ile ncelik kurallarna
uymaz. Bu konuya biraz ileride deineceiz.
C'de mantksal veri tr olmadn biliyorsunuz. Mantksal veri tr olmad iin bu
trn yerine int tr kullanlr ve mantksal doru olarak 1, mantksal yanl olarak da 0
deeri kullanlr.
C dilinde herhangi bir ifade, mantksal ilelerin terimi olabilir. Bu durumda sz konusu
ifade, mantksal olarak yorumlanr. Bunun iin ifadenin saysal deeri hesaplanr.
Hesaplanan saysal deer, 0 d bir deer ise doru (1), 0 ise yanl (0) olarak
yorumlanr. rnein:
25 Doru (nk 0 d bir deer)
-12 Doru (nk 0 d bir deer)
0 Yanl (nk 0)
ifadesi mantksal bir ilecin terimi olduu zaman yanl olarak yorumlanr. nk saysal
deeri sfra eittir.

Mantksal Deil leci

Mantksal deil ileci, nek konumunda bulunan tek terimli bir iletir. Bu ile, teriminin
mantksal deerinin tersini retir. Yani terimi mantksal olarak "doru" biiminde
yorumlanan bir deer ise ile yanl anlamnda int trden 0 deerini retir. Terimi,
mantksal olarak "yanl" biiminde yorumlanan bir deer ise ile doru anlamnda int
trden 1 deerini retir.
x
Doru (0 d deer)
Yanl (0)

!x
Yanl (0)
Doru (1)

rnekler :
a = !25; /* a deikenine 0 deeri atanr
b = 10 * 3 < 7 + !2
lem sras:

84/529

*/

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

!2 = 0
10 * 3 = 30
7 + 0 = 7
30 < 7 = 0
b = 0 (atama ileci en dk ncelikli iletir)
y = 5;
x = !++y < 5 != 8;
lem sras:
++y 6
!6 0
/* ++ ve ! ileleri ayn ncelik seviyesindedir ve ncelik
yn sadan soladr. */
0 < 5 1
1 != 8 1
x = 1

Mantksal ve (&&) ileci

Bu ile ilikisel ilelerin hepsinden dk, || (veya / or) ilecinden yksek nceliklidir.
Terimlerinin ikisi de doru ise doru (1), terimlerinden biri yanl ise yanl (0) deerini
retir.

x
3
7
1
x

= 3 < 5 && 7;
< 5 1
1
&& 1 1
= 1

&& ilecinin, nce sol tarafndaki ilemler ncelik srasna gre tam olarak yaplr. Eer
bu ilemlerde elde edilen saysal deer 0 ise, && ilecinin sa tarafndaki ilemler hi
yaplmadan, yanl (0) saysal deeri retilir. rnein:
x = 20;
b = !x == 4 && sqrt(24);
!20 0
0 == 4 0
Sol taraf 0 deeri alacandan ilecin sa taraf hi yrtlmez dolaysyla da sqrt ilevi
arlmaz. Sonu olarak b deikenine 0 deeri atanr.
Uygulamalarda mantksal ileler ounlukla karlatrma ileleriyle birlikte kullanlr:
scanf("%d", &x);
y = x >= 5 && x <= 25;
Bu durumda y deikenine, ya 1 ya da 0 deeri atanr. Eer x deikeninin deeri 5'den
byk ya da eit ve 25'den kk ya da eit ise y deikenine 1 deeri, bunun dndaki
durumlarda y deikenine 0 deeri atanr.

85/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

ch = 'c'
z = ch >= 'a' && ch <= 'z'
Yukardaki rnekte, ch deikeninin kk harf olup olmamas durumuna gre z
deikenine 1 ya da 0 atanr.

Mantksal veya (||) leci

ncelii en dk olan mantksal iletir. ki teriminden biri doru ise doru deerini
retir. ki terimi de yanl ise yanl deerini retir.

a = 3 || 5
x = 0 || -12
sayi = 0 || !5

/* a = 1 */
/* x = 1 */
/* sayi = 0 */

&& ve || lelerinin Ksa Devre Davran

"Mantksal ve", "mantksal veya" ilelerinde nce soldaki terimlerinin deerlendirilmesi


gvence altna alnmtr. "Mantksal ve" ilecinin soldaki terimi yanl olarak yorumlanrsa
ilecin sa terimi hi ele alnmaz. Ayn durum "mantksal veya" ileci iin de geerlidir.
"Mantksal veya" ilecinin nce soldaki terimine baklr. Sol terimi doru olarak
yorumlanrsa ilecin sa terimi hi dikkate alnmaz. C dili tarafndan gvence altna alnan
bu zellie "ksa devre davran" (short circuit behavior) denir. Ksa devre davranna
neden gerek duyulmutur? nk bu zellik baz kodlarn ok daha verimli yazlmasn
salar. C'nin ileride greceimiz birok kalp kodu ksa devre davrannn kullanmna
baldr.
Aadaki ifadeyi inceleyin:
result =

ch == 'A' || ch == 'E'

Yukardaki ifade ile, result isimli deikene, ch deikeninin deerinin 'A' ya da 'B' ye eit
olmas durumunda 1 deeri, aksi halde 0 deeri atanr. ch eer 'A' ya eit ise ikinci
karlatrma yaplmaz.
Mantksal ileler bir deer retebilmek iin terimlerini nce 1 ya da 0, yani doru ya da
yanl olarak yorumlar, ama yan etkileri yoktur. Yani terimlerinin nesne olmas
durumunda bu nesnelerin bellekteki deerlerini 1 ya da 0 olarak deitirmezler.

Atama leleri

Atama ileleri, C dilinde ncelik tablosunun en alttan ikinci seviyesinde, yani 14.
seviyesinde bulunur ve yalnzca virgl ilecinden daha yksek nceliklidir. Atama
ilelerinin bulunduu 14. seviye, sadan sola ncelik ynne sahiptir.

Yaln Atama leci

Dier ileler gibi atama ileci de, yapt atama ileminin yansra, bir deer retir.

86/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Atama ilecinin rettii deer, nesneye atanan deerin kendisidir. Aadaki program
derleyerek altrn:
#include <stdio.h>
int main()
{
int x;
printf("ifade degeri = %d\n", x = 5);
printf("x = %d\n", x);
}

return 0;

main ilevi iinde yaplan birinci printf ars ile, x = 5 ifadesinin deeri yazdrlyor.
x = 5 ifadesinin deeri atama ilecinin rettii deer olan 5 deeridir. Yani ilk printf
ars ile ekrana 5 deeri yazdrlr. Atama ileci yan etkisi sonucu x nesnesinin deerini
5 yapar. Bu durumda ikinci printf ars ile x deikeninin deeri ekrana yazdrldndan
ekrana yazlan, 5 deeri olur.
Atama ilecinin rettii deer nesne deildir. Aadaki deyim geersizdir:
(b = c) = a;

/* Geersiz! */

b = c atamasndan elde edilen deer, c nesnesinin kendisi deil, c nesnesinin saysal


deeridir.
C'nin birok kalp kodunda, atama ilecinin rettii deerden faydalanlr. Aadaki main
ilevini inceleyin:
#include <stdio.h>
int main()
{
int a, b, c, d;
a = b = c
printf("a
printf("b
printf("c
printf("d
printf("e
}

=
=
=
=
=
=

d = 5;
%d\n",
%d\n",
%d\n",
%d\n",
%d\n",

a);
b);
c);
d);
e);

return 0;

le ncelik tablosundan da grlecei gibi, atama ileleri sadan sola ncelik ynne
sahiptir. Bu yzden:
a = b = c = d = 5;
deyimi C'de geerlidir.
Bu deyimde nce d deikenine 5 deeri atanr. Atama ilecinin rettii 5 deeri, bu kez
c deikenine atanr. Sadan sola doru ele alnan her atama ileci, nesneye atanan
deeri rettiine gre, tm deikenlere 5 deeri aktarlm olur. Atama ilecinin rettii
deerden faydalanmak, zellikle kontrol deyimlerinde karnza ok kacak.

lemli Atama leleri

87/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Bir ilemin terimi ile, ilem sonucunda retilen deerin atanaca nesne ayn ise, ilemli
atama ileleri kullanlabilir.
<nesne1> = <nesne1> ilem <terim2>
ile
<nesne1>

ilem= <terim2>

ayn anlamdadr.
lemli atama ileleri, atama ileciyle ayn ncelik seviyesindedir.
lemli atama ileleri, hem okunabilirlik hem de daha ksa yazm iin tercih edilir.
Aadaki ifadeler edeerdir:
deger1 += 5;
sonuc *= yuzde;
x %= 5

deger1 = deger1 + 5;
sonuc = sonuc * yuzde;
x = x % 5;

katsayi = katsayi * (a * b + c * d);


ifadesi de yine
katsayi *= a * b + c * d;
eklinde yazlabilir. imdi de aadaki main ilevini inceleyin:
#include <stdio.h>
int main()
{
int x = 3;
int y = 5;
x += y *= 3;
printf("x = %d\n", x);
printf("y = %d\n", y);
return 0;
}
x += y *= 3;
deyimiyle nce y deikenine 15 deeri atanr. Bu durumda *= ileci 15 deerini retir ve
retilen 15 deeri bu kez += ilecinin terimi olur. Bylece x deikenine 18 deeri
atanr.
zellikle += ve -= ilelerinin yanl yazlmas, bulunmas zor hatalara neden olabilir.
x += 5;
deyimi x deikeninin deerini 5 artrrken, ilecin yanllkla aadaki gibi yazlmas
durumunda
x =+ 5;
x deikenine 5 deeri atanr. nk burada iki ayr ile sz konusudur: Atama ileci
olan = ve iaret ileci olan +.

88/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yukardaki rneklerden de grld gibi, atama grubu ilelerin yan etkileri vardr. Yan
etkileri, ilecin sol teriminin bellekteki deerinin deitirilmesi, yani ilecin sa tarafndaki
terimi olan ifadenin deerinin sol tarafndaki nesneye aktarlmas eklinde kendini
gsterir.

Virgl leci
ki ayr ifadeyi tek bir ifade olarak birletiren virgl ileci, C'nin en dk ncelikli
ilecidir.
ifade1;
ifade2;
ile
ifade1, ifade2;
ayn ileve sahiptir.
Virgl ilecinin, nce sol terimi olan ifadenin sonra sa terimi olan ifadenin ele alnmas
gvence altndadr. Bu ilecin rettii deer, sa tarafndaki ifadenin rettii deerdir.
Virgl ilecinin sol teriminin, retilen deere bir etkisi olmaz.
x = (y++, z = 100);
gibi bir deyimle x ve z deikenlerine 100 deeri atanr.
Aadaki rnekte if ayrac iindeki ifadenin rettii deer 0'dr.
if (x > 5,0) {
/***/
}
Virgl ileleri ile bir bileik deyim basit deyim durumuna getirilebilir:
if (x ==
a1 =
a2 =
a3 =
}

20) {
20;
30;
40;

yerine
if (x == 20)
a1 = 20, a2 = 30, a3 = 40;
yazlabilir.
Virgl ilecinin sa terimi nesne gsteren bir ifade olsa bile ilecin oluturduu ifade bir
nesne deildir:
int x, y;
/***/
(x, y) = 10;
Yukardaki atama ilemi geersizdir.
[C++ dilinde virgl ilecinin oluturduu bir ifade sol taraf deeri olabilir. Yukardaki atama C++ dilinde
geerlidir.]

89/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

ncelik leci
ncelik ileci ( ), bir ifadenin nceliini ykseltmek amacyla kullanlr.
x = (y + z) * t;
ncelik ileci, C'nin en yksek ncelikli ileler grubundadr. ncelik ileci de, kendi
arasnda soldan saa ncelik kuralna uyar. rnein:
a = (x + 2) / ((y + 3) * (z + 2) 1);
ifadesinde ilem sras yledir :
i1
i2
i3
i4
i5
i6
i7

:
:
:
:
:
:
:

x + 2
y + 3
z + 2
i2 * i3
i4 1
i1 / i5
a = i6

ncelik ilecinin terimi nesne gsteren bir ifade ise, ilecin rettii ifade de nesne
gsterir:
int x;
(x) = 20;

/* Geerli

*/

le ncelii ve Bir lemin lemci Tarafndan nce Yaplmas

le ncelii, bir ilemin ilemci tarafndan daha nce yaplmas anlamna gelmez.
Aadaki ifadeyi dnelim:
x = func1() * func2() + func3();

arpma ilecinin toplama ilecinden daha yksek ncelikli olduunu biliyorsunuz. Ancak
bu ncelik, rnein yukardaki deyimde func1 ilevinin func3 ilevinden daha nce
arlaca gvencesi anlamna gelmez. ncelik ilecinin de kullanm byle bir gvence
salamaz.
x = func1() * (func2() + func3());
Bu kez de rnein func2 ilevinin func1 ilevinden daha nce arlmasnn gvencesi
yoktur.Bu kez de aadaki main ilevini inceleyin:
#include <stdio.h>
int main()
{
int x = 10;
int y = x + (x = 30);
printf("y = %d\n", y);
return 0;
}
main ilevi iinde yazlan
y = x + (x = 30);

90/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

deyimi pheli kod oluturur. y deikenine atanan deerin ne olaca konusunda bir
gvence yoktur. x = 30 ifadesinin ncelik ayrac iine alnmas, toplama teriminin sol
terimi olan x ifadesinin deerinin 30 olarak ele alnacan, gvence altna almaz.
Sonuta, y deikenine 60 deeri aktarlabilecei gibi, 40 deeri de atanabilir.
Ancak C dilinin 4 ileci terimlerine ilikin, daha nce ilem yapma gvencesini verir. Bu
ileler:
mantksal ve, mantksal veya, koul ve virgl ileleridir.
Mantksal ve/veya ilelerinin ksa devre davranlarn renmitiniz. Ksa devre
davrannn gerekletirilebilmesi iin bu ilelerin sol terimlerinin daha nce yaplmas
gvence altna alnmtr.
leride greceiniz koul ilecinin de bir deer retebilmesi iin, nce ilk teriminin
deerlendirilmesi gerekir. Virgl ilecinin ise zaten varlk nedeni nce sol, daha sonra sa
teriminin yaplmasn salamaktr.

91/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

C Dilinin le ncelik Tablosu


Seviye

le

()
[]
.
->

+
++
-~
!
*
&
sizeof
(tr)

*
/
%
+
<<

4
5

>>
6

<
>
<=
>=

==
!=
&
^
|
&&
||
?:
=
+=

8
9
10
11
12
13
14

-=
*=
/=
%=
<<=
>>=
&=
|=
^=
15

Tanm
ncelik kazandrma ve ilev ar
(precedence and function call)
keli ayra ileci (subscript)
yap elemanna yap nesnesi ile ulam
(structure access with object)
yap elemanna yap gstericisi ile ulam
(structure access with pointer)
iaret ileci (unary sign)
iaret ileci (unary sign)
artrma ileci (increment)
eksiltme ileci (decrement)
bitsel deil ileci (bitwise not)
mantksal deil ileci(logical not)
ierik ileci (indirection)
adres ileci (address of)
sizeof ileci (sizeof)
tr dntrme ileci
(type cast operator)
arpma ileci (multiplication)
blme ileci(division)
kalan ileci (modulus)
toplama ileci (addition)
karma ileci (subtraction)
bitsel sola kaydrma ileci(bitwise shift left)

bitsel saa kaydrma ileci


(bitwise shift right)
kktr ileci (less than)
byktr ileci (greater than)
kk eittir ileci (less than or equal)
byk eittir ileci
(greater than or equal)
eittir ileci (equal)
eit deildir ileci (not equal to)
bitsel ve ileci (bitwise and)
bitsel zel veya ileci (bitwise exor)
bitsel veya ileci (bitwise or)
mantksal ve ileci (logical and)
mantksal veya ileci (logical or)
koul ileci (conditional)
atama ileci (assignement)
toplamal atama ileci
(assignment with addition)
karmal atama ileci
(assignment with subtraction)
arpmal atama ileci
(assignment with multiplication)
blmeli atama ileci
(assignment with division)
kalanl atama ileci
(assignment with modulus)
bitsel sola kaydrmal atama ileci
(assignment with bitwise left shift)
bitsel saa kaydrmal atama ileci
(assignment with bitwise right shift)
bitsel ve ilemli atama ileci
(assignment with bitwise and)
bitsel veya ilemli atama ileci
(assignment with bitwise or)
bitsel zel veya ilemli atama ileci
(assignment with bitwise exor)
virgl ileci (comma)

92/529

ncelik Yn
(associativity)
soldan saa

sadan sola

soldan saa

soldan saa
soldan saa

soldan saa

soldan saa
soldan saa
soldan saa
soldan saa
soldan saa
soldan saa
sadan sola
sadan sola

soldan saa

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

BLNRLK ALANI VE MR
Daha nceki konularda nesnelerin isimlerinden, deerlerinden ve trlerinden sz
edilmiti. Nesnelerin C dili asndan ok nem tayan zellii daha sz konusudur.
Bunlar bilinirlik alan (scope), mr (storage duration) ve balant (linkage) zelliidir.

Bilinirlik Alan

Bilinirlik alan (scope), bir ismin tannabildii program araldr. Derleyiciye bildirilen
isimler, derleyici tarafndan her yerde bilinmez. Her isim derleyici tarafndan ancak "o
ismin bilinirlik alan" iinde tannabilir. Bilinirlik alan dorudan kaynak kod ile ilgili bir
kavramdr, dolaysyla derleme zamanna ilikindir. C dilinde derleyici, bildirimleri yaplan
deikenlere kaynak kodun ancak belirli blmlerinde ulalabilir. Yani bir deikenin
tanmlanmas, o deikene kaynak dosyann her yerinden ulalabilmesi anlamna gelmez.
Bilinirlik alanlar C standartlar tarafndan 4 ayr grupta toplanmtr:
i. Dosya Bilinirlik Alan (File scope) : Bir ismin bildirildikten sonra tm kaynak dosya
iinde, yani tanmlanan tm ilevlerin hepsinin iinde bilinmesidir.
ii. Blok Bilinirlik Alan (Block scope): Bir ismin bildirildikten sonra yalnzca bir blok iinde,
bilinmesidir.
iii. lev Bilinirlik Alan (Function Scope): Bir ismin, bildirildikten sonra yalnzca bir blok
iinde bilinmesidir. Yalnzca goto etiketlerini kapsayan zel bir tanmdr. Bu bilinirlik
alanna "goto deyimi" konusunda deinilecek.
iv. lev Bildirimi Bilinirlik Alan (Function Prototype Scope): lev bildirimlerindeki, ilev
parametre ayrac iinde kullanlan isimlerin tannabilirliini kapsayan bir tanmdr. Bu
bilinirlik alanna "lev Bildirimleri" konusunda deinilecek.
Bir kaynak dosya iinde tanmlanan deikenler, bilinirlik alanlarna gre "yerel" ve
"global" olmak zere ikiye ayrlabilir:

Yerel Deikenler

Bloklarn iinde ya da ilevlerin parametre ayralar iinde tanmlanan deikenlere, yerel


deikenler (local variables) denir. C dilinde bloklarn iinde tanmlanan deikenlerin
tanmlama ilemlerinin, bloun en banda yaplmas gerektiini biliyorsunuz. Yerel
deikenler, blok iinde tanmlanan deikenlerdir, bir ilevin ana blou iinde ya da isel
bir blok iinde bildirilmi olabilirler.
Yerel deikenlerin bilinirlik alan, blok bilinirlik alandr. Yani yerel deikenlere yalnzca
tanmlandklar blok iinde ulalabilir. Tanmlandklar bloun daha dndaki bir blok
iinde bu deikenlere eriilemez.
Aadaki programda tanmlanan deikenlerin hepsi yereldir. nk x, y, z isimli
deikenler bloklarn iinde tanmlanyor. Bu deikenler yalnzca tanmlanm olduklar
blok iinde kullanlabilir. Tanmlandklar blok dnda bunlarn kullanlmas geersizdir.
Yorum satrlar iine alnan deyimler geersizdir. z ve y deikenleri bilinirlik alanlarnn
dnda kullanlmtr. Yukardaki rnekte deikenlerin hepsi yerel olduu iin blok
bilinirlik alan kuralna uyar, ancak bu durum, 3 deikenin de bilinirlik alannn tamamen
ayn olduu anlamna gelmez. rnek programda x deikeni en geni bilinirlik alanna
sahipken y deikeni daha kk ve z deikeni de en kk bilinirlik alanna sahiptir:

93/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
int main()
{
int x = 10;
printf("x = %d\n", x);
{
int y = 20;
printf("y = %d\n", y);
x = 30;
{
int z = 50;
y = 60;
printf("z = %d\n", z);
printf("x = %d\n", x);
printf("y = %d\n", y);
}
z = 100; /* Geersiz! */
y = x;
printf("x = %d\n", x);
printf("y = %d\n", y);

}
y = 500; /* Geersiz! */
printf("x = %d\n", x);
return 0;
}

levlerin parametre deikenleri de (formal parameters), blok bilinirlik alan kuralna


uyar. Bu deikenler ilevin ana blou iinde bilinir. lev parametre deikeninin bilinirlik
alan, ilevin ana blounun kapanmasyla sonlanr. Yani ilev parametre deikeninin
bilinirlik alan, ilevin ana bloudur.
void func (int a, double b)
{
/* a ve b bu ilevin her yerinde bilinir. */
}
Yukardaki rnekte func ilevinin parametre deikenleri olan a ve b isimli deikenler,
func ilevinin her yerinde kullanlabilir.

Global Deikenler

C dilinde bloklarn dnda da deikenlerin tanmlanabileceini biliyorsunuz. Bloklarn


dnda tanmlanan deikenler "global deikenler" (global variables) olarak
isimlendirilir.
Derleme ileminin bir yn vardr. Bu yn kaynak kod iinde yukardan aaya dorudur.
Bir deiken yerel de olsa global de olsa, tanmlamas yaplmadan nce kullanlmas
geersizdir. Global deikenler tanmlandklar noktadan sonra kaynak dosyann sonuna
kadar her yerde bilinir:

94/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
int g;
void func()
{
g = 10;
}
int main()
{
g = 20;
printf("g = %d\n", g);
func();
printf("g = %d\n", g);

/* g = 20 */
/* g = 10 */

return 0;

}
Yukardaki rnekte g deikeni blok dnda tanmland iin -ya da hibir ilevin iinde
tanmlanmad iin- global deikendir. g deikeninin bilinirlik alan, dosya bilinirlik
alandr. Yani g deikeni, tanmlandktan sonra tm ilevlerin iinde kullanlabilir.
Yukardaki programda nce g global deikenine 20 deeri atanyor.Daha sonra bu deer
printf ileviyle ekrana yazdrlyor. Daha sonra func ilevi arlyor. func ilevi arlnca
kodun ak func ilevine geer. func ilevi iinde de g global deikeni bilinir. func
ilevinde global y deikenine 10 deerinin atanmasndan sonra bu deer yine printf
ileviyle ekrana yazdrlyor.

Ayn simli Deikenler

C dilinde ayn isimli birden fazla deiken tanmlanabilir. Genel kural udur: ki
deikenin bilinirlik alanlar ayn ise, bu deikenler ayn ismi tayamaz. Ayn ismi
tamalar derleme zamannda hata oluturur. ki deikenin bilinirlik alanlarnn ayn
olmas ne anlama gelir? ki deikenin bilinirlik alanlar, ayn kapanan kme ayrac ile
sonlanyorsa, bu deikenlerin bilinirlik alanlar ayn demektir.
{

float a;
int b;
double a;
{
int c;
/*...*/
}

/* Geersiz */

}
Yukardaki kod geersizdir. nk her iki a deikeninin de bilinirlik alan ayndr.
Farkl bilinirlik alanlarna sahip birden fazla ayn isimli deiken tanmlanabilir. nk
derleyiciler iin, artk bu deikenlerin ayn isimli olmas nemli deildir. Bunlar bellekte
farkl yerlerde tutulur. Aadaki rnei inceleyin:

95/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
int main()
{
int x = 100;
printf("%d\n", x);
{
int x = 200;
printf("%d\n", x);
{
int x = 300;
printf("%d\n", x);
}
}
return 0;
}
Yukardaki program parasnda bir hata bulunmuyor. nk her x deikeninin de
bilinirlik alanlar birbirlerinden farkldr. Peki yukardaki rnekte i bloklarda x ismi
kullanldnda derleyici bunu hangi x deikeni ile ilikilendirir?
Bir kaynak kod noktas, ayn isimli birden fazla deikenin bilinirlik alan iinde ise, bu
noktada deikenlerden hangisine eriilir?
Derleyici, bir ismin kullanm ile karlatnda bu ismin hangi yazlmsal varla ait
olduunu bulmaya alr. Bu ileme "isim arama" (name lookup) denir. sim arama, dar
bilinirlik alanndan geni bilinirlik alanna doru yaplr. Yani derleyici sz konusu ismi
nce kendi blounda arar. Eer isim, bu blok iinde tanmlanmam ise bu kez isim
kapsayan bloklarda aranr. sim, kapsayan bloklarda da bulunamaz ise bu kez global isim
alannda aranr.
Dar bilinirlik alanna sahip isim, daha geni bilinirlik alannda yer alan ayn ismi maskeler,
onun grnmesini engeller. Aadaki program inceleyin:
void func1()
{
int k;
/***/
}
void func2()
{
int k;
/***/
}
void func3()
{
int k;
/***/
}
Yukardaki kod parasnda bir hata sz konusu deildir. Her ilevde de k isimli bir
deiken tanmlanm olsa da bunlarn bilinirlik alanlar tamamen birbirinden farkldr.
Bir global deikenle ayn isimli yerel bir deiken olabilir mi? ki deikenin bilinirlik
alanlar ayn olmad iin bu durum bir hataya neden olmaz.
Ayn isimli hem bir global hem de bir yerel deikene eriilebilen bir noktada, eriilen
yerel deiken olur. nk ayn bilinirlik alannda, birden fazla ayn isimli deiken olmas
durumunda, o alan iinde en dar bilinirlik alanna sahip olanna eriilebilir. Aadaki kodu
inceleyin:

96/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
int

g = 20;

/* g global deiken */

void func()
{
/* global g deikenine atama yaplyor. */
g = 100;
/* global g deikeninin deeri yazdrlyor. */
printf("global g = %d\n", g);
}
int main()
{
int g; /* g yerel deiken */
/* yerel g deikenine atama yaplyor */
g = 200;
/* yerel g yazdrlyor. */
printf("yerel g = %d\n", g);
func();
/* yerel g yazdrlyor. */
printf("yerel g = %d\n", g);
}

return 0;

levlerin kendileri de btn bloklarn dnda tanmlandklarna gre global varlklardr.


Gerekten de ilevler kaynak kodun her yerinden arlabilir. Ayn bilinirlik alanna ilikin,
ayn isimli birden fazla deiken olmayacana gre, ayn isme sahip birden fazla ilev de
olamaz.
[Ancak C++ dilinde isimleri ayn parametrik yaplar farkl ilevler tanmlamak mmkndr.]
Bildirilen bir isme bilinirlik alan iinde her yerde ulalamayabilir. nk bir isim, daha
dar bir bilinirlik alannda ayn isim tarafndan maskelenmi olabilir. Bu yzden "bilinirlik
alan" dnda bir de "grlebilirlik" (visibility) teriminden sz edilebilir.
[C++ dilinde global bir ismin yerel bir isim tarafndan maskelenmesi durumda, global isme znrlk ileci
(scope resolution operator) ismi verilen bir ilele eriim mmkndr.]

Nesnelerin mrleri

mr (storage duration / lifespan), nesnelerin, programn alma zaman iinde bellekte


yer kaplad sreyi anlatmak iin kullanlan bir terimdir. Bir kaynak kod iinde
tanmlanm deikenlerin hepsi, program almaya baladnda ayn zamanda
yaratlmaz. Programlarda kullanlan varlklar, mrleri bakmndan gruba ayrlabilir:
1. Statik mrl varlklar
2. Otomatik mrl varlklar
3. Dinamik mrl varlklar

i. Statik mrl Varlklar

Statik mrl varlklar (static duration static storage class), programn almaya
balamasyla bellekte yerlerini alr, programn almas bitene kadar varlklarn
srdrr, yani bellekte yer kaplar. Statik mrl varlklar, genellikle ama kod (.obj) iine
yazlr. C dilinde statik mrl ayr varlk grubu vardr:
global deikenler
dizgeler (ift trnak iindeki yazlar)
statik yerel deikenler

97/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Dizgeler ile statik yerel deikenleri daha sonra greceksiniz.


Global deikenler statik mrl varlklardr. Yani global deikenler programn almas
sresince yaayan, yani programn almas sresince bellekte yer kaplayan
deikenlerdir.

ii. Otomatik mrl Varlklar

Otomatik mrl nesneler programn almasnn belli bir zamannda yaratlan, belli sre
etkinlik gsterdikten sonra yok olan, yani mrlerini tamamlayan nesnelerdir. Bu tr
nesnelerin mrleri, programn toplam alma sresinden ksadr.
Yerel deikenler, otomatik mrldr. Programn alma zamannda tanmlandklar
bloun almas baladnda yaratlrlar, bloun almas bitince yok olurlar, yani
mrleri sona erer.
void func(int a, int b)
{
int result;
/***/
}
Yukardaki func ilevinin ana blou iinde result isimli bir yerel deiken tanmlanyor.
Programn almas srasnda func ilevinin koduna girildiinde result deikeni yaratlr.
Programn ak func ilevinden ktnda, result deikeninin mr sona erer.
Statik mrl deikenlerle otomatik mrl deikenler arasnda ilkdeer verme
(initialization) asndan da fark vardr. Statik mrl olan global deikenlere de yerel
deikenlerde olduu gibi ilkdeer verilebilir.
lkdeer verilmemi ya da bir atama yaplmam bir yerel deikenin iinde bir p deer
bulunur. Bu deer o an bellekte o deiken iin ayrlm yerde bulunan 1 ve 0 bitlerinin
oluturduu deerdir.
lkdeer verilmemi statik mrl deikenlerin 0 deeri ile balatlmas gvence
altndadr. lk deer verilmemi ya da bir atama yaplmam global deikenler iinde her
zaman 0 deeri vardr. Yani bu deikenler derleyici tarafndan retilen kod yardmyla 0
deeriyle balatlr.
Aadaki program derleyerek altrn:
#include <stdio.h>
int g;
int main()
{
int y;
printf("g = %d\n", g);
printf("y = %d\n", y);
}

/* Yanl /

return 0;

Bir yerel deikenin ilkdeer verilmeden ya da kendisine bir atama yaplmadan


kullanlmas bir programlama hatasdr. Derleyicilerin hemen hemen hepsi byle
durumlarda mantksal bir uyar iletisi verir.
[C++ dilinde byle bir zorunluluk yoktur.]
Global deikenlere ancak deimez ifadeleriyle ilkdeer verilebilir. Global deikenlere
ilkdeer verme ileminde kullanlan ifadede (initializer), deikenler ya da ilev ar
ifadeleri kullanlamaz. fade yalnzca deimezlerden olumak zorundadr.

98/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

[Global deikenlere deimez ifadesi olmayan ifadelerle ilkdeer verilmesi C++ dilinde geerlidir. Yeni C
derleyicilerin ou, global deikenlere deimez ifadesi olmayan ifadelerle ilkdeer verilmesi durumunda da
kodu geerli sayma eilimindedir. Tanabilirlik asndan bu durumdan kanlmasn salk veriyoruz.]
Ancak yerel deikenlere ilkdeer verilme ileminde byle bir kstlama yoktur.
#include <stdio.h>
int func(void);
int x = 5;
int y = x + 5;
int z = func();

/* Geersiz */
/* Geersiz */

int main()
{
int a = b;
int k = b - 2;
int m = func();
/***/
}
Yukardaki programda main ilevi iinde a, k, m deikenlerinin tanmlanmalar geerlidir.

iii. Dinamik mrl Varlklar

Dinamik bellek ilevleri ile yerleri ayrlm nesneler, dinamik mrldr. Dinamik bellek
ilevleri ile yaratlm nesneleri daha sonra greceksiniz.

Global ve Yerel Deikenlerin Karlatrlmas

Bir programda bir deiken gereksinimi durumunda, global ya da yerel deiken


kullanlmas baz avantajlar ya da dezavantajlar getirebilir. Ancak genel olarak global
deikenlerin baz sakncalarndan sz edilebilir. zel bir durum sz konusu deil ise,
yerel deikenler global deikenlere tercih edilmeli, global deikenler ancak zorunlu
durumlarda kullanlmaldr. Global deikenler aadaki sakncalara neden olabilir:
1.Global deikenler statik mrl olduklarndan programn sonuna kadar bellekte
yerlerini korur. Bu nedenle bellein daha verimsiz olarak kullanlmalarna neden olurlar.
2. Global deikenler tm ilevler tarafndan ortaklaa paylaldndan, global
deikenlerin oka kullanld kaynak dosyalar okumak daha zordur.
3. Global deikenlerin ska kullanld bir kaynak dosyada, hata arama maliyeti daha
yksektir. Global deikene ilikin bir hata sz konusu ise, bu hatay bulmak iin tm
ilevler aratrlmaldr. Tm ilevlerin global deikenlere ulaabilmesi, bir ilevin global
bir deikeni yanllkla deitirebilmesi riskini de dourur.
4. Global deikenlerin kullanld bir kaynak dosyada, deiiklik yapmak da daha fazla
aba gerektirir. Kaynak kodun eitli blmleri, birbirine global deiken kullanmlaryla
sk bir ekilde balanm olur. Bu durumda kaynak kod iinde bir yerde deiiklik
yaplmas durumunda baka yerlerde de deiiklik yapmak gerekir.
5. Programclarn ou, global deikenleri mmkn olduu kadar az kullanmak ister.
nk global deikenleri kullanan ilevler, baka projelerde kolaylkla kullanlamaz.
Kullanldklar projelerde de ayn global deikenlerin tanmlanm olmas gerekir.
Dolaysyla global deikenlere dayanlarak yazlan ilevlerin yeniden kullanlabilirlii
azalr.

99/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

6. Global deikenler global isim alann kirletir. Bu noktaya ileride "balant" kavram ele
alnd zaman yeniden deinilecek.

levlerin Geri Dn Deerlerini Tutan Nesneler

levler geri dn deerlerini, geici bir nesne yardmyla kendilerini aran ilevlere
iletir. Aadaki program inceleyin:
#include <stdio.h>
int add(int x, int y)
{
return x + y;
}
int main()
{
int a, b, sum;
printf("iki say girin: ");
scanf("%d%d", &a, &b);
sum = add(a, b);
printf("toplam = %d\n", sum);
}

return 0;

Bir ilevin geri dn deerinin tr aslnda, ilevin geri dn deerini iinde tayacak
geici nesnenin tr demektir. Yukarda tanm verilen add isimli ilevin main ilevi
iinden arldn gryorsunuz. Programn ak, add ilevi iinde return deyimine
geldiinde, geici bir nesne yaratlr. Bu geici nesne, return ifadesiyle ilkdeerini alr.
Yani return ifadesi aslnda oluturulan geici nesneye ilkdeerini veren ifadedir. Geri
dn deeri reten bir ileve yaplan ar, bu ilevin geri dn deerini iinde tutan
geici nesneyi temsil eder. Peki bu geici nesnenin mr ne kadardr? Bu nesne, return
deyimiyle yaratlr ve ilev arsn ieren ifadenin deerlendirilmesi sona erince yok
edilir. Yani rnekteki main ilevi iinde yer alan
sum = add(a, b);
deyiminin yrtlmesinden sonra, geici nesnenin mr de sona erer.

100/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

KONTROL DEYMLER
C dilinde yazlm bir programn cmlelerine deyim(statement) dendiini biliyorsunuz.
Baz deyimler, yalnzca derleyici programa bilgi verir. Bu deyimler derleyicinin ilem
yapan bir kod retmesine neden olmaz. Byle deyimlere "bildirim deyimi" (declaration
statement) denir.
Baz deyimler derleyicinin ilem yapan bir kod retmesine neden olur. Byle deyimlere
"yrtlebilir deyim" (executable statement) denir.
Yrtlebilir deyimler de farkl gruplara ayrlabilir:

Yaln Deyim:

Bir ifadenin, sonlandrc atom ile sonlandrlmasyla oluan deyimlere yaln deyim (simple
statement) denir;
x = 10;
y++;
func();
Yukarda 3 ayr yaln deyim yazlmtr.

Bo Deyim:

C dilinde tek bana bulunan bir sonlandrc atom ';', kendi bana bir deyim oluturur.
Bu deyime bo deyim (null statement) denir. Bo bir blok da bo deyim oluturur:
;
{}
Yukardaki her iki deyim de bo deyimdir.

Bileik Deyim:

Bir blok iine alnm bir ya da birden fazla deyimin oluturduu yapya, bileik deyim
(compound statement) denir. Aada bir bileik deyim grlyor.
{

x = 10;
y++;
func();

Kontrol deyimi:

Kontrol deyimleri, programn ak ynn deitirebilen deyimlerdir. Kontrol deyimleri ile


programn ak farkl noktalara ynlendirilebilir. Bunlar, C dilinin nceden belirlenmi baz
szdizimi kurallarna uyar, kendi szdizimleri iinde en az bir anahtar szck ierir. C
dilinde aadaki kontrol deyimleri vardr:
if deyimi
while dng deyimi
do while dng deyimi
for dng deyimi
break deyimi
continue deyimi
switch deyimi
goto deyimi
return deyimi

101/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

if DEYM
C dilinde program akn denetlemeye ynelik en nemli deyim if deyimidir.
En yaln biimiyle if deyiminin genel szdizimi aadaki gibidir:
if (ifade)
deyim;
if ayrac iindeki ifadeye koul ifadesi (conditional expression) denir.
if ayracn izleyen deyime, if deyiminin doru ksm (true path) denir.
if deyiminin doru ksmn oluturan deyim, bir yaln deyim (simple statement) olabilecei
gibi, bir bo deyim (null statement), bir bileik deyim (compound statement) ya da
baka bir kontrol deyimi de (control statement) olabilir.
Yaln if deyiminin yrtlmesi aadaki gibi olur:
nce koul ifadesinin saysal deerini hesaplar. Hesaplanan saysal deer, mantksal
DORU ya da YANLI olarak yorumlanr. Koul ifadesinin hesaplanan deeri 0 ise yanl,
0'dan farkl bir deer ise doru olarak yorumlanr. rnein koul ifadesinin hesaplanan
deerinin 5 olduunu dnelim. Bu durumda kontrol ifadesi doru olarak
deerlendirilir. Eer ifade DORU olarak yorumlanrsa, if deyiminin doru ksm yaplr,
ifade YANLI olarak yorumlanrsa doru ksm yaplmaz. Yaln if deyimi, bir ifadenin
doruluuna ya da yanllna gre, bir deyimin yaplmas ya da yaplmamasna dayanr.
Aadaki program derleyerek altrn:
int main()
{
int x;
printf("bir sayi girin : ");
scanf("%d", &x);
if (x > 10)
printf("if deyiminin doru ksm!\n");
}

return 0;

main ilevi iinde yazlan if deyimiyle, klavyeden girilen tamsaynn 10'dan byk olmas
durumunda printf ars yrtlr, aksi halde yrtlmez.

Yanl Ksm Olan if Deyimi

if kontrol deyimi, else anahtar szcn de ierebilir. Byle if deyimine, yanl ksm
olan if deyimi denir. Yanl ksm olan if deyiminin genel biimi aadaki gibidir:
if (ifade)
deyim1;
else
deyim2;

Bu kez if deyiminin doru ksmn izleyen deyimden sonra else anahtar szcnn, daha
sonra ise bir baka deyimin yer aldn gryorsunuz. Genel biimdeki deyim2'ye if
deyiminin yanl ksm (false path) denir.
if deyiminin koul ifadesi, mantksal olarak DORU ya da YANLI olarak yorumlanr. Bu
kez koul ifadesinin DORU olmas durumunda deyim1, YANLI olarak yorumlanmas
durumunda deyim2 yaplr. Yanl ksm olan if deyimi, bir koul ifadesinin doru ya da

102/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

yanl olmasna gre iki ayr deyimden birinin yaplmasna yneliktir. Yani ifade doru ise
bir i, yanl ise baka bir i yaplr.
Aadaki rnei inceleyin:
#include <stdio.h>
int main()
{
char ch;
printf("bir karakter girin : ");
ch = getchar();
if (ch >= 'a' && ch <= 'z')
printf("%c kucuk harf!\n", ch);
else
printf("%c kucuk harf degil!\n", ch);
}

return 0;

Yukardaki main ilevinde standart getchar ilevi kullanlarak klavyeden bir karakter
alnyor. Alnan karakterin sra numaras, ch isimli deikene atanyor. Koul ifadesinin
doru ya da yanl olmas durumuna gre, klavyeden alnan karakterin kk harf olup
olmad bilgisi ekrana yazdrlyor. Koul ifadesine bakalm:
ch >= 'a' && ch <= 'z'
Bu ifadenin doru olmas iin "mantksal ve (&&)" ilecinin her iki teriminin de doru
olmas gerekir. Bu da ancak, ch karakterinin kk harf karakteri olmas ile mmkndr.
if deyiminin doru ve/veya yanl ksm bir bileik deyim olabilir. Bu durumda, koul
ifadesinin doru ya da yanl olmasna gre, birden fazla yaln deyimin yrtlmesi
salanabilir. Aadaki rnei inceleyin:
/***/
if (x > 0) {
y = x * 2 + 3;
z = func(y);
result = z + x;
}
else {
y = x * 5 - 2;
z = func(y - 2);
result = z + x - y;
}
/***/
Yukardaki if deyiminde, x > 0 ifadesinin doru olup olmasna gre, result deikeninin
deeri farkl ilemlerle hesaplanyor. if deyiminin hem doru hem de yanl ksmlarn
bileik deyimler oluturuyor.
Bir if deyiminin yanl ksm olmak zorunda deildir. Ancak bir if deyimi yalnzca else
ksmna sahip olamaz. Bu durumda if deyiminin doru ksmna bo deyim ya da bo
bileik deyim yerletirilmelidir:
if (ifade)
;
else
deyim1;

103/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

ya da
if (ifade)
{ }
else
deyim1;
Yalnzca yanl ksm olan, doru ksm bir bo deyim olan bir if deyimi, okunabilirlik
asndan iyi bir seenek deildir. Byle durumlarda daha iyi bir teknik, koul ifadesinin
mantksal tersini alp, if deyiminin yanl ksmn ortadan kaldrmaktr:
if (!ifade)
deyim1;
Aadaki kod parasn inceleyin:
/***/
if (x > 5)
;
else {
func1(x);
func2(x);
}
/***/
Yukardaki if deyiminde, x deikeninin deeri 5'ten bykse bir ey yaplmyor, aksi
halde func1 ve func2 ilevleri x deikeninin deeri ile arlyor. Koul ifadesi ters
evrilerek if deyimi yeniden yazlrsa:
/***/
if (x <= 5) {
func1(x);
func2(x);
}
/***/
if ayracnn iinde, ifade tanmna uygun herhangi bir ifade bulunabilir:
if (10)
deyim1;
if (-1)
deyim2;
Yukardaki koul ifadelerinin deeri, her zaman doru olarak yorumlanr. nk ifadeler,
sfrdan farkl deere sahiptir.
Aadaki koul ifadesi ise her zaman yanl olarak yorumlanacandan if deyiminin doru
ksm hibir zaman yrtlmez:
if (0)
deyim1;
Aadaki if deyiminde ise, x deikeninin deerinin 0 olup olmamasna gre, deyim1 ve
deyim2 yrtlr:

104/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

if (x) {
deyim1;
deyim2;
/***/
}
Yukardaki yapyla aadaki yap edeerdir:
if (x != 0) {
deyim1;
deyim2;
}
Aadaki rnei inceleyin :
if (!x) {
deyim1;
deyim2;
}
Bu if deyiminde ise ancak x deikeninin deerinin 0 olmas durumunda deyim1 ve
deyim2 yrtlr.
Yine yukardaki yapyla aadaki yap edeerdir:
if (x == 0) {
deyim1;
deyim2;
}

Koul fadesinde Atama lecinin Kullanlmas

if deyiminin koul ifadesinde atama ileci sklkla kullanlr. Bylece, atama ilecinin
rettii deerden faydalanlr: Aadaki kod parasn inceleyin:
if ((x = getval()) > 5)
func1(x);
else
func2(x);
if deyiminin koul ifadesinde ise, arlan getval ilevinin geri dn deeri, x deikenine
aktarlyor. Atama ilecinin rettii deerin nesneye atanan deer olduunu anmsayn.
Atama ileci ile oluturulan ifadenin, ncelik ayrac iine alndn gryorsunuz. Bu
durumda hem getval ilevinin geri dn deeri x deikenine aktarlyor hem de ilevin
geri dn deerinin 5'ten byk olup olmad sorgulanyor. ncelik ayrac
kullanlmasayd getval ilevinin geri dn deerinin 5'ten byk olup olmamasna gre x
deikenine 0 ya da 1 deeri atanrd. Bu durumda da ya func1 ilevi 1 deeriyle ya da
func2 ilevi 0 deeriyle arlrd. Deyim aadaki gibi de yazlabilirdi, deil mi?
x = getval();
if (x > 5)
func1(x);
else
func2(x);
Ancak kalp kod, daha karmak deyimlerin yazlmasnda kolaylk salar. Aadaki if
deyiminin nasl yrtleceini dnn. "Mantksal ve" ilecinin birinci ksmnn, daha
nce ele alnmasnn, yani "ksa devre" davrannn gvence altnda olduunu anmsayn.

105/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

if ((y = getval()) > 5 && isprime(x))


func1(y);
func2(y);

e if Deyimleri

if deyiminin doru ya da yanl ksmn, baka bir if deyimi de oluturabilir:


if (ifade1)
if (ifade2) {
deyim1;
deyim2;
deyim3;
}
deyim4;
Bu rnekte ikinci if deyimi birinci if deyiminin doru ksmn oluturur. Birinci ve ikinci if
deyimlerinin yanl ksmlar yoktur.
ie if deyimlerinde, son if anahtar szcnden sonra gelen else anahtar szc, en
iteki if deyimine ait olur:
if (ifade1)
if (ifade2)
deyim1;
else
deyim2;
Yukardaki rnekte, yazm biimi nedeniyle else ksmnn birinci if deyimine ait olmas
gerektii gibi bir grnt verilmi olsa da, else ksm ikinci if deyimine aittir. else anahtar
szc, bu gibi durumlarda, kendisine yakn olan if deyimine ait olur (dangling else).
else anahtar szcnn birinci if deyimine ait olmas isteniyorsa, birinci if deyiminin
doru ksm bloklanmaldr:
if (ifade1) {
if (ifade2)
deyim1;
}
else
deyim2;
Yukardaki rnekte else ksm birinci if deyimine aittir.
if (ifade1) {
if (ifade2)
deyim1;
else {
deyim2;
deyim3;
}
deyim4;
}
else
deyim5;
Yukardaki rnekte birinci if deyiminin doru ksm, birden fazla deyimden olutuu iin bu deyimlerden birisi de yine baka bir if deyimidir- bloklama yaplyor. deyim5, birinci if
deyiminin yanl ksmn oluturur.

106/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

else if Merdiveni

Aadaki if deyimlerini inceleyin:


Eer bir karlatrmann doru olarak sonulanmas durumunda yaplan dier
karlatrmalarn doru olmas sz konusu deilse, bu tr karlatrmalara ayrk
karlatrma denir. Ayrk karlatrmalarda, if deyimlerinin ayr ayr kullanlmas kt
tekniktir:
if (m == 1)
printf("Ocak\n");
if (m == 2)
printf(ubat\n");
if (m == 3)
printf("Mart\n");
/***/
if (m == 12)
printf("Aralk\n");
Yukardaki rnekte m deikeninin deerinin 1 olduunu dnn. Bu durumda ekrana
Ocak yazs yazdrlr. Fakat daha sonra yer alan if deyimleriyle m deikeninin srasyla 2,
3, ... 12'ye eit olup olmad ayr ayr snanr. Ama x deikeni 1 deerine sahip
olduundan, btn dier if deyimleri iindeki kontrol ifadelerinin yanl olarak
deerlendirilecei bellidir. Bu durumda birinci if deyiminden sonraki btn if deyimleri
gereksiz yere yrtlm olur. Ayn zamanda kodun okunabilirlii de bozulur.
Ayrk karlatrmalarda else if merdivenleri kullanlmaldr:
if (ifade1)
deyim1;
else
if (ifade2)
deyim2;
else
if (ifade3)
deyim3;
else
if (ifade4)
deyim4;
else
deyim5;
Bu yapda, herhangi bir if deyiminin koul ifadesi doru olarak deerlendirilirse programn
ak hibir zaman baka bir if deyimine gelmez. Bu yapya, else if merdiveni (cascaded if
/ else if ladder) denir. else if merdivenlerinin yukardaki biimde yazl, zellikle uzun
else if merdivenlerinde okunabilirlii bozduu iin aadaki yazm biimi, okunabilirlik
asndan tercih edilmelidir:
if (ifade1)
deyim1;
else if (ifade2)
deyim2;
else if (ifade3)
deyim3;
else if (ifade4)
deyim4;
else
deyim5;

107/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Merdiveninin en sonundaki if deyiminin yanl ksmnn zel bir nemi vardr. Yukardaki
rnekte deyim5, merdivenin son if deyiminin else ksmnda yer alyor. Merdiven iindeki
hibir if deyiminin koul ifadesi doru deilse, son if deyimininin yanl ksm yaplr, deil
mi? Yukardaki merdivenin yrtlmesi sonucu, deyim1, deyim2, deyim3, deyim4,
deyim5'den biri mutlaka yaplr.
Son basamaktaki if deyiminin yanl ksm olmayan bir else if merdiveninden, hibir i
yaplmadan da klabilir.
Hem okunabilirlik asndan hem de verim asndan, else if merdiveninde olasl ya da
skl daha yksek olan koullar, daha yukarya kaydrlmaldr.

Sk Yaplan Hatalar

zellikle C'ye yeni balayanlarn sk yapt bir hata, yaln if deyimiyle yanl ksm olan if
deyimini birbirine kartrmaktr. Yani if deyiminin yanl ksm unutulur:
#include <stdio.h>
int main()
{
int x;
printf("bir sayi girin: ");
scanf("%d", &x);
if (x % 2 == 0)
printf("%d cift sayi!\n", x);
printf("%d teksayi!\n", x);
}

return 0;

if ayrac iindeki ifadenin yanl olmas durumunda bir yanllk sz konusu deildir. Ama
ifade doru ise ekrana ne yazlr? Klavyeden 28 deerinin girildiini dnelim:
28 ift sayi!
28 tek sayi!
Belki de en sk yaplan hata, if ayracnn sonuna yanllkla sonlandrc atomun (;)
yerletirilmesidir. Aadaki main ilevini inceleyin:
#include <stdio.h>
int main()
{
int x;
printf("bir sayi girin: ");
scanf("%d", &x);
if (x % 2 == 0);
printf("%d cift sayi!\n", x);
}

return 0;

Yukardaki main ilevinde, x % 2 == 0 ifadesi doru da olsa yanl da olsa printf ilevi
arlr. printf ars if deyiminin dndadr. if deyiminin doru ksmn bir bo deyimin
(null statement) oluturmas szdizim kurallarna kesinlikle uyan bir durumdur. Yazlan if
deyimi, gerekte "x ift ise bir ey yapma" anlamna gelir. Bilinli bir biimde yazlma

108/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

olasl yksek olmayan bu durum iin, derleyicilerin ou mantksal bir uyar iletisi
vermez.
Ayn hata, yanl ksm olan bir if deyiminin doru ksmnda yaplsayd bir szdizim hatas
oluurdu, deil mi?
if (x > 5);
printf("doru!\n");
else
printf("yanl\n");
else anahtar szcnn, bir if deyimine bal olarak kullanlmas gerektiini biliyorsunuz.
Yukardaki kod parasndaki if deyimi, doru ksm "hibir ey yapma" anlamna gelen bir
if deyimidir. Dolaysyla, else anahtar szc hibir if deyimine balanmam olur. Bu da
bir szdizim hatasdr. nk bir if deyimine balanmayan, bir else olamaz.
Tabi ki bir if deyiminin doru ya da yanl ksmn bir bo deyim (null statement)
oluturabilir. Bu durumda okunabilirlik asndan, bu bo deyimin bir tab ieriden
yazlmas, bo deyimin bilinli olarak yerletirildii konusunda gl bir izlenim verir.
if ((val = getval()) != 0)
;
Sk yaplan baka bir yanllk, if ayrac iinde karlatrma ileci (==) yerine atama
ilecinin (=) kullanlmasdr.
/***/
if (x == 5)
printf("eit\n");
/***/
Yukardaki if deyiminde, x deikeninin deeri 5'e eitse printf ilevi arlyor.
Karlatrma ilecinin yan etkisi yoktur. Yani yukardaki if ayrac iinde x deikeninin
deeri, 5 deimezi ile yalnzca karlatrlyor, deitirilmiyor. Oysa karlatrma
ilecinin yerine yanllkla atama ileci kullanlrsa:
/***/
if (x = 5)
printf("eit\n");
/***/
Atama ileci, atama ilecinin sa tarafndaki ifadenin deerini retir, if ayrac iindeki
ifadenin deeri 5 olarak hesaplanr. 5, sfr d bir deer olduundan, x deikeninin
deeri ne olursa olsun, printf ilevi arlr. Atama ilecinin yan etkisi olduundan, x
deikenine de if deyiminin yrtlmesi ile 5 deeri atanr.
C derleyicilerinin ou, if ayrac iindeki ifade yaln bir atama ifadesi ise, durumu
pheyle karlayarak, mantksal bir uyar iletisi verir. rnein Borland derleyicilerinde
tipik bir uyar iletisi aadaki gibidir:
warning : possibly incorrect assignment! (muhtemelen yanl atama!)
Oysa if ayrac iinde atama ileci bilinli olarak da kullanlabilir:
if (x = func())
m = 20;
Bilinli kullanmda, derleyicinin mantksal uyar iletisinin kaldrlmas iin, ifade aadaki
gibi dzenlenebilir:

109/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

if ((x = func()) != 0)
m = 20;
Yukardaki rnekte olduu gibi, atama ilecinin rettii deer, ak olarak bir
karlatrma ilecine terim yaplrsa, derleyiciler bu durumda bir "mantksal uyar" iletisi
vermez.
ok yaplan baka bir hata da, if deyiminin doru ya da yanl ksmn bloklamay
unutmaktr. Yani bir bileik deyim yerine yanllkla yaln deyim yazlr.
if (x == 10)
m = 12;
k = 15;
Yukardaki if deyiminde yalnzca
m = 12;
deyimi if deyiminin doru ksmn oluturur.
k = 15;
deyimi, if deyimi dndadr. Bu durum genellikle programcnn, if deyiminin doru ya da
yanl ksmn nce yaln bir deyimle oluturmasndan sonra, doru ya da yanl ksma
ikinci bir yaln deyimi eklerken, bloklamay unutmas yznden oluur.
Kodun yazl biiminden de, if deyiminin doru ksmnn, yanllkla bloklanmad
anlalyor. Dorusu aadaki gibi olmalyd:
if (x == 10) {
m = 12;
k = 15;
}
Aadaki if deyimi ise, yine if anahtar szc ile elenmeyen bir else anahtar szc
kullanld iin geersizdir:
if ( x == 10)
m = 12;
k = 15;
else
/* Geersiz */
y = 20;
Bu tr yanllklardan saknmak iin baz programclar, if deyiminin doru ya da yanl
ksm yaln deyimden olusa da, bu basit deyimi bileik deyim olarak yazarlar:
if (x > 10) {
y = 12;
}
else {
k = 5;
}
Yukardaki rnekte if deyiminin doru ya da yanl ksmna baka bir yaln deyimin
eklenmesi durumunda szdizim hatas ya da bir yanllk olumaz. Ancak gereksiz
bloklamadan kanmak okunabilirlik asndan daha dorudur.
if ayrac iinde, bir deerin belirli bir aralkta olup olmadnn snanmak istendiini
dnn:

110/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

if (10 < x < 20)


func();
Yukardaki if deyiminde, x deikeni 10 20 deerleri arasnda ise func ilevinin
arlmas istenmi. Ancak if ayrac iinde yer alan ifade her zaman dorudur. Yani func
ilevi ars her zaman yrtlr. Kktr ileci soldan saa ncelik ynne sahip
olduu iin, nce daha soldaki kktr ileci deer retir. lecin rettii deerin 1 ya da
0 olduunu biliyorsunuz. retilen 1 ya da 0 deeri, daha sadaki kktr ilecinin terimi
olur. 20 deeri, 1 ya da 0'dan daha byk olduuna gre, ifade her zaman dorudur.
Tehlikeli bir baka yanllk da, if ayrac iindeki ifadenin bir ilev ar ifadesi olmas
durumunda, ilev ar ilecinin unutulmasdr:
if (func())
m = 12;
yerine
if (func)
m = 12;
yazldn dnn. Bu durum bir szdizim hatas oluturmaz. Bu durumda her zaman, if
deyiminin doru ksm yrtlr. C dilinde bir ilev ismi, o ilevin kodunun bellekteki
yerine edeer bir adres bilgisi olarak ele alnr. Bu adres bilgisi her zaman sfrdan farkl
bir deer olduundan, koul ifadesi her zaman doru olarak deerlendirilir.

Snama levleri

bool veri tr, C'nin doal veri trlerinden olmad iin, C dilinde yazlan snama
ilevleri, yani bir soruya yant veren ilevler ounlukla int trne geri dner.
[C99 standartlaryla bool tr de doal veri tr olarak eklenmitir. C99 standartlar ile C diline gre _bool
anahtar szc eklenmitir.]
rnein bir tamsaynn asal say olup olmadn snayan bir ilev yazldn dnelim.
levin parametrik yaps aadaki gibi olur:
int isprime(int val);
Snama ilevlerinin geri dn deerlerinde yaygn olarak kullanlan anlama yledir:
Eer ilev, sorulan soruya doru ya da olumlu yant veriyorsa, 0 d herhangi bir deerle
geri dner. Sorulan sorunun ya da yaplan snamann sonucu, olumsuz ya da yanl ise,
ilev 0 deeriyle geri dner. Bu durum snama ilevini aran kod parasnn iini
kolaylatrr, aadaki gibi kalp kodlarn yazlmasna olanak verir:
Snamann olumlu sonulanmas durumunda bir i yaplacaksa aadaki gibi bir deyim
yazlabilir:
if (isprime(val))
deyim;
Snamann olumsuz sonulanmas durumunda bir i yaplacaksa
if (!isprime(val))
deyim;
yazlabilir.
Aadaki program inceleyin:

111/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
#include <ctype.h>
int main()
{
int ch;
printf("bir karakter girin : ");
ch = getchar();
if (isupper(ch))
printf("%c buyuk harf!\n", ch);
else
printf("%c buyuk harf degil!\n", ch);
}

return 0;

isupper, kendisine kod numaras gnderilen karakterin, byk harf karakteri olup
olmadn snayan standart bir ilevdir. Eer kod numarasn ald karakter byk harf
ise ilev, sfrdan farkl bir deere geri dner. Byk harf deil ise, ilevin geri dn
deeri 0'dr. Bu durumda main ilevinde yer alan if deyiminin koul ifadesi "ch byk harf
ise" anlamna gelir, deil mi? Koul ifadesi
if (!isupper(ch))
biiminde yazlsayd, bu "ch byk harf deil ise" anlamna gelirdi.
Aada, bir yln artk yl olup olmadn snayan isleap isimli bir ilev tanmlanyor. 4'e
tam blnen yllardan, 100'e tam blnmeyenler ya da 400'e tam blnenler artk
yldr:
#include <stdio.h>
int isleap(int y)
{
return y % 4 == 0 && (y % 100 != 0 || y % 400 == 0);
}
int main()
{
int year;
printf("bir yil girin: ");
scanf("%d", &year);
if (isleap(year))
printf("%d yili artik yildir!\n", year);
else
printf("%d yili artik yil degildir!\n", year);
return 0;
}

Standart Karakter Snama levleri

Karakter snama ilevleri, karakterler hakknda bilgi edinilmesini salayan ilevlerdir.


Derleyicilerin ounda bu ilevler, ctype.h balk dosyas iinde ayn zamanda makro
olarak tanmlanr. Bu nedenle, karakter snama ilevleri arlmadan nce kaynak koda
ctype.h dosyas mutlaka eklenmelidir. Karakter snama ilevleri, ASCII karakter
repertuarnn ilk yars iin geerlidir. Yani Trke karakterler iin kullanlmas durumunda

112/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

geri dn deerleri gvenilir deildir. Karakter snama ilevlerinin Trkemize zel , ,


, , , , , , I, , , , karakterleri iin doru olarak altrlmas, yerelletirme
(localization) ile ilgili bir konudur. Bu konuya daha sonraki blmlerde deinilecek.
Aada, standart karakter snama ilevlerini ieren bir tablo veriliyor:
lev
isalpha
isupper
islower
isdigit
isxdigit

isalnum
isspace
ispunct
isprint
isgraph
iscntrl

Geri Dn Deeri
Alfabetik karakterse doru, deilse yanl.
Byk harf ise doru, deilse yanl.
Kk harf ise doru, deilse yanl.
Saysal bir karakterse doru, deilse yanl.
Onaltlk say sistemi basamak simgelerinden birini gsteren bir karakterse,
yani 0123456789ABCDEFabcdef karakterlerinden biri ise doru, deilse
yanl.
Alfabetik ya da saysal bir karakterse doru, deilse yanl.
Boluk karakterlerinden biri ise (space, carriage return, new line, vertical
tab, form feed) doru, deilse yanl.
Noktalama karakterlerinden biriyse, yani kontrol karakterleri, alfanmerik
karakterler ve boluk karakterlerinin dndaki karakterlerden ise doru,
deilse yanl.
Ekranda grlebilen yani print edilebilen bir karakterse (space karakteri
dahil) doru, deilse yanl.
Ekranda grlebilen bir karakterse (space karakteri dahil deil) doru,
deilse yanl.
Kontrol karakteri ya da silme karakteri ise (ASCII setinin ilk 32 karakter ya
da 127 numaral karakter) doru, deilse yanl.

Bu ilevlerden bazlarn kendimiz yazmaya alalm:

islower levi

islower, kendisine kod numaras gnderilen karakterin, kk harf karakteri olup


olmadn snayan, standart bir ilevdir. Kod numarasn ald karakter kk harf ise
ilev, sfr d bir deere, yani mantksal "doru" deerine geri dner. Kk harf deil
ise ilevin geri dn deeri sfr deeridir. Bu ilev aadaki biimde yazlabilir:
#include <stdio.h>
int islower (int ch)
{
return ch >= 'a' && ch <= 'z';
}
int main()
{
char ch;
printf("bir karakter girin: ");
ch = getchar();
if (islower(ch))
printf("kk harf\n");
else
printf("kk harf deil\n");
return 0;
}
Yukarda yazlan islower ilevinde nce parametre deikeninin kk harf olup olmad
snanyor:

113/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

ch >= 'a' && ch <= 'z';


Kk harflerin ardk olarak yerletirildii bir karakter kodunda, yukardaki ifadenin
deeri, ancak ch deikeninin deerinin, bir kk harfin sra numaras olmas
durumunda dorudur.

isalpha levi

isalpha da standart bir ilevdir. Parametresine kod numaras aktarlan karakter alfabetik
karakterse, yani byk ya da kk harf ise ilev sfr d bir deere, alfabetik bir
karakter deilse sfr deerine geri dner.
int isalpha (int ch)
{
return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
}

isdigit levi

isdigit, standart bir ilevdir. Parametresine kod numaras aktarlan karakter bir rakam
karakteri ise, ilev sfrdan farkl deer ile, rakam karakteri deilse sfr deeri ile geri
dner:
int isdigit (int ch)
{
return (ch >= '0' && ch <= '9');
}

isalnum levi

isalnum da standart bir ilevdir. Parametresine kod numaras aktarlan karakter alfabetik
karakter ya da bir rakam karakteri ise sfr d deere, aksi halde sfr deerine dner.
Aada bu ilev iki ayr biimde yazlyor:

#include <ctype.h>
int isalnum1(int ch)
{
return ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z'
|| ch >= '0' && ch <= '9';
}
int isalnum2(int ch)
{
return isalpha(ch) || isdigit(ch);
}

isxdigit levi

isxdigit, bir karakterin, onaltlk say sistemine ait bir basamak simge olup olmadn
snayan standart bir ilevdir. Eer kod numarasn ald karakter
0123456789ABCDEFabcdef karakterlerinden biri ise ilev sfrdan farkl deere, bu
karakterlerden biri deil ise sfr deerine geri dner.
int isxdigit (int ch)
{
return ch >= '0' && ch <= '9' || ch >= 'A' && ch <= 'F'
|| ch >= 'a' && ch <= 'f';
}

114/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Standart Karakter Dnm levleri

Kk harften byk harfe ya da byk harften kk harfe dnm yapmak, sk


gereken ilemlerdendir. Standart toupper ve tolower ilevleri bu amala kullanlr.

tolower levi

tolower standart bir C ilevidir. Parametresine kod numaras aktarlan karakter byk
harf ise, onun kk harf karlnn kod numarasyla geri dner. tolower ilevine byk
harf olmayan bir karakterin kod numaras aktarlrsa, ilev ayn deeri geri dndrr.
Aada bu ilev tanmlanyor:
#include <stdio.h>
int tolower (int ch)
{
if (ch >= 'A' && ch <= 'Z')
return ch - 'A' + 'a';
return ch;
}
int main()
{
char ch;
printf("bir karakter girin :");
ch = getchar();
printf("%c\n", tolower(ch));
}

return 0;

toupper levi

toupper, standart bir C ilevidir. Parametresine sra numaras aktarlan karakter, eer
kk harf ise, onun byk harf karlnn sra numarasyla geri dner. toupper ilevine
kk harf olmayan bir karakterin sra numaras aktarlrsa, ilev ayn deeri geri
dndrr. lev aada tanmlanyor:
int toupper(int ch)
{
if (ch >= 'a' && ch <= 'z')
return ch - 'a' + 'A';
return ch;
}

if Deyimini kullanan rnek Programlar

Aada iki saydan daha byk olanna geri dnen get_max2 ve saydan en byne
geri dnen getmax3 ilevi yazlyor:
int get_max2(int a, int b)
{
if (a > b)
return a;
return b;
}

115/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

int get_max3(int a, int b, int c)


{
int max = a;
if (b >
max
if (c >
max
}

max)
= b;
max)
= c;

return max;

#include <stdio.h>
int main()
{
int x, y, z;
printf("iki sayi girin : ");
scanf("%d%d", &x, &y);
printf("%d ve %d sayilarindan buyugu = %d\n", x, y, get_max2(x, y));
printf("uc sayi girin : ");
scanf("%d%d%d", &x, &y, &z);
printf("%d %d ve %d sayilarindan en buyugu = %d\n",x, y, z,
get_max3(x, y, z));
return 0;
}
Aadaki programda get_hex_char isimli bir ilev tanmlanyor. lev, kendisine
gnderilen 0 ile 15 arasndaki bir tamsaynn onaltlk say sistemindeki simgesi olan
karakterin sra numaras ile geri dnyor.
#include <stdio.h>
int get_hex_char(int number)
{
if (number >= 0 && number <= 9)
return ('0' + number);
if (number >= 10 && number <= 15)
return ('A' + number - 10);
return -1;
}
int main()
{
int number;
printf("0 ile 15 arasinda bir sayi girin : ");
scanf("%d", &number);
printf("%d = %c\n", number, get_hex_char(number));
return 0;
}
Aadaki programda get_hex_val isimli bir ilev tanmlanyor. lev, kendisine kod
numaras gnderilen, onaltlk say sisteminde bir basamak gsteren simgenin, onluk say

116/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

sistemindeki deerine geri dnyor. leve gnderilen karakter, onaltlk say sistemine
ilikin bir karakter deilse, -1 deeri dndrlyor.
#include <stdio.h>
#include <ctype.h>
int get_hex_val(int ch)
{
ch = toupper(ch);
if (isdigit(ch))
return ch - '0';
if (ch >= 'A' && ch <= 'F')
return ch - 'A' + 10;
return -1;
}
int main()
{
char hex;
printf("hex digit gsteren bir karakter girin: ");
hex = getchar();
printf("%c = %d\n", hex, get_hex_val(hex));
return 0;
}
Aadaki programda change_case isimli bir ilev tanmlanyor. change_case ilevi,
kendisine gnderilen karakter kk harf ise, bu karakteri byk harfe dntryor,
byk harf ise karakteri kk harfe dntryor. Eer harf karakteri deilse ilev,
karakterin kendi deeriyle geri dnyor.
#include <stdio.h>
#include <ctype.h>
int change_case(int ch)
{
if (isupper(ch))
return tolower(ch);
}

return toupper(ch);

int main()
{
int c;
printf("bir karakter girin : ");
c = getchar();
c = change_case(c);
putchar(c);
}

return 0;

Aadaki C programnda katsaylar klavyeden alnan ikinci dereceden bir denklem


zlyor:

117/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
#include <math.h>
int main()
{
double a, b, c;
double delta;
printf("denklemin katsayilarini girin\n");
printf("a = ");
scanf("%lf", &a);
printf("b = ");
scanf("%lf", &b);
printf("c = ");
scanf("%lf", &c);
delta = b * b - 4 * a * c;
if (delta < 0)
printf("denkleminizin gercek koku yok\n");
else if (delta == 0) {
printf("denkleminizin tek gercek koku var\n");
printf("kok = %lf\n", -b / (2 * a));
}
else {
double kokdelta = sqrt(delta);
printf("denkleminizin 2 gercek koku var\n");
printf("kok 1 = %lf\n", (-b + kokdelta) / (2 * a));
printf("kok 2 = %lf\n", (-b - kokdelta) / (2 * a));
}
}

return 0;

118/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

LEV BLDRMLER
Derleme ilemi, derleyici tarafndan kaynak kod iinde yukardan aaya doru yaplr.
Derleme aamasnda derleyici, bir ilev ars ile karlatnda, arlan ilevin geri
dn deerinin trn bilmek zorundadr. Bir ilevin geri dn deerinin tr, geri
dn deerinin hangi CPU yazmacndan (registers) alnacan belirler. Programn doru
almas iin derleme zamannda bu bilginin elde edilmesi zorunludur.
Eer arlan ilevin tanm, aran ilevden daha nce yer alyorsa, derleyici derleme
ilemi srasnda ilev ar ifadesine gelmeden nce, arlan ilevin geri dn deeri
tr hakknda zaten bilgi sahibi olur. nk derleme ilemi yukardan aa doru yaplr.
Aadaki rnei inceleyin:
#include <stdio.h>
double get_val(double x, double y)
{
return x * y / (x + y);
}
int main()
{
double d;
d = get_val(4.5, 7.3);
printf("d = %lf\n", d);
}

return 0;

Yukardaki rnekte get_val ilevi, kendisini aran main ilevinden daha nce
tanmlanyor. ar ifadesine gelmeden nce derleyici, get_val ilevinin geri dn deeri
trn zaten bilir.
arlan ilevin tanm aran ilevden daha sonra yaplrsa, derleyici ilev ar ifadesine
geldiinde, arlan ilevin geri dn deerinin trn bilemez. Bu sorunlu bir
durumdur:
#include <stdio.h>
int main()
{
double d;
//ilevin geri dn deerininin tr bilinmiyor.
d = get_val(4.5, 7.3);
printf("d = %lf\n", d);
return 0;
}
double get_val(double x, double y)
{
return x * y / (x + y);
}
Yukarda get_val ilevi, main ilevi iinde arlyor. Fakat get_val ilevinin tanm,
kaynak kod iinde main ilevinden daha sonra yer alyor. Derleyici, derleme zamannda
get_val ilevinin ars ile karlatnda, bu ilevin geri dn deerinin trn bilmez.

119/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

C derleyicisi bir ilev ar ifadesi ile karlatnda, ilevin geri dn deeri tr


hakknda henz bilgi edinememise, sz konusu ilevin geri dn deerinin int trden
olduunu varsayar.
Yukardaki rnekte derleyici, get_val ilevinin geri dn deerinin int trden olduunu
varsayar, buna gre kod retir. Daha sonra derleme ak ilevin tanmna geldiinde, bu
kez ilevin geri dn deerinin double trnden olduu grlr. Hedef kod oluumunu
engelleyen bu elikili durumu derleyiciler bir hata iletisi ile bildirir.
[C++ dilinde eer arlan ilev aran ilevden daha nce tanmlanmamsa, ilevin geri dn deeri int
trden kabul edilmez. Bu durumda ilev bildiriminin yaplmas zorunludur. Bu bildirimin yaplmamas
durumunda derleme zamannda hata oluur.]
arlan ilevi, aran ilevin stnde tanmlamak her zaman mmkn deildir. Byk
bir kaynak dosyada onlarca ilev tanmlanabilir. Tanmlanan her ilevin birbirini armas
sz konusu olabilir. Bu durumda arlacak ilevin aran ilevden nce tanmlanmas
ok zor olur. Kald ki, C dilinde iki ilev birbirini de arabilir. Bu, zyinelemeli (recursive)
bir ar dzeneine karlk gelir. Bu tr bir ilev tasarmnda, artk arlan ilevin daha
nce tanmlanmas mmkn olamaz.
double func1()
{
/***/
func2();
/***/
}
double func2()
{
/***/
func1();
/***/
}
Yukardaki ilev tanmlamalarndan hangisi daha yukar yerletirilirse yerletirilsin, yine
de elikili bir durum sz konusu olur.
Dier taraftan, arlan ilevlerin tanmlar ou zaman ayn kaynak dosya iinde yer
almaz. Bu durumda derleyicinin arlan ilev hakknda bilgi almas nasl gerekleir?

lev Bildirimi Nedir

lev bildirimi, derleyiciye bir ilev hakknda bilgi veren bir deyimdir. Derleyici, ilev
arsna ilikin kodu buradan ald bilgiye gre retir. Ayrca derleyici, ald bu bilgiyle,
baz kontroller de yapabilir. Yapt kontroller sonucunda hata ya da uyar iletileri
reterek olas yanllklar engeller.

lev Bildirimlerinin Genel Biimi

Bir ilev bildiriminin genel biimi aadaki gibidir:


[geri dn deeri tr] <ilev ismi> ([tr1], [tr2].....);
rnein get_val ilevi iin bildirim aadaki biimde yaplabilir:
double get_val(double, double);
Derleyici byle bir bildirimden aadaki bilgileri elde eder:
1. get_val ilevin geri dn deeri double trdendir. Bu bilgiden sonra artk derleyici bu
ilevin arlmas durumunda geri dn deerini int trden varsaymaz, double trden bir
geri dn deeri elde edilmesine gre bir kod retir.
120/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

2. get_val ilevinin iki parametre deikeni vardr. Bu bilgilendirmeden sonra artk


derleyici bu ilevin doru sayda argman ile arlp arlmadn sorgulama ansna
sahip olur. Eer ilevin yanl sayda argman ile arldn grrse, durumu bir hata
iletisi ile bildirir.
3. get_val ilevinin parametre deikenleri double trdendir. Bu bilgiden sonra derleyici
ileve baka trden argmanlar gnderilmesi durumunda, argmanlar zerinde otomatik
tr dnm uygular. Bu konu "otomatik tr dnm" isimli blmde ele alnacak.
Aada rnek bildirimler veriliyor:
int multiply (int, int);
double power (double, double);
void clrscr(void);
Tpk ilev tanmlamalarnda olduu gibi, ilev bildirimlerinde de ilevin geri dn deeri
belirtilmemise, derleyici bildirimin int trden bir geri dn deeri iin yapldn kabul
eder:
func(double);
bildirimi ile
int func(double);
bildirimi tamamen edeerdir. Ancak okunabilirlik asndan int anahtar szcnn
aka yazlmas daha iyidir.
[C++ dilinde geri dn deerinin trnn yazlmas zorunludur.]
Eer bildirilen ilev, geri dn deeri retmiyorsa, void anahtar szc kullanlmaldr:
void func(double);
lev bildirimleri ile, yalnzca derleyiciye bilgi verilir. Bu bir tanmlama (definition) ilemi
deildir. Dolaysyla yaplan bildirim sonucunda derleyici programn alma zamanna
ynelik olarak bellekte bir yer ayrmaz.

Bildirimde Parametre Ayracnn inin Bo Braklmas


C'nin standartlatrma sreci ncesinde ilev bildirimlerinde,parametre ayracnn ii bo
braklyordu. Bildirimde, ilevin parametre deikenlerinin trleri ve says hakknda bir
bilgi verilmiyordu. Bildirimin tek amac, bir ilevin geri dn deerinin tr hakknda
bilgi vermekti. Dolaysyla aadaki gibi bir bildirim
double func();
func ilevin parametre deikenine sahip olmad anlamna gelmiyordu. Standartlatrma
sreci iinde ilev bildirimlerine yaplan eklemeyle, ilevlerin parametre deikenlerinin
says ve trleri hakknda da bilgi verilmesi olana verildi. Ancak bu durumda da ortaya
yle bir sorun kt. Eski kurallara gre yazlan bir kod yeni kurallara gre derlendiinde
double func();
gibi bir bildirim, ilevin parametre deikenine sahip olmad biiminde yorumlanrsa,
bildirilen ilevin rnein
func(5)

121/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

biiminde arlmas durumunda bir szdizim hatas ortaya kard. Gemie doru
uyumluluu salamak iin yle bir karar alnd. Eer ilevin parametre deikeni yoksa
bildirimde parametre ayracnn iine void anahtar szc yazlmaldr. Aadaki
bildirimleri inceleyin:
double foo();
double func(void);
Standartlara gre foo ilevinin bildiriminden derleyici, foo ilevinin parametre
deikenleri hakknda bir bilginin verilmedii sonucunu karr ve ilev arsyla
karlatnda ileve gnderilen argmanlarn saysna ilikin bir kontrol yapmaz. Yani
byle bildirilen bir ilev, kurallara uygun bir ekilde istenen sayda bir argmanla
arlabilir.
func ilevinin bildiriminden derleyici, func ilevin parametre deikenine sahip olmad
sonucunu karr ve ilev arsyla karlatnda, ileve bir ya da daha fazla sayda
argman gnderildiini grrse, bu durumu derleme zaman hatas olarak belirler.
[C++ dilinde ise her iki bildirim de edeerdir. Yani ilev bildiriminde parametre ayracnn iinin bo
braklmasyla buraya void anahtar szcnn yazlmas arasnda bir fark yoktur]

Bildirimlerde Parametre Deikenleri in sim yazlmas

lev bildirimlerinde, parametre deikenlerinin trlerinden sonra isimleri de yazlabilir.


Bildirimlerde yer alan parametre deikenleri isimlerinin bilinirlik alanlar, yalnzca bildirim
parametre ayrac ile snrldr. Standartlar bu durumu, ayr bir bilinirlik alan kural ile
belirlemitir. lev bildirim ayrac iinde kullanlan isimler, yalnzca bu ayra iinde bilinir.
Bu ayracn dna kldnda bu isimler bilinmez. Bu bilinirlik alan kuralna "lev
Bildirimi Bilinirlik Alan Kural" (function prototype scope) denir.
Buraya yazlan parametre isimleri, yalnzca okunabilirlik asndan faydaldr. Buradaki
parametre isimlerinin, ilevin tanmnda kullanlacak parametre isimleriyle ayn olmas
gibi bir zorunluluk yoktur.
Yukardaki bildirimleri parametre deikenlerine isim vererek yeniden yazalm:
float calculate(float a, float b);
int multiply(int number1, int number2);
double pow(double base, double exp);
levlerin tanmlarn grmeden yalnzca ilevlerin bildirimlerini okuyanlar, bildirimlerde
kullanlan parametre deikeni isimlerinden, bu deikenlerin ilev arlarndan hangi
bilgileri bekledikleri konusunda fikir sahibi olurlar.

lev Bildirimlerinin Yerleri

Bir ilevin bildirimi, programn herhangi bir yerinde yaplabilir. Bildirimler global dzeyde
yaplmsa, yani tm bloklarn dnda yaplmsa, bildirildikleri yerden dosya sonuna
kadar olan alan iinde geerliliklerini srdrr. Sz konusu ilev arlmadan, ilevin
bildirimi yaplm olmaldr.
Ancak uygulamalarda ok az rastlanmasna karlk, ilev bildirimleri yerel dzeyde de
yaplabilir. Bu durumda bildirim ile, yalnzca bildirimin yaplm olduu bloa bilgi verilmi
olur. Baka bir deyile ilev bildirimi de, deiken tanmlamalar gibi, bilinirlik alan
kuralna uyar.
Genel olarak ilev bildirimleri programn en yukarsnda ya da programcnn tanmlad
balk dosyalarnn birinin iinde yaplr. Balk dosyalar (header files), ileride ayrntl
olarak ele alnacak.

Standart C levlerinin Bildirimleri

Standart C ilevlerinin bildirimleri, standart balk dosyalar iine yerletirilmitir.


Programc, uygulamalarda standart bir C ilevinin bildirimini kendi yazmaz, bu bildiriminin
bulunduu balk dosyasn #include nilemci komutuyla kendi kaynak koduna ekler.

122/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

lev Bildiriminin Yaplmamas

arlan bir ilevin kaynak kodunun, ayn kaynak dosya iinde yer almas gibi bir
zorunluluk yoktur. Derleyici, bir ilev ars ile karlatnda, arlan ilevin kaynak
kodunu aramaz. rettii hedef dosya (object file) iine, balayc iin, ilgili ilevin
arldn belirten bir bilgi yazar. arlan ilevin derlenmi kodunu bulmak ve hedef
dosyalar uygun bir biimde birletirmek, balayc programn grevidir.
arlan bir ilevin tanmnn ayn kaynak dosyada olmadn dnelim. Bu durumda
arlan ilevin bildirimi yaplmamsa ne olur? C dilinde bu durum bir szdizim hatas
deildir.
C++ dilinde bu durum dorudan szdizim hatasdr. Derleyici, bir ilevin arlmasndan nce, sz konusu
ilevin tanmn ya da bildirimini mutlaka grmek zorundadr.
C dilinde derleyici, bildirimini grmedii bir ilevin geri dn deerini int trden kabul
ederek hedef dosyay retir. Eer kaynak kod iinde ilevin geri dn deeri
kullanlmamsa, ya da arlan ilevin geri dn deeri gerekten int trden ise bir
sorun kmaz. Ancak ilevin geri dn deeri kullanlmsa ve geri dn deeri int
trden deilse, bir alma zaman hatas sz konusudur. Aadaki rnei derleyicinizde
derleyerek altrn:
#include <stdio.h>
int main()
{
double d;
d = sqrt(9.);
printf("d = %lf\n", d);
}

return 0;

Yukardaki programn derlenmesi srasnda bir hata olumaz. Ancak derleyici, arlan
sqrt ilevinin geri dn deerinin int trden olduunu varsayarak kod retir. Oysa,
derlenmi sqrt ilevinin geri dn deeri double trdendir. alma zaman srasnda,
ilevin geri dndrd double trden deer yerine, derleyicinin rettii kod sonucunda,
int trden bir deer ekilmeye allr. Bu, programn alma zamanna ynelik bir
hatadr.
imdi de main ilevinden nce aadaki bildirimi ekleyerek program yeniden derleyerek
altrn:
double sqrt(double val);
Standart C ilevlerinin bildirimleri, sonu .h uzantl olan balk (header) dosyalar
iindedir. #include nilemci komutuyla ilgili balk dosyasnn kaynak koda eklenmesiyle,
aslnda standart C ilevlerinin de bildirimi yaplm olur. Zira nilemci programn kts
olan kaynak program, artk derleyiciye verildiinde, eklenmi bu dosyada ilevin bildirimi
de bulunur. phesiz, ilgili balk dosyasn kaynak koda eklemek yerine, standart C
ilevlerinin bildirimleri programc tarafndan da yaplabilir. Bu durumda da bir yanllk sz
konusu olmaz. Yukardaki rnekte arlan sqrt ilevinin bildirimi iki ekilde kaynak koda
eklenebilir:
i. lev bildiriminin bulunduu balk dosyasnn, bir nilemci komutuyla kaynak koda
eklenmesiyle:
#include <math.h>
ii) levin bildirimi dorudan yazlabilir:

123/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

double sqrt(double val);


Ancak tercih edilecek yntem balk dosyasn kaynak koda eklemek olmaldr. nk
programc tarafndan ilevin bildirimi yanl yazlabilir.
Balk dosyalarnn kaynak koda eklenmesinin nedeni yalnzca ilev bildirimi deildir.
Balk dosyalarnda daha baka bildirimler de vardr: Makrolar, simgesel deimezler, tr
ismi bildirimleri, yap bildirimleri vs.

lev Bildirimi le Argman-Parametre Uyumu Sorgulamas

lev bildirimlerin ana amac, yukarda da belirtildii gibi, derleyiciye ilevin geri dn
deeri tr hakknda bilgi vermektir. Ancak ilev bildirimlerinde ilev parametrelerinin
trleri belirtilmise, derleyici prototip bildirimindeki parametre deikeni saysn ilev
ar ifadesindeki ileve gnderilen argman says ile karlatrr. rnein:
float process(float, float);
biiminde bir bildirim yazldnda eer process ilevi eksik ya da fazla argman ile
arlrsa derleme zamannda hata oluur.
x = process(5.8);
y = process(4.6, 7.9, 8.0)

/* Geersiz! Eksik argman ile ar*/


/* Geersiz! Fazla argman ile ar*/

Bildirim Szdizimine likin Ayrntlar

Ayn trden geri dn deerine sahip ilevlerin bildirimi, virgllerle ayrlarak yazlabilir,
ama byle bir bildirim biimi, programclar tarafndan genel olarak pek tercih edilen bir
durum deildir.
double func1(int), func2(int, int), func3(float);
Yukardaki bildirim geerlidir. Byle bir bildirimle, derleyiciye func1, func2, func3
ilevlerinin hepsinin geri dn deerinin double trden olduu bilgisi verilir.
lev bildirimleri, deiken tanmlamalaryla da birletirilebilir. Bu da okunabilirlik
asndan tercih edilen bir durum deildir.
long func1(int), long func2(void), x, y;
Yukardaki bildirim deyimi ile func1 ve func2 ilevlerinin bildirimi yaplrken, x ve y
deikenleri tanmlanyor.
Bir ilevin bildiriminin yaplm olmas, o ilevin tanmlamasn ya da arlmasn zorunlu
klmaz. Bildirimi yaplan bir ilevi tanmlamamak hata oluturmaz.
Bir ilevin bildirimi birden fazla kez yaplabilir. Bu durum, bir derleme zaman hatas
oluturmaz. Ama yaplan bildirimler birbirleriyle elimemelidir.
Kaynak dosya iinde ayn ileve ilikin bildirimlerin farkl yerlerde, aadaki biimlerde
yapldn dnelim:
int func (int, int);
func (int, int);
int func(int x, int y);
func(int number1, int number2);
Yukardaki bildirimlerinin hibirinde bir eliki sz konusu deildir. lev parametre
deikenlerinin isimleri iin daha sonraki bildirimlerde farkl isimler kullanlmas bir eliki
yaratmaz. nk bu isimlerin bilinirlik alan (scope), yalnzca bildirimin yapld ayracn
iidir. Ancak aadaki farkl bildirimler geersizdir.

124/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

double func(int x, double y);


double func(int x, float y); /* Geersiz! */
long sample(double x);
sample (double x);
/* Geersiz! */

lev Bildirimlerinin Yerleri

C ve C++ dillerinde bir proje, ou zaman birden fazla kaynak dosyadan, yani modlden
oluur. Kaynak dosyalarn ounda, baka kaynak dosyalar iinde tanmlanan ilevler
arlr. Yani ou zaman kaynak dosyalar arasnda bir hizmet alma verme ilikisi vardr.
Baka modllere hizmet verecek bir modl, iki ayr dosya eklinde yazlr. Dosyalardan
biri kodlama (implementation) dosyasdr. Bu dosyann uzants .c dir. Bu dosya
tarafndan dier modllere sunulan hizmetlere ilikin bildirimler, .h uzantl baka bir
dosyaya yerletirilir. Bu dosyaya balk dosyas (header file) denir. Dier modllere
hizmet verecek ilevlerin bildirimleri, balk dosyas iine yerletirilmelidir.
Hizmet alan kodlama dosyas, hizmet veren modln balk dosyasnn ieriini, kendi
dosyasna #include nilemci komutuyla ekler. Bylece bildirim yaplm olur. Bu durum
"nilemci komutlar" konusunda yeniden ele alnacak.

125/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

126/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

TR DNMLER
Bilgisayarlarn aritmetik ilemleri gerekletirmesinde bir takm kstlamalar sz
konusudur. Bilgisayarlarn aritmetik bir ilemi gerekletirmesi iin genellikle ileme
sokulan terimlerin uzunluklarnn ayn olmas, yani bit saylarnn ayn olmas ve bellekte
ayn formatta ifade edilmeleri gerekir. rnein ilemci 16 bit uzunluunda iki tam sayy
dorudan toplayabilir ama 16 bit uzunluunda bir tam say ile 32 bit uzunluundaki bir
gerek sayy dorudan toplayamaz.
C programlama dili, deiik trlerin ayn ifade iinde bulunmalarna izin verir. Yani tek bir
ifadede bir tamsay trnden deiken, float trden bir deimez ya da char trden bir
deiken birlikte yer alabilir. Bu durumda C derleyicisi, bunlar herhangi bir ileme
sokmadan nce, bilgisayar donanmnn ifadeyi deerlendirebilmesi iin uygun tr
dnmlerini yapar.
rnein 16 bitlik int trden bir deerle 64 bitlik double trden bir deer toplandnda,
nce 16 bitlik int trden deer, 64 bit uzunluunda double trden bir deer olarak ifade
edilir, daha sonra toplama ilemi gerekletirilir. Yine 16 bitlik bir int trden bir deerle
64 bitlik bir double trden bir deer arpldnda derleyici, nce int trden deeri 64
bitlik double trden bir deere dntrr. Bu tr dnm daha karmaktr, nk int
ve double trden deerler bellekte farkl biimlerde tutulur.
Bu tr dnmler, programcnn bir kod yazmasna gerek duyulmakszn otomatik olarak
gerekletirilir. Byle dnmlere, otomatik tr dnmleri (implicit type conversions)
diyeceiz. Dier taraftan C dili, programcya herhangi bir ifadeyi, bir ile kullanarak
baka bir trden ele alma olana da verir. Programc tarafndan yaplan byle tr
dnmlerine bilinli tr dnmleri (explicit type conversions/type casts) diyeceiz.
nce otomatik tr dnmlerini inceleyelim. Otomatik tr dnmleri ne yazk ki
karmak yapdadr ve iyi renilmemesi durumunda programlarda hatalar kanlmazdr.
C'de 11 ayr doal veri tr olduunu biliyorsunuz. Herhangi bir hataya neden olmamak
iin bunlarn her trl ikili bileimi iin nasl bir otomatik tr dnm yaplacan ok
iyi bilmek gerekir.

Hangi Durumlarda Tr Dnm Yaplr

Aada belirtilen drt durumda mutlaka otomatik bir tr dnm yaplr:


1. Aritmetik ya da mantksal bir ifadenin terimleri ayn trden deilse:
Byle yaplan tr dnmlerine ilem ncesi tr dnmleri diyeceiz.
2. Atama ileci kullanldnda atama ilecinin sa tarafndaki ifadenin tr ile sol
tarafndaki ifadenin tr ayn deilse:
double toplam;
long sayi1, sayi2;
/***/
toplam = sayi1 + sayi2;
Bu durumda yaplan tr dnmlerine atama tr dnmleri diyeceiz.
3. Bir ilev arsnda ileve gnderilen bir argmann tr ile ilevin ilgili parametre
deikeninin tr ayn deilse:
double sqrt (double val);
void func()
{
int number;
double result = sqrt(number);
/***/
}

127/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yukardaki rnekte arlan sqrt ilevine gnderilen argman olan number deikeninin
tr, arlan ilevin parametre deikeninin trnden farkldr. Bu durumda bir tr
dntrme ilemi yaplr.
4. Bir return ifadesinin tr ile ilgili ilevin geri dn deerinin tr ayn deilse:
double func(int val)
{
/****/
return val;
}
Yukarda tanmlanan func isimli ilevin iinde yer alan return ifadesinin tr int iken,
ilevin bildirilen geri dn deeri tr double trdr. Bu durumda da, derleyici
tarafndan bir otomatik tr dntrme ilemi yaplr.
3. ve 4. maddeler de bir atama ilemi olarak dnlebilir. lev ar ifadesindeki
argmanlar, parametre deikenlerine kopyalanarak, geirilir. Yani rtl bir atama
ilemi sz konusudur. Yine return ifadeleri de aslnda ilevlerin geri dn deerlerini
tutacak geici nesnelere kopyalanrlar.

lem ncesi Aritmetik Tr Dnmleri

lem ncesi otomatik tr dnmleri, iki terimli ilelerin bulunduu ifadelerde


terimlerin trlerinin farkl olmas durumunda uygulanr. Otomatik tr dnm
sonucunda, farkl iki tr olmas durumu ortadan kaldrlarak terimlerin her ikisinin de
trlerinin ayn olmas salanr. rnein
int i;
double d, result;
result = i + d;
Bu ifadenin sa tarafnda yer alan i ve d deikenlerinin trleri farkldr. Terimlerden biri
int, dieri double trdendir. Bu durumda derleyici, terimlerden birini geici bir blgede
dierinin trnden ifade edecek bir kod retir. Dolaysyla ilem, ortak olan trde yaplr.
Peki int trnden olan terim mi double trnde ifade edilir, yoksa double trnden olan
terim mi int trnde ifade edilir? Derleyici byle bir dnm bilgi kayb olmayacak
biimde yapmaya alr.
Bu durumda bilgi kaybn engellemek iin genel olarak daha kk trden olan terim,
daha byk trde olan terimin trnde ifade edilir.
Kurallar ayrntl olarak renmek iin oluabilecek durumlar iki ana grup altnda
inceleyelim:
1. Terimlerden biri gerek say trlerinden birine ait ise:
Terimlerden birinin long double trnden, dierinin farkl bir trden olmas durumunda
dier terim long double trnde ifade edilir ve ilem long double trnde yaplr.
Terimlerden birinin double trnden, dierinin farkl bir trden olmas durumunda dier
terim double trnde ifade edilir ve ilem double trnde yaplr.
Terimlerden birinin float trnden, dierinin farkl bir trden olmas durumunda dier
terim float trnde ifade edilir ve ilem float trnde yaplr.
2. Terimlerden hibiri gerek say trlerinden deilse:
Eer ifade iindeki terimlerden herhangi biri signed char, unsigned char, signed short int
ya da unsigned short int trden ise aadaki algoritma uygulanmadan nce bu trler int

128/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

trne dntrlr. Yaplan bu dnme "tam sayya ykseltme" (integral promotion)


denir.
Daha sonra aadaki kurallar uygulanr:
Terimlerden birinin unsigned long trnden, dierinin farkl bir trden olmas durumunda
dier terim unsigned long trnde ifade edilir ve ilem unsigned long trnde yaplr.
Terimlerden birinin signed long trnden, dierinin farkl bir trden olmas durumunda
dier terim signed long trnde ifade edilir ve ilem signed long trnde yaplr.
Terimlerden birinin unsigned int trnden, dierinin farkl bir trden olmas durumunda
dier terim unsigned int trnde ifade edilir ve ilem unsigned int trnde yaplr.
stisnalar:
Eer terimlerden biri signed long int dieri unsigned int trnden ise ve kullanlan
sistemde bu trlerin uzunluklar ayn ise (UNIX ve Win 32 sistemlerinde olduu gibi) her
iki terim de unsigned long int trne dntrlr.
Eer terimlerden biri signed int dieri unsigned short int trnden ise ve kullanlan
sistemde bu trlerin uzunluklar ayn ise (DOS iletim sisteminde olduu gibi) her iki
terim de unsigned int trne dntrlr.
aretli bir tamsay trnden iaretsiz tamsay trne dnm yaplmas durumunda
dikkatli olunmaldr:
#include <stdio.h>
int main()
{
int x = -2;
unsigned int y = 1;
if (y > x)
printf("dogru!\n");
else
printf("yanlis!\n");
}

return 0;

Yukardaki programn almasyla ekrana "yanl" yazs yazdrlr.


y > x
ifadesinde '>' ilecinin sol terimi unsigned int trnden iken sa terimi int trdendir. Bu
durumda yaplacak otomatik tr dntrme ilemi sonucunda int trden olan terim,
ilem ncesinde unsigned int trnde ifade edilir. -2 deeri unsigned int trnde ifade
edildiinde artk negatif bir deer olmayp byk bir pozitif say olur. rnein 2 byte' lk
int tr sz konusu olduunda bu deer 65534'tr. Dolaysyla y > x ifadesi yanl olarak
yorumlanr. nk otomatik tr dnmnden sonra y > x ifadesi artk yanltr.
lev ar ifadeleri de, ilelerle birlikte baka ifadeleri oluturuyorsa, otomatik tr
dnmlerine neden olabilir. Zira geri dn deerine sahip olan ilevler iin ileve
yaplan ar ifadesi, ilevin geri dn deerine karlk gelir. rnein:
int i = 5;
...
pow(2, 3) + i

129/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

ifadesinde pow ilevinin geri dn deeri double trden olduu iin, int trden olan i
deikeni de, ilemin yaplabilmesi iin geici bir blgede double trnde ifade edilerek
ileme sokulur.

Atama Tr Dnmleri
Bu tr dnmlerin ok basit bir kural vardr: Atama ncesinde, atama ilecinin sa
tarafndaki ifade, atama ilecinin sol tarafndaki nesnenin trnde ifade edilir:
Kk trlerin byk trlere dntrlmesinde bilgi kayb sz konusu deildir. rnein:
double leftx;
int righty = 5;
leftx = righty;
Yukardaki rnekte righty deikeninin tr int'tir. nce double tre otomatik dnm
yaplr, daha sonra double trnde ifade edilen righty deikeninin deeri leftx
deikenine atanr.
Aada 16 bitlik sistemler iin baz rnekler veriliyor:
TR
int
char
int
char

desimal
138
'd' (100)
-56
'\x95' (07)
unsigned int 45678
char
'0' (48)

hex
0x008A
0x64
0xFFC8
0x95

dntrlecek tr
long int
int
long int
int

hex
0x0000008A
0x0064
0xFFFFFFFC8
0xFF95

desimal
138L
100
-56L
-107

0xB26E
0x30

long int
long int

0X0000B26EL
0x00000030L

45678
30L

Negatif olan bir tamsay, kk trden byk tre dntrldnde saynn yksek
anlaml bitleri, negatifliin korunmas amacyla 1 biti ile beslenir.
Derleyici tarafndan yaplan atama tr dnmlerinde, atama ncesi, byk trn kk
tre dntrlmesi durumunda bilgi kayb sz konusu olabilir.
Aadaki basit kurallar verilebilir:
Eer atama ilecinin her iki taraf da tam say trlerinden ise (char, short, int, long),
atama ilecinin sa tarafnn daha byk bir trden olmas durumunda bilgi kayb olabilir.
Bilgi kayb ancak, atama ilecinin sa tarafndaki deerin, sol taraftaki trn snrlar
iinde olmamas durumunda sz konusu olur. Bilgi kayb, yksek anlaml byte'larn
kaybolmas eklinde ortaya kar. rnek:
long m = 0x12345678;
int y = m;
printf ("m = %x\n", m);
Yukardaki rnekte int trden olan y deikenine long trden bir deikenin deeri
atanmtr. Kodun 16 bitlik bir sistemde, rnein DOS altnda altn dnyoruz.
DOS altnda int tr iin say snrlar 32768 +32767 deerleridir. Bu saylar da, iki
byte'lk bir alan iin iaretli olarak yazlabilecek en byk ve en kk deerlerdir.
Onaltlk say sisteminde her bir basamak 4 bite ve her iki basamak 1 byte alana karlk
gelir. Dolaysyla 0x12345678 says 8 hex basamak, yani 4 byte uzunluunda bir saydr.
Oysa atamann yaplaca nesne int trdendir ve bu tr max. 4 hex basamak (2 byte)
uzunlukta olabilir. Bu durumda m deikenine ilikin deerin yksek anlaml 2 byte' yani
(4 hex basma) yitirilir. Atama ileminden sonra, printf ileviyle, y deikeninin deeri
5678 olarak yazdrlr.

130/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Atama ilecinin sa terimi, bir gerek say trnden ise(float, double, long double) ve sol
terimi tam say trnden ise nce gerek say deerinin ondalk ksm kaybedilir. Eer
gerek saydan elde edilen tamsay ksm, atamann yapld tamsay trnden ifade
edilemiyorsa, bu durum tanmsz davrantr (undefined behaviour). Bu durumun
olutuu kodlardan kesinlikle kanmak gerekir. Ama derleyicilerin hemen hepsi, bu
durumda aadaki ekilde tr dnm yapar:
Atama ilecinin sa terimi olan gerek say bir ondalk ksm ieriyorsa, nce ondalk ksm
kaybedilir. Ondalk ksm kaybedildikten sonra kalan tamsay deer, eer sol terimin
trnn snrlar iinde kalyorsa daha fazla bir bilgi kayb olmaz, fakat sol taraf trnn
snrlar alyorsa fazladan bir bilgi kayb daha olur ve bu kez yksek anlaml byte'lar
kaybedilir. rnek:
#include <stdio.h>
int main()
{
double y = 234.12;
int x;
x = y;
printf("x = %d\n", x); /* x deikenine 234 deeri atanr*/
y = 7689523345.347;
x = y;
/* Yanl */
printf("x = %d\n", x);
}

return 0;

imdi de aadaki program derleyerek altrn:


#include <stdio.h>
int main()
{
char ch;
ch = 135;
if (ch == 135)
printf("dogru!\n");
else
printf("yanl!\n");
}

return 0;

Program altrldnda ekrana neden "yanl" yazs yazdrlyor?


ch deikenine 135 deeri atanyor:
ch = 135;
Bu durumda yksek anlaml byte kaybedileceinden ch deikenine atanan deer
1000 0111
deeri olur.

131/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

ch == 135
karlatrma ileminde char trden olan ch deikeni, karlatrma ilemi ncesi signed
int trne ykseltilir. lem ncesi tamsayya ykseltme sonucu, yksek anlam byte'ler
1 bitleriyle beslenir. nk ch negatif bir deere sahiptir. Karlatrma ilemi ncesinde
ch'nin deeri
1111 1111 1000 0111
olur. Oysa karlatrma ilecinin sa terimi olan 135 deeri, int trden bir deimezdir.
Yani aslnda karlatrlan deerler aadaki gibi olur:
1111 1111 1000 0111
0000 0000 1000 0111
Karlatrma yanl olarak sonulanr.

Tamsayya Ykseltme

Daha nce de akland gibi tamsayya ykseltme (integral promotion), bir ifade iinde
bulunan char, unsigned char, short, unsigned short trlerinin, ifadenin derleyici
tarafndan deerlendirilmesinden nce, otomatik olarak int trne dntrlmeleri
anlamna gelir.
Peki dnm, signed int trne mi, unsigned int trne mi yaplr?
Genel kural udur: Tr dnmne urayacak terimin deeri int trnde ifade
edilebiliyorsa int, edilemiyorsa unsigned int trne dnm yaplr.
rnein unsigned short ve int trlerinin ayn uzunlukta olduu DOS iletim sisteminde
unsigned short tr, tamsayya ykseltilirken unsigned int trne dntrlr.
Eer tam sayya ykseltilecek deer, signed char, unsigned char ya da signed short
trlerinden ise, dnm signed int trne yaplr.
Bilgi kayb ile ilgili u hususu da gz ard etmemeliyiz. Baz durumlarda bilgi kayb tr
dnm yapld iin deil yaplmad iin oluur. Snr deer tamalar, bu duruma iyi
bir rnek olabilir.
rnek: (DOS altnda altmz dnelim)
long x = 1000 * 2000;
Yukardaki kod ilk bakta normal gibi grnyor. Zira arpma ileminin sonucu olan
2000000 deeri DOS altnda signed long tr say snrlar iinde kalr. Oysa bilgi kayb
atama ileminden nce gerekleir. 1000 ve 2000 int trden deimezlerdir, ileme
sokulduklarnda arpma ilecinin de rettii deer int trden olur. Bu durumda 2 byte
uzunlukta olan int tr, 2000000 deerini tutamayaca iin yksek anlaml byte
kaybedilir. 2000000 onaltlk say sisteminde 0x1E8480 olarak gsterilebilir. Yksek
anlaml byte kaybedilince ilem sonucu, 0x8480 olur. 0x8480 negatif bir saydr. nk
iaret biti 1'dir. kiye tmleyenini alrsak
0x8480
ikiye tmleyeni

1000 0100 1000 0000


0111 1011 1000 0000

(0x7B80 = 31616)

Grld gibi ilem sonucu retilecek deer 31616 dir. Bu durumda x deikeninin
tr long tr de olsa, atanacak deer 31616 olur.

lev arlarnda Tr Dnm

Daha nce sylendii gibi, bir ileve gnderilen argmanlarla, bu argmanlar tutacak
ilevin parametre deikenleri arasnda tr fark varsa otomatik tr dnm gerekleir

132/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

ve argmanlarn tr, parametre deikenlerinin trlerine dntrlr. Ancak bu tr


dnmnn gereklemesi iin, derleyicinin ilev ar ifadesine gelmeden nce ilevin
parametre deikenlerinin trleri hakknda bilgi sahibi olmas gerekir. Derleyici bu bilgiyi
iki ayr ekilde elde edebilir:
arlan ilev aran ilevden daha nce tanmlanmsa derleyici, ilevin
tanmlamasndan parametre deikenlerinin trn belirler.
levin bildirimi yaplmsa derleyici, parametre deikenlerinin tr hakknda nceden
bilgi sahibi olur. Aadaki rnei inceleyin:
#include <stdio.h>
double func(double x, double y)
{
/***/
}
int main()
{
int a, b;
/***/
func(a, b);
}

return 0;

Yukardaki rnekte main ilevi iinde arlan func ilevine argman olarak, int trden
olan a ve b deikenlerinin deerleri gnderiliyor. lev tanm ar ifadesinden nce yer
ald iin int trden olan a ve b deikenlerinin deerleri, double trne dntrlerek
func ilevinin parametre deikenleri olan x ve y deikenlerine aktarlr. func ilevinin
main ilevinden sonra tanmlanmas durumunda, otomatik tr dnmnn
yaplabilmesi iin, ilev bildirimi ile derleyiciye parametre deikenlerinin trleri hakknda
bilgi verilmesi gerekir.
#include <stdio.h>
double func(double x, double y);
int main()
{
int a, b;
/***/
func(a, b);
}

return 0;

double func(double x, double y)


{
/***/
}
Peki arlan ilev aran ilevden daha sonra tanmlanmsa ve ilev bildirimi
yaplmamsa -tabi bu durumda derleme zamannda hata olumamas iin ilevin int
trden bir geri dn deerine sahip olmas gerekir- tr dnm gerekleebilecek mi?
Bu durumda derleyici, ilevin parametre deikenlerinin trleri hakknda bilgi sahibi
olamayaca iin, ileve gnderilen argmanlara, varsaylan argman dnm denilen
ilemi uygular. Varsaylan argman dnm u ekilde olur:

133/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

char ya da short trnden olan argmanlar tamsayya ykseltilir (integral promotion).


float trnden olan argmanlar double trne dntrlr. Bunun dndaki trlerden
olan argmanlar iin tr dnm yaplmaz.

Tr Dntrme leci

Tr dntrme ileci (typecast operator) ile bir ifade bir ileme sokulmadan nce baka
bir trden ifade edilebilir. Tr dntrme ileci, nek konumunda bulunan tek terimli bir
iletir.
le, bir ayra ve ayra iine yazlan bir tr bilgisinden oluur:
(double)x
lecin rettii deer, terimi olan ifadenin ayra iindeki trden ifade edilmi deeridir.
Tr dntrme ileci de, dier tm tek terimli ileler gibi, ile ncelik tablosunun ikinci
ncelik seviyesinde bulunur.
Aadaki program derleyerek altrn:
#include <stdio.h>
int main()
{
int x = 10;
int y = 4;
double z;
z = (double)x / y;
printf("z = %lf\n", z);
return 0;
}
Yukardaki programda
z = (double)x / y
ifadesinde nce tr dntrme ileci deer retir. Tr dntrme ilecinin rettii
deer, x nesnesinin double trde ifade edilmi deeridir. Bu durumda blme ilecine sra
geldiinde blme ilecinin terimi double trden 10 deeri olur. Bu kez de otomatik tr
dnm ile blme ilecinin sa terimi double trne dntrlerek blme ilemi
double trnde yaplr. Bu durumda blme ileci 2.5 deerini retir.
phesiz ifade aadaki biimde yazlsayd yine bilgi kayb olumazd:
z = x /(double)y
Ancak ifade aadaki gibi yazlsayd:
z = (double) (x / y)
bu durumda tr dntrme ilecinin terimi (x / y) ifadesi olurdu. Bu da bilgi kaybn
engellemezdi.
Bir verinin istenerek kaybedilmesi durumunda okunabilirlik asndan, otomatik tr
dnm yerine, tr dntrme ileci ile bilinli bir dnm yaplmaldr.
int i;
double d;
/***/
i = d;

134/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

double trden olan d deikeninin deerinin int trden i deikenine atanmas gvenilir
bir davran gstermez. Atama sonunda, en iyi olaslkla i deikenine d nin deerinin
yalnzca tam say ksm atanr. Byle bir kodu okuyanlar bu atamann yanllkla yapld
izlenimini edinirler. Derleyicilerin ou da olas bilgi kaybn uyar iletisiyle bildirir. Bu
atamann bilinli bir ekilde yaplmas durumunda tr dntrme ileci kullanlmaldr:
int i;
double d;
/***/
i = (int)d;
Aadaki programda, klavyeden girilen bir gerek say tam sayya yuvarlanyor. Girilen
deerin ondalk ksm .5'ten daha bykse say yukarya, .5'ten daha kkse say
aaya yuvarlanyor:
#include <stdio.h>
int main()
{
double d;
int x;
printf("bir gercek sayi girin : ");
scanf("%lf", &d);
if (d > 0)
x = d + .5;
else
x = d - .5;
printf("x = %d\n", x);
}

return 0;

135/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

DNG DEYMLER
Bir program parasnn yinelemeli olarak altrlmasn salayan kontrol deyimlerine
"dng deyimi" (loop statement) denir. C dilinde 3 ayr dng deyimi vardr:
while dng deyimi
do while dng deyimi
for dng deyimi
Bunlardan en fazla kullanlan, for dng deyimidir. for dng deyimi, yalnzca C dilinin
deil, tm programlama dillerinin en gl dng yapsdr. while ya da do while dng
deyimleri olmasa da, bu dngler kullanlarak yazlan kodlar, for dngsyle yazlabilir.
Ancak okunabilirlik asndan while ve do while dnglerinin tercih edildii durumlar
vardr.

while Dng Deyimi

while dng deyiminin genel szdizimi aadaki gibidir:


while (ifade)
deyim;
while anahtar szcn izleyen ayra iindeki ifadeye kontrol ifadesi (control
expression) denir. while ayracn izleyen ilk deyime dng gvdesi (loop body) denir.
Dng gvdesini bir basit deyim, bo deyim, bileik deyim ya da bir kontrol deyimi
oluturabilir.
while dng deyiminin yrtlmesi syle olur: nce kontrol ifadesinin saysal deeri
hesaplanr. Bu ifade mantksal olarak deerlendirilir. fade 0 deerine sahipse, yanl
olarak yorumlanr. Bu durumda dng gvdesindeki deyim yrtlmez, programn ak
dng deyimini izleyen ilk deyimle srer. Kontrol ifadesi sfrdan farkl bir deere sahipse,
doru olarak yorumlanr bu durumda dng gvdesindeki deyim yrtlr.
Dng gvdesindeki deyimin yrtlmesinden sonra kontrol ifadesinin deeri yeniden
hesaplanr. Kontrol ifadesi sfrdan farkl bir deere sahip olduu srece dng
gvdesindeki deyim yrtlr. Dngden kontrol ifadesinin sfr deerine sahip olmasyla,
yani ifadenin yanl olarak yorumlanmasyla klr.
C dilinin while dngs, bir koul doru olduu srece bir ya da birden fazla iin
yaptrlmasn salayan bir dng deyimidir.
Aadaki rnei inceleyelin:
#include <stdio.h>
int main()
{
int i = 0;

while (i < 100) {


printf("%d ", i);
++i;
}
return 0;

main ilevinde yer alan while dngsn inceleyelim. Dng gvdesini bir bileik deyim
oluturuyor. i < 100 ifadesi doru olduu srece bu bileik deyim yrtlr. Yani printf
ilevi arlr, daha sonra i deikeninin deeri 1 artrlr. i deikeninin deeri 100
olduunda, kontrol ifadesi yanl olacandan dngden klr. Aadaki rnei
inceleyin:

137/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
int main ()
{
char ch = 'A';
while (ch <= 'Z')
putchar(ch++);
}

return 0;

Yukardaki main ileviyle ngiliz alfabesinin tm byk harf karakterleri srayla ekrana
yazdrlyor. ch isimli deikene nce 'A' deeri atandn gryorsunuz. Dng ch <=
'Z' ifadesi doru olduu srece dner. Dng gvdesini bu kez bir basit deyim
oluturuyor. Sonek konumundaki ++ ilecinin nesnenin kendi deerini rettiini
biliyorsunuz. Ancak ilecin yan etkisi nedeniyle ch deikeninin deeri 1 artrlyor. ch
deikeninin deeri 'Z' olduunda kontrol ifadesi halen dorudur. Ancak dngnn bir
sonraki turunda kontrol ifadesi yanl olduundan dngden klr.
while dng deyiminde dng gvdesindeki deyimin en az bir kez yaplmas gvence
altnda deildir. nce kontrol ifadesi ele alndndan, dngye ilk girite kontrol
ifadesinin yanl olmas durumunda, dng gvdesindeki deyim hi yrtlmez.

Kontrol fadeleri

Herhangi bir ifade while dngsnn kontrol ifadesi olabilir.


Kontrol ifadesi bir ilev ars ierebilir:
while (isupper(ch)) {
/***/
}
Yukardaki while dngs, isupper ilevi sfr d bir deere geri dnd srece, yani ch
byk harf karakteri olduu srece dner.
Aadaki while dngs ise, isupper ilevi 0 deerine geri dnd srece, yani ch
byk harf karakteri olmad srece dner.
while (!isupper(ch)) {
/***/
}
while dng deyiminin kontrol ifadesinde virgl ileci de kullanlabilir. Aadaki rnei
inceleyin:
#include <stdio.h>
#include <ctype.h>
#include <conio.h>
int main()
{
char ch;
while (ch = getch(), toupper(ch) != 'Q')
putchar(ch);
}

return 0;

138/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Virgl ilecinin sol terimi olan ifadenin daha nce yaplmasnn gvence altnda olduunu
biliyorsunuz. Yukardaki main ilevinde yer alan while dngsnn kontrol ifadesine
bakalm:
while (ch = getch(), toupper(ch) != 'Q')
nce virgl ilecinin sol terimi olan ifade yaplacana gre, getch ilevi arlr.
Klavyeden alnan karakterin kod numaras ch deikenine atanr. Daha sonra toupper
ilevinin arlmasyla, ch deikeni deerinin'Q' karakteri olup olmad snanr. Virgl
ilecinin rettii deerin, sa teriminin deeri olduunu anmsayn. Bu durumda
dngnn srdrlmesi hakknda sz sahibi olan ifade
toupper(ch) != 'Q'
ifadesidir. Yani dng ch 'Q' veya 'q' dnda byk harf karakteri olduu srece dner.
Kontrol ifadesini bir deiken de oluturabilir:
while (x) {
/***/
}
Yukardaki dng, x deikeni sfrdan farkl bir deere sahip olduu srece dner.
Kontrol ifadesi bir deimez de olabilir:
while (1) {
/***/
}
Yukardaki while deyiminde kontrol ifadesi olarak 1 deimezi kullanlyor. 1 sfr d bir
deer olduundan, yani kontrol ifadesi bir deikene bal olarak deimediinden, byle
bir dngden koul ifadesinin yanl olmasyla klamaz. Bu tr dnglere sonsuz dng
(infinite loops) denir. Sonsuz dngler programcnn bir hatas sonucu oluabildii gibi,
bilinli olarak, yani belirli bir amac gerekletirmek iin de oluturulabilir. while ayrac
iine 1 deimez deerinin olduu while dngs, bilinli olarak oluturulmu bir sonsuz
dng deyimidir.
Atama ilecinin kontrol ifadesi iinde kullanlmas da, sk rastlanan bir durumdur:
while ((val = get_value()) > 0) {
foo(val);
/***/
}
Yukardaki while dngsnde get_value ilevinin geri dn deeri, val isimli deikene
atanyor. Atama ileci ile oluturulan ifade ncelik ayrac iine alndn gryorsunuz.
Atama ilecinin rettii deer, nesneye atanan deer olduundan, byktr ilecinin sol
terimi yine get_value ilevinin geri dn deeridir. Bu durumda dng get_value
ilevinin geri dn deeri, 0'dan byk olduu srece dner. Dng gvdesi iinde
arlan foo ilevine val deerinin argman olarak gnderildiini gryorsunuz. foo ilevi,
get_value ilevinin geri dn deeri ile arlm olur.

break Deyimi

break anahtar szcn dorudan sonlandrc atom izler:


break;

139/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Bu biimde oluturulan deyime "break deyimi" (break statement) denir. break deyimi bir
dng deyiminin ya da switch deyiminin gvdesinde kullanlabilir. Bir dng deyiminin
yrtlmesi srasnda break deyimi ile karlaldnda, dngden klr, programn ak
dng gvdesi dndaki ilk deyim ile srer. Yani koulsuz olarak dngden klr.
Aadaki program inceleyin:
#include <stdio.h>
#include <math.h>
int main ()
{
int val;
while (1) {
printf("bir sayi girin : ");
scanf("%d", &val);
if (val < 0)
break;
printf("karekok %d = %lf\n", val, sqrt(val));
}
printf("donguden kld program sonlanyor!\n");
return 0;

}
Programda bilinli olarak bir sonsuz dng oluturuluyor. Dngnn her turunda val isimli
deikene klavyeden bir deer alnyor. Eer klavyeden 0'dan kk bir deer girilirse,
break deyimi ile dngden klyor.
break deyimi yalnzca bir dng deyiminin ya da switch deyiminin gvdesinde
kullanlabilir. Aadaki kod paras geersizdir:
if (x > 100) {
if (y < 200)
break;
/***/
}

continue Deyimi

continue anahtar szcn de dorudan sonlandrc atom izler:


continue;
Bu ekilde oluturulan deyime "continue deyimi" (continue statement) denir.
Programn ak bir dng deyimi iinde continue deyimine geldiinde, sanki dngnn
turu bitmi gibi dngnn bir sonraki turuna geilir.
int getval(void);
int isprime(void);
while (1) {
val = getval();
if (val < 0)
break;
/* deyimler */
if (isprime(val))
continue;
/* deyimler */
}

140/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yukardaki main ilevinde bir sonsuz dng oluturuluyor. Dngnn her turunda getval
isimli ilevin geri dn deeri val deikeninde saklanyor. Eer val deikenine atanan
deer 0 ise break deyimiyle dngden klyor. Daha sonra yer alan if deyimi ile val
deerinin asal olup olmad snanyor. val'e atanan deer asal ise, dngnn kalan ksm
yrtlmyor, continue deyimiyle dngnn bir sonraki turuna geiliyor.
continue deyimi, zellikle dng iinde uzun if deyimleri olduunda, okunabilirlii
artrmak amacyla kullanlr.
while (k++ < 100) {
ch = getch();
if (!isspace(ch)) {
/* deyimler */
}
}
Yukardaki yazlan while dngs iinde, klavyeden getch ilevi ile ch deikenine bir
karakterin kod numaras alnyor. Klavyeden alnan karakter bir boluk karakteri deilse
deyimlerin yrtlmesi isteniyor. Yukardaki kod parasnn okunabilirlii, continue
deyiminin kullanlmasyla artrlabilir:
while (k++ < 100) {
ch = getch();
if (isspace(ch))
continue;
/* deyimler */
}
Baz programclar da continue deyimini dng gvdesinde yer alacak bir bo deyime
seenek olarak kullanrlar:
while (i++ < 100)
continue;
continue deyimi yalnzca bir dng deyiminin gvdesinde kullanlabilir. continue
deyiminin, dng dnda bir yerde kullanlmas geerli deildir.

Sk Yaplan Hatalar

while dng deyiminin gvdesinin yanllkla bo deyim yaplmas sk yaplan bir hatadr:
#include <stdio.h>
int main()
{
int i = 10;

while (--i > 0);


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

/* burada bir bo deyim var */

Yukardaki dng while ayrac iindeki ifadenin deeri 0 olana kadar dner. printf ars
dng deyiminin gvdesinde deildir. while ayracn izleyen sonlandrc atom, dngnn
gvdesini oluturan deyim olarak ele alnr. Dngden kldnda ekrana 0 deeri yazlr.
Eer bir yanllk sonucu deil de, bilinli olarak while dngsnn gvdesinde bo deyim
(null statement) bulunmas isteniyorsa, okunabilirlik asndan bu bo deyim, while
ayracndan hemen sonra deil, alt satrda bir tab ieriden yazlmaldr.

141/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

while dng deyimiyle ilgili yaplan bir baka tipik hata da, dng gvdesini bloklamay
unutmaktr. Yani dng gvdesindeki deyimin bir bileik deyim olmas gerekirken,
yanllkla bir yaln deyim kullanlr:
#include <stdio.h>
int main()
{
int i = 1;

while (i <= 100)


printf("%d ", i);
i++;
return 0;

1'den 100'e kadar olan saylarn, aralarnda birer bolukla ekrana yazdrlmak istendiini
dnelim. Yukardaki while deyiminde i++ deyimi, yani dng deikeninin artrlmas
dngnn gvdesine ait deildir. Bu durumda i <= 100 ifadesi hep doru olacandan
sonsuz dng oluur ve ekrana srekli olarak 1 deeri yazlr.
if deyiminde olduu gibi while ayrac iinde de karlatrma ileci olan "==" yerine
yanllkla atama ileci "=" kullanlmas, yine sk yaplan hatadr:
while (x == 5) {
/***/
}
gibi bir dng, x deikeninin deeri 5 olduu srece dnerken aadaki deyim, bir
sonsuz dng oluturur:
while (x = 5) {
/***/
}
Dngnn her turunda x deikenine 5 deeri atanr. Atama ilecinin rettii deer olan
5, "doru" olarak yorumlanacandan, dng srekli dner.

Kontrol fadesinde Sonek Konumundaki ++ ya da -- lecinin


Kullanlmas

Kontrol ifadesi iinde sonek konumundaki ++ ya da -- ileci sk kullanlr. Byle bir


durumda, nce ifadenin deerine baklarak dngnn srdrlp srdrlmeyecei karar
verilir, sonra artrma ya da eksiltme ilecinin yan etkisi kendisini gsterir. Aadaki
rnei inceleyin:
#include <stdio.h>
int main()
{
int i = 0;
while (i++ < 100)
;
printf("\n%d\n", i);
}

/* ekrana 101 deerini basar. */

return 0;

142/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

n Kez Dnen while Dngs

n bir pozitif tamsay olmak zere, n defa dnen bir while dngs oluturmak iin
while (n-- > 0)
ya da
while (n--)
kod kalplar kullanlabilir. Aada, bir tamsaynn belirli bir ssn hesaplayan power
isimli bir ilev yazlyor. levi inceleyin:
int power(int base, int exp)
{
int result = 1;
while (exp--)
result *= base;
return result;
}
lev iinde yazlan while dngs, exp deikeninin deeri kadar dner, deil mi? Bu
durumda base deikeni, exp kez kendisiyle arplm olur.

Dng Gvdesinin Bo Deyim Olmas

Bazen dng gvdesi bilinli bir ekilde bo deyim yaplr. Okunabilirlik asndan bu
durumda bo deyimin normal bir deyim gibi tablama kuralna uygun olarak yazlmas
tavsiye edilir. Aadaki program inceleyin:
#include <stdio.h>
#include <ctype.h>
#include <conio.h>
int main()
{
int ch;
printf("Evet mi Hayir mi? [e] [h] : ");
while ((ch = toupper(getch())) != 'E' && ch != 'H')
;
if (ch == 'E')
printf("evet dediniz!\n");
else
printf("hayr dediniz!\n");
}

return 0;

Yukardaki main ilevi iinde yazlan while dngs ile, kullanc klavyeden 'e', 'E', 'h',
'H' harflerinden birini girmeye zorlanyor. Dngy dikkatli bir ekilde inceleyin.
Dngnn kontrol ifadesi iinde "mantksal ve" ileci "&&" kullanlyor. "Mantksal ve"
ilecinin sol teriminin daha nce yaplmasnn gvence altnda olduunu anmsayn.
Standart olmayan getch ilevi ile, klavyeden bir karakter alnyor. Alnan karakterin sra
numaras, yani getch ilevinin geri dn deeri, standart toupper ilevine argman
olarak gnderiliyor. Bylece eer klavyeden kk harf karakteri girilmise byk harfe
dntrlm olur. toupper ilevinin geri dn deeri ch deikenine atanyor. Ayra

143/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

iinde yer alan ifadenin deeri, ch deikenine atanan deerdir. "Mantksal ve" ilecinin
sa tarafndaki ifadenin btn ile atama ilecinin rettii deerin de 'E' karakterine
eitsizlii sorgulanyor. ch deikenine atanan deer 'E' ise "mantksal ve" ilecinin
ikinci ksmna hi baklmaz, kontrol ifadesinin deeri yanl olarak yorumlanr. Bylece
dngden klr. ch deikenine atanan deerin 'H' olmas durumunda, && ilecinin sa
terimi deerlendirilir yani ch deikeninin deerinin 'H' karakterine eitsizlii sorgulanr.
Eer ch 'H' deerine eit ise kontrol ifadesi yine yanl olarak yorumlanr, dngden
klr. Bunun dndaki tm durumlarda, kontrol ifadesi doru olarak yorumlanacandan
dngnn dnmesi srer. Bir baka deyile, dngden klmas ancak klavyeden 'e',
'E', 'h', 'H' karakterlerinden birinin girilmesi ile mmkn olur.

while Dng Deyiminin Kullanld rnekler

Aada, bir tamsaynn ka basamakl olduu bilgisiyle geri dnen num_digit isimli bir
ilevin tanm yer alyor. Program derleyerek altrn:
#include <stdio.h>
int num_digit(int val)
{
int digit_counter = 0;
if (val == 0)
return 1;

while (val != 0) {
digit_counter++;
val /= 10;
}
return digit_counter;

int main()
{
int x;
printf("bir tamsayi girin :");
scanf("%d", &x);
printf("%d sayisi %d basamakl!\n", x, num_digit(x));
return 0;
}
Basamak saysn hesaplamak iin ok basit bir algoritma kullanlyor. Say, sfr elde
edilinceye kadar srekli 10'a blnyor. num_digit ilevinde, nce parametre deikeni
olan val in deerinin 0 olup olmad snanyor. Eer val 0 deerine eit ise, 1 deeri ile
geri dnlyor. 0 says da 1 basamakldr deil mi? Daha sonra oluturulan while
dngs val != 0 kouluyla dner. Yani val deikeninin deeri 0 olunca bu dngden
klr. Dngnn her turunda gvde iinde digit_counter deikeninin deeri 1 artrlyor.
Daha sonra val /= 10; deyimiyle val deikeni onda birine eitleniyor.
Aada bu kez kendisine gnderilen bir tamsaynn basamak deerlerinin toplam ile geri
dnen sum_digit isimli bir ilev tanmlanyor:
#include <stdio.h>
int sum_digit(int val)
{
int digit_sum = 0;

144/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

while (val) {
digit_sum += val % 10;
val /= 10;
}
}

return digit_sum;

int main()
{
int val;
printf("bir tamsayi girin :");
scanf("%d", &val);
printf("%d sayisinin basamaklari toplami = %d\n", val, sum_digit(val));
}

return 0;

sum_digit ilevinde, yine parametre deikeni olan val, bir dng iinde srekli 10'a
blnyor, val 0 oluncaya kadar dng gvdesindeki deyimler yrtlyor. Dng
gvdesi iinde
digit_sum += val % 10;
deyimi ile val deikeninin birler basama, deeri digit_sum deikenine katlyor.
Bylece dngden kldktan sonra digit_sum deikeni, dardan gnderilen saynn
basamaklar deerlerinin toplamn tutuyor.
Aada, kendisine gnderilen bir tamsaynn tersine geri dnen get_rev_num isimli bir
ilev yazlyor:
#include <stdio.h>
int get_rev_num(int val)
{
int rev_number = 0;
while (val) {
rev_number = rev_number * 10 + val % 10;
val /= 10;
}
return rev_number;
}
int main()
{
int val;
printf("bir tamsayi girin :");
scanf("%d", &val);
printf("%d sayisinin tersi = %d\n", val, get_rev_num(val));
}

return 0;

get_rev_num ilevi iinde tanmlanan rev_number deikeni 0 deeriyle balatlyor.


lev iinde yer alan while dngsnn, parametre deikeni olan val'in deeri 0 olana
kadar dnmesi salanyor. Dngnn her turunda, rev_number deikenine

145/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

rev_number * 10 + val % 10
ifadesinin deeri atanyor.
leve gnderilen deerin 1357 olduunu dnelim:
rev_number

val

1357

135

75

13

753

7531

Dng knda rev_number deikeninin deeri 7531 olur.


Aadaki programda, bir tamsayy arpanlarna ayran ve arpanlar kkten bye
ekrana yazdran, display_factors isimli bir ilev tanmlanyor:
#include <stdio.h>
void display_factors(int number)
{
int k = 2;
printf("(%d) -> ", number);
while (number != 1) {
while (number % k == 0) {
printf("%d ", k);
number /= k;
}
++k;
}
printf("\n");
}
Aadaki programda 3 basamakl saylardan abc == a3 + b3 + c3 eitliini salayanlar
ekrana yazdrlyor:
#include <stdio.h>
int main()
{
int k = 100;

while (k < 1000) {


int y = k / 100;
int o = k % 100 / 10;
int b = k % 10;
if (y * y * y + o * o * o + b * b * b == k)
printf("%d\n", k);
++k;
}
return 0;

Aadaki ilevin hangi deeri hesapladn bulmaya aln:

146/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

int func(int val)


{
int sum = 0;
while (val) {
sum += val % 10;
if (sum > 10)
sum = 1 + sum % 10;
val /= 10;
}
return sum;
}

do while Dng Deyimi

do while dng deyiminin genel szdizimi aadaki gibidir:


do

deyim;
while (ifade);
do while dngsnde kontrol ifadesi sondadr. while ayracndan sonra sonlandrc atom
bulunmaldr. Yani buradaki sonlandrc atom, dng deyiminin szdiziminin bir
parasdr. do while dngsnn yrtlmesi aadaki gibi olur:
do anahtar szcn izleyen deyim dngye girite bir kez yaplr, daha sonra while
ayrac iindeki kontrol ifadesine baklr. Kontrol ifadesi doru olduu srece dng
gvdesini oluturan deyim yaplr. do while dngsnn while dngsnden fark nedir?
while dngsnde dng gvdesindeki deyimin en az bir kez yaplmas gvence altnda
deildir. Ancak do while dngsnde kontrol sonda yapld iin gvdedeki deyim en az
bir kez yaplr.
Aadaki program derleyerek altrn:
#include <stdio.h>
int main()
{
int val;
do {
printf("0 - 100 arasi bir deger girin : ");
scanf("%d", &val);
} while (val < 0 || val > 100);
printf("val = %d\n", val);
}

return 0;

main ilevinde do while dngs ile kullanc, 0 100 aralnda bir deer girmeye
zorlanyor. Eer girilen deer 0'dan kk ya da 100'den bykse, kullancdan yeni bir
deer isteniyor.
Daha nce while dngs kullanarak yazlan num_digit isimli ilev, bu kez do while
dngs ile yazlyor:

147/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

int num_digit(int val)


{
int digit_counter = 0;
do {
digit_counter++;
val /= 10;
} while(val != 0);
}

return digit_counter;

Aada tanmlanan print_ulam ileviyle bir tamsayya ilikin ulam serisi ekrana
yazdrlyor:
#include <stdio.h>
void print_ulam(int val)
{
printf("%d icin ulam serisi\n", val);
do {
printf("%d ", val);
if (val % 2 == 0)
val /= 2;
else
val = val * 3 + 1;
} while(val > 1);
printf("%d\n", val);
}
int main()
{
int x;
printf("bir sayi girin: ");
scanf("%d", &x);
print_ulam(x);
}

return 0;

for Dng Deyimi

for dng deyiminin genel szdizimi aadaki gibidir:


for (ifade1; ifade2; ifade3)
deyim;
Derleyici for anahtar szcnden sonra bir ayra almasn ve ayra iinde iki noktal
virgl atomu bulunmasn bekler. Bu iki noktal virgl, for ayracn ksma ayrr. Bu
ksmda da ifade tanmna uygun ifadeler yer alabilir.
for ayrac iinde iki noktal virgl mutlaka bulunmaldr. for ayracnn iinin bo
braklmas, ya da for ayrac iinde bir, ya da daha fazla sayda noktal virgln
bulunmas geersizdir.
for ayracnn kapanmasndan sonra gelen ilk deyim, dng gvdesini (loop body)
oluturur. Dng gvdesi, yaln bir deyimden oluabilecei gibi, bileik deyimden de yani
blok iine alnm birden fazla deyimden de, oluabilir. Dng gvdesini bir bo deyim ya
da bir kontrol deyimi de oluturabilir.

148/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

for ayrac iindeki her ifadenin de ayr ayr ilevi vardr.


for ayracnn ikinci ksmn oluturan ifadeye kontrol ifadesi (control expression) denir.
Tpk while ayrac iindeki ifade gibi, dngnn srdrlmesi konusunda bu ifade sz
sahibidir. Bu ifadenin deeri sfrdan farkl ise, yani "doru" olarak yorumlanrsa, dng
srer. Dng gvdesindeki deyim yrtlr. Kontrol ifadesinin deeri 0 ise, yani ifade
yanl olarak yorumlanrsa programn ak for dng deyimini izleyen ilk deyimin
yrtlmesiyle srer.
Programn ak for deyimine gelince, for ayracnn birinci ksmndaki ifade deerlendirilir.
Birinci ksmdaki ifade genellikle dng deikenine ilkdeer verme amacyla kullanlr.
Ancak phesiz byle bir zorunluluk yoktur.
for ayracnn nc ksmndaki ifade, dng gvdesindeki deyim ya da deyimler
yrtldkten sonra, kontrol ifadesi yeniden snanmadan nce ele alnr. Bu ksm
ounlukla, bir dng deikeninin artrlmas ya da azaltlmas amacyla kullanlr.
Aadaki program inceleyin:
#include <stdio.h>
int main()
{
int i;
for (i = 0; i < 2; ++i)
printf("%d ", i);
printf("\nson deger = %d\n", i);
}

return 0;

Programn ak for dng deyimine gelince, nce for ayrac iindeki birinci ifade ele alnr.
Yani i deikenine 0 deeri atanr.
imdi programn ak for ayracnn ikinci ksmna, yani kontrol ifadesine gelir ve i < 2
koulu sorgulanr. Kontrol ifadesinin deeri sfrdan farkl olduu iin, ifade mantksal
olarak doru kabul edilir. Bylece programn ak dng gvdesine geer. Dng
gvdesinin bir basit deyim tarafndan oluturulduunu gryorsunuz. Bu deyim yrtlr.
Yani ekrana i deikeninin deeri yazlarak imle alt satra geirilir.
Programn ak, bu kez for ayracnn nc ksmna gelir ve buradaki ifade ele alnr,
yani i deikeninin deeri 1 artrlr, i deikeninin deeri 1 olur.
kinci ifade yeniden deerlendirilir ve i < 2 ifadesi doru olduu iin bir kez daha dng
gvdesindeki deyim yrtlr.
Programn ak yine for ayracnn nc ksmna gelir ve buradaki ifade ele alnr, yani i
deikeninin deeri 1 artrlr. i deikeninin deeri 2 olur.
Programn ak yine for ayracnn ikinci ksmna gelir. Buradaki kontrol ifadesi yine
sorgulanr. i < 2 ifadesi, bu kez yanl olduu iin programn ak, dng gvdesine
girmez, dng gvdesini izleyen ilk deyimle srer. Yani ekrana:
sondeger = 2
yazlr.

Dng Deikenleri

for dngsnde bir dng deikeni kullanlmas gibi bir zorunluluk yoktur. rnein
aadaki dng, kurallara tamamen uygundur:
for (func1(); func2(); func3())
func4();

149/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yukardaki for dng deyimiyle, dngye girite func1 ilevi arlr. func2 ilevi sfr d
bir deere geri dndke dng gvdesindeki deyim yrtlr yani func4 ilevi arlr.
Kontrol ifadesine yeniden gelmeden, yani func4 ilevinin arlmasndan sonra bu kez
func3 ilevi arlr.
Aadaki for dng deyimiyle klavyeden 'x' karakteri girilmedii srece, alnan karakter
ekrana yazdrlyor:
#include <stdio.h>
#include <conio.h>
int main()
{
char ch;
for (ch = getch(); ch != 'x' ; ch = getch())
putchar(ch);
}

return 0;

Dng deikeninin tamsay trlerinden birinden olmas gibi bir zorunluluk yoktur. Dng
deikeni, gerek say trlerinden de olabilir:
#include <stdio.h>
int main()
{
double i;
for (i = 0.1; i < 6.28; i += 0.01)
printf("%lf ", i);
return 0;
}
Yukardaki dngde, double trden bir dng deikeni seiliyor. for ayracnn birinci
ksmnda dng deikenine 0.1 deeri atanyor. Ayracn nc ksmnda ise dng
deikeni 0.01 artrlyor. Dng, i deikeninin deerinin 6.28'den kk olmas
kouluyla dnyor.

for Ayrac inde Virgl lecinin Kullanlmas

Virgl ileci ile birletirilmi ifadelerin, soldan saa doru srayla ele alndn anmsayn.
for dnglerinin birinci ve nc ksmnda virgl ilecinin kullanlmasna sk rastlanr.
Aadaki dng deyimini inceleyin:
#include <stdio.h>
int main()
{
int i, k;
for (i = 1, k = 3; i * k < 12500; i += 2, k += 3)
printf("(%d %d)", i, k);
}

return 0;

150/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yukardaki for deyiminde, for ayracnn birinci ksmnda virgl ileci kullanlarak yazlan
ifade ile, i deikenine 1, k deikenine 3 deeri atanyor. Dng, i * k ifadesinin deeri
12500'den kk olduu srece dner. for ayracnn nc ksmnda i deikeninin
deeri 2, k deikeninin deeri 3 artrlyor.

for Ayrac indeki ifadelerin Olmamas

for dng deyimi ayracnn birinci ksmnda bir ifade bulunmayabilir. Bu tamamen
kurallara uygun bir durumdur. 1'den 100'e olan kadar saylarn ekrana yazdrlmak
istendiini dnelim. Dng deikenine ilkdeer verme ilemi, for ayracnn birinci
ksmndan, for dngs dna alnabilir:
#include <stdio.h>
int main()
{
int i = 0;

for (; i < 100; ++i)


printf("%d ", i);
return 0;

for dng ayracnn nc ksmnda da bir ifade bulunmayabilir. Dng deikeninin


artrlmas ya da eksiltilmesi, for ayrac ii yerine, dng gvdesinde gerekletirilebilir:
#include <stdio.h>
int main()
{
int i = 0;

for (; i < 100;) {


printf("%d ", i);
i++;
}
return 0;

Birinci ve nc ifadesi olmayan for dngleri, while dngleriyle tamamen edeerdir.


while dngleriyle yazlabilen her kod, bir for dngsyle de yazlabilir. while dngs,
birinci ve nc ksm olmayan for dnglerine okunabilirlik asndan daha iyi bir
seenek olur.
for ayracnn ikinci ifadesi de hi olmayabilir. Bu durumda kontrol ifadesi olmayaca iin
dng, bir koula bal olmakszn srekli dner. Yani sonsuz dng oluturulur. Ancak
iki adet noktal virgl, yine ayra iinde mutlaka bulunmak zorundadr. Ayn i, bu kez bir
sonsuz dngnn bilinli kullanlmasyla yaplyor:

C programclarnn ou bilinli bir ekilde sonsuz dng oluturmak istediklerinde for (;;)
kalbn yeler. Bu kalp while (1) kalbna edeerdir. kisi de sonsuz dng belirtir.
Sonsuz dng oluturmak iin for (;;) biimi while (1) biimine gre daha ok tercih
edilir.
#include <stdio.h>
int main()
{
int i = 0;

151/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

for (;;) {
if (i == 100)
break;
printf("%d ", i);
i++;
}
return 0;
}
imdi de, aadaki dng deyiminin yrtlmesiyle ekrana ne yazdrlacan kestirmeye
aln:
#include <stdio.h>
int main()
{
double d;
for (d = 1.5; d < 3,0; d += 0.1)
printf("%lf ", d);
return 0;
}
Ekrana hibir ey yazlmaz! Dngnn kontrol ifadesinin d < 3,0 olduunu gryorsunuz.
Gerek say deimezi yazarken '.' yerine yanllkla virgl karakteri kullanlm. Bu
durumda virgl ilecinin rettii deer, ikinci terim olan 0 deeridir. Kontrol ifadesi yanl
olarak yorumlanr bylece dng gvdesindeki deyim hi yrtlmez.

n Kez Dnen for Dngleri


n 0'dan byk bir tamsay olmak zere, aadaki dnglerden hepsi n kez dner.
for (i = 0; i < n; ++i)
for (i = 1; i <= n; ++i)
for (i = n - 1; i >= 0; --i)
for (i = n; i > 0; --i)

for Dnglerinde continue Deyiminin Kullanm

Bir dngnn gvdesi iinde continue deyiminin kullanlmas ile, gvde iinde geriye
kalan deyimlerin atlanarak dngnn bir sonraki turuna geilir. for dngs gvdesi
iinde continue deyimi ile karlaldnda, programn ak for ayracnn nc ifadesine
gelir ve bu ifade ele alnr.

Dng Deikeninin Bayrak Amal Kullanlmas

Baz uygulamalarda, for dngsnn dng deikeni, bir bayrak grevi de grr. Bir for
dngs iinden, belirli bir koul olutuunda klmas gereksin:
for (i = 0; i < 100; ++i)
if (is_valid(i))
break;
Yukardaki dng deyiminin altrlmas sonucunda iki farkl durum sz konusudur. Eer
dngnn gvdesinde break deyimi yrtlrse, yani herhangi bir i deeri iin is_valid
ilevi sfr d bir deere geri dnerse, dng knda i deikeninin deeri, 100'den

152/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

kk olur. break deyimi hi yrtlmeden dng tm turlarn tamamlarsa, dng


knda i deikeninin deeri 100 olur.
Dng knda i deerinin 100 olup olmadnn snanmas ile, dngden nasl kld
anlalabilir.

for Dng Deyiminin Kullanmna rnekler

Aadaki programda, iki saynn ortak blenlerinin en by ve ortak katlarnn en


kn hesaplayan okek ve obeb isimli ilevler tanmlanyor:
#include <stdio.h>
int obeb(int number1, int number2)
{
int i;
int min = (number1 < number2) ? number1 : number2;
for (i = min; i >= 1; --i)
if (number1 % i == 0 && number2 % i == 0)
return i;
return 1;
}
int okek(int number1, int number2)
{
int i;
int max = (number1 > number2) ? number1 : number2;

for (i = max; i <= number1 * number2; i += max)


if (i % number1 == 0 && i % number2 == 0)
return i;
return number1 * number2;

int main()
{
int x, y;
int n = 5;

while (n--) {
printf("iki tamsayi girin : ");
scanf("%d%d", &x, &y);
printf("obeb = %d\n", obeb(x, y));
printf("okek = %d\n", okek(x, y));
}
return 0;

Aada tanmlanan ilev, ortak blenlerin en byn Euclid algoritmasyla buluyor:


int obeb(int a, int b)
{
int temp;
while (b) {
temp = b;
b = a % b;
a = temp;
}
return a;
}

153/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Aadaki programda, bir tamsay iin faktriyel deerini hesaplayan, fact isimli bir ilev
yazlyor. Program, int trnn 4 byte olduu bir sistemde derlenmeli:
#include <stdio.h>
int fact(int number)
{
int i;
int result = 1;
if (number == 0 || number == 1)
return 1;
for (i = 2; i <= number; ++i)
result *= i;
}

return result;

int main()
{
int k;
for (k = 0; k < 14; ++k)
printf("%2d! = %-10d\n", k, fact(k));
}

return 0;

Aada e says, fact ilevi kullanlarak bir seri toplamyla bulunuyor:


#include <stdio.h>
int fact(int);
int main()
{
int k;
double e = 0.;
for (k = 0; k < 14; ++k)
e += 1. / fact(k);
printf("e = %lf\n", e);
return 0;
}
Aadaki programda, kendisine gnderilen bir tamsaynn asal olup olmadn snayan
isprime isimli bir ilev yazlyor. lev, eer kendisine gnderilen say asal ise sfrdan
farkl bir deere, asal deil ise 0 deerine geri dnyor. Snama amacyla yazlan main
ilevinde isprime ilevi arlarak, 1000'den kk asal saylar ekrana yazdrlyor:

154/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
int isprime(int number)
{
int k;
if (number == 0 || number == 1)
return 0;
if (number % 2 == 0)
return number == 2;
if (number % 3 == 0)
return number == 3;
if (number % 5 == 0)
return number == 5;
for (k = 7; k * k <= number; k += 2)
if (number % k == 0)
return 0;
return 1;
}
int main()
{
int k;
int prime_counter = 0;

for (k = 0; k < 1000; ++k)


if (isprime(k)) {
if (prime_counter % 10 == 0 && prime_counter)
putchar('\n');
prime_counter++;
printf("%3d ", k);
}
return 0;

Blenlerinin toplamna eit olan tamsaylara, mkemmel tamsay (perfect integer) denir.
rnein 6 ve 28 tamsaylar mkemmel tamsaylardr.
1 + 2 + 3 = 6
1 + 2 + 4 + 7 + 14 = 28
Aadaki program ile 10000'den kk mkemmel saylar aranyor. Bulunan saylar
ekrana yazdrlyor:
#include <stdio.h>
int is_perfect(int number);
int main()
{
int k;
for (k = 2; k < 10000; ++k)
if (is_perfect(k))
printf("%d perfect\n", k);

155/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

return 0;

int is_perfect(int number)


{
int i;
int total = 1;
for (i = 2; i <=
if (number %
total +=
return number ==

number / 2; ++i)
i == 0)
i;
total;

}
Aadaki programda klavyeden srekli karakter alnmas salanyor, alnan karakterler
ekranda gsteriliyor. Arka arkaya "xyz" karakterleri girildiinde program sonlandrlyor:
#include <stdio.h>
#include <conio.h>
int main()
{
char ch;
int total = 0;

while (total < 3) {


ch = getch();
putchar(ch);
if (ch == 'x' && total == 0)
total++;
else if (ch == 'y' && total == 1)
total++;
else if (ch == 'z' && total == 2)
total++;
else total = 0;
}
return 0;

e Dngler

Bir dngnn gvdesini baka bir dng deyimi oluturabilir. Byle yaratlan dnglere
i ie dngler (nested loops) denir. Aadaki program derleyerek altrn:

#include <stdio.h>
int main()
{
int i, k;
for (i = 0; i < 5; ++i)
for (k = 0; k < 10; ++k)
printf("(%d %d) ", i, k);
printf("\n\n(%d %d) ", i, k);
return 0;
}
Dtaki for dngsnn gvdesindeki deyim, bir baka for dngsdr. i < 5 ifadesi
doru olduu srece iteki for dng deyimi yrtlr. Son yaplan printf ars ekrana
hangi deerleri yazdrr? Dtaki dng i < 5 kouluyla dndne gre dtaki dngden
ktktan sonra i deikeninin deeri 5 olur. teki for dng deyiminin son kez
156/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

yaplmasndan sonra da k deikeninin deeri 10 olur. Bu durumda en son printf ars


ekrana (5 10) yazdrr.
imdi de aada kodu verilen put_star ilevinin ne i yaptn bulmaya aln:
#include <stdio.h>
void put_stars(int n)
{
int i, k;
for (i = 1; i <= n; ++i) {
for (k = 1; k <= i; ++k)
putchar('*');
putchar('\n');
}
}
int main()
{
int val;
printf("bir deger girin : ");
scanf("%d", &val);
put_stars(val);
}

return 0;

Aadaki programda abc = a3 + b3 + c3 eitliini salayan basamakl saylar ekrana


yazdryor.
#include <stdio.h>
int main()
{
int i, j, k;
int number = 100;
for (i = 1; i <= 9; ++i)
for (j = 0; j <= 9; ++j)
for (k = 0; k <= 9; ++k) {
if (i * i * i + j * j * j + k * k * k == number)
printf("%d\n", number);
number++;
}
}

return 0;

e Dnglerde break Deyiminin Kullanlmas

ie dnglerde break deyimi kullanmna dikkat etmek gerekir. teki bir dngnn
gvdesinde break deyiminin kullanlmas ile, yalnzca iteki dngden klr: Aadaki
rnei inceleyin:

157/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

while (1) {
while (1) {
if (ifade)
break;
/***/
}
/*i dngden break ile kldnda ak bu noktaya gelir */
}
Eer i ie dnglerden yalnzca itekinden deil de dnglerin hepsinden birden kmak
istenirse bu durumda goto kontrol deyimi kullanlmaldr. Bu konuyu goto kontrol deyimi
blmnde greceksiniz.
Burada ikinci while dngs tek bir kontrol deyimi olarak ele alnaca iin bloklamaya
gerek yoktur.

Dnglerden k

Bir dngden nasl klabilir? Bir dngden kmak iin aadaki yollardan biri
kullanlabilir.
1. Kontrol ifadesinin yanl olmasyla:
Dng deyimlerinin, kontrol ifadelerinin doru olduu srece dndn biliyorsunuz.
2. return deyimi ile:
Bir ilev iinde yer alan return deyimi ilevi sonlandrdna gre, bir dng deyimi iinde
return deyimi ile karlaldnda dngden klr.
3. break deyimi ile:
break deyiminin kullanlmas ile, programn ak dng deyimini izleyen ilk deyimle srer.
4. goto deyimi ile:
goto deyimi ile bir programn ak ayn ilev iinde dngnn dnda bir baka noktaya
ynlendirilebilir. Bylece dngden klabilir.
5. Program sonlandran bir ilev ars ile:
Standart exit ya da abort ilevleri ile programn kendisi sonlandrlabilir.
Bir dngden kmak amacyla, kontrol ifadesinin yanl olmasn salamak iin dng
deikenine doal olmayacak bir biimde deer atanmas, programn okunabilirliini
bozar. Byle kodlardan kanmak gerekir.

158/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

KOUL LEC
Koul ileci (conditional operator / ternary operator), C dilinin terimli tek ilecidir.
Herhangi bir ifade koul ilecinin terimlerinden biri olabilir. Koul ilecinin genel szdizimi
aadaki gibidir:
ifade1 ? ifade2 : ifade3
Koul ileci, yukardaki biimden de grld gibi, birbirinden ayrlm iki atomdan
oluur. ? ve : atomlar, ilecin terimini birbirinden ayrr.
Derleyici, bir koul ileci ile karlatn, ? atomundan anlar. ? atomunun solundaki
ifadenin (ifade1) saysal deeri hesaplanr. Bu ifade mantksal olarak yorumlanr. Eer
ifade1'in 0'dan farkl ise, bu durumda yalnzca ifade2' nin saysal deeri hesaplanr.
ifade1'in deeri 0 ise, bu kez yalnzca ifade3'n saysal deeri hesaplanr.
Dier ilelerde olduu gibi koul ileci de bir deer retir. Koul ilecinin rettii deer
ifade1 doru ise (0 d bir deer ise) ifade2'nin deeri, ifade1 yanl ise ifade3'n
deeridir. rnek:
m = x > 3 ? y + 5 : y 5;
Burada nce x > 3 ifadesinin saysal deeri hesaplanr. Bu ifadenin deeri 0'dan farkl ise
yani doru ise, koul ileci y + 5 deerini retir. x > 3 ifadesinin deeri 0 ise yani ifade
yanl ise, koul ileci y 5 deerini retir. Bu durumda m deikenine x > 3 ifadesinin
doru ya da yanl olmasna gre y + 5 ya da y 5 deeri atanr.
Ayn ilem if deyimi ile de yaplabilir :
if (x > 3)
m = y + 5;
else
m = y 5;
Koul ileci, ile ncelik tablosunun 13. ncelik seviyesindedir. Bu seviye atama ilecinin
hemen stdr. Aadaki ifadeyi ele alalm:
x > 3 ? y + 5 : y 5 = m
Koul ilecinin ncelii atama ilecinden daha yksek olduu iin, nce koul ileci ele
alnr. x > 3 ifadesinin doru olduunu ve ilecin y + 5 deerini rettiini dnelim.
y + 5 = m
Koul ilecinin rettii deer sol taraf deeri olmadndan, yukardaki ifade geersizdir.
Normal olarak koul ilecinin ilk terimini ayra iine almak gerekmez. Ancak bu terimin,
okunabilirlik asndan genellikle ayra iine alnmas tercih edilir.
(x >= y + 3) ? a * a : b
Koul ilecinin nc terimi konusunda dikkatli olmak gerekir. rnein:
m = a > b ? 20 : 50 + 5
a > b ifadesinin doru olup olmamasna gre koul ileci, 20 ya da 55 deerini retir ve
son olarak da m deikenine koul ilecinin rettii deer atanr. Ancak m deikenine
a > b ? 20 : 50

159/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

ifadesinin deerinin 5 fazlas atanmak isteniyorsa bu durumda ifade aadaki gibi


dzenlenmelidir:
m = (a > b ? 20 : 50) + 5;
Koul ilecinin terimi de bir ilev ar ifadesi olabilir, ama arlan ilevlerin, geri
dn deeri reten ilevler olmas gerekir. teriminden birinin geri dn deeri void
olan bir ileve ilikin ilev ar ifadesi olmas, geersiz bir durum oluturabilir.
Aadaki kod parasn inceleyin:
#include <stdio.h>
int func1(void);
int func2(void);
int func3(void);
int main()
{
int m;
m = func1() ? func2() : func3();
}

return 0;

Yukarda koul ilecinin kullanld ifadede m deikenine, func1 ilevinin geri dn


deerinin sfr d bir deer olmas durumunda func2 ilevinin geri dn deeri, aksi
halde func3 ilevinin geri dn deeri atanr.
Koul ilecinin rettii, bir nesne deil bir deerdir. Koul ilecinin rettii deer nesne
gstermedii iin bu deere bir atama yaplamaz. Aadaki if deyimini inceleyin:
if (x > y)
a = 5;
else
b = 5;
Yukardaki if deyiminde x > y ifadesinin doru olmas durumunda a deikenine, yanl
olmas durumunda ise b deikenine 5 deeri atanyor. Ayn i koul ilecinin
kullanlmasyla yaptrlrsa:
(x > y) ? a : b = 5;

/* Geersiz! */

Bu durum derleme zaman hatasna yol aar. nk koul ilecinin rettii a ya da b


deikenlerinin deeridir, nesnenin kendisi deildir. Byle bir atama sol tarafn nesne
gsteren bir ifade olmamas nedeniyle derleme zamannda hata oluturur.
Ayn nedenden dolay aadaki ifade de geersizdir:
(x > 5 ? y : z)++;

/* Geersiz! */

Ayra iindeki ifade deerlendirildiinde elde edilen, y ya da z nesneleri deil, bunlarn


deerleridir. Yani sonek konumundaki ++ ilecinin terimi nesne deildir.
[C++ dilinde koul ilecinin 2. ya da 3. teriminin nesne olmas durumunda ilecin rettii deer sol taraf
deeridir. Yani yukardaki deyimler C de geersiz iken C++'da geerlidir.]

Koul lecinin Kullanld Durumlar

160/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

if deyiminin yerine koul ileci kullanmak her zaman doru deildir. Koul ilecinin
kullanlmasnn salk verildii tipik durumlar vardr. Bu durumlarda genel fikir, koul
ilecinin rettii deerden ayn ifade iinde faydalanmak, bu deeri bir yere aktarmaktr:
1. Koul ilecinin rettii deer bir nesneye atanabilir.
p = (x == 5) ? 10 : 20;
m = (a >= b + 5) ? a + b : a b;
Yukardaki deyimlerin iini grecek if deyimleri de yazlabilirdi:
if (x == 5)
p = 10;
else
p = 20;
if (a >= b + 5)
m = a + b;
else
m = a - b;
2. Bir ilev, koul ilecinin rettii deer ile geri dnebilir:
return x > y ? 10 : 20;
Bu rnekte x > y ifadesinin doru olup olmamasna gre ilev, 10 ya da 20 deerine geri
dner. Yukardaki ifade yerine aadaki if deyimi de kullanlabilirdi :
if (x > y)
return 10;
return 20;
3. Koul ilecinin rettii deer ile bir ilev arlabilir:
func(a == b ? x : y);
Yukardaki deyimde, a, b'ye eit ise func ilevi x deeri ile, a, b'ye eit deil ise y deeri
ile arlr. Ayn ii gren bir if deyimi de yazlabilirdi:
if (a == b)
func(x);
else
func(y);
4. Koul ilecinin rettii deer, bir kontrol deyiminin kontrol ifadesinin bir paras olarak
da kullanlabilir:
if (y == (x > 5 ? 10 : 20))
func();
Yukardaki deyimde x > 5 ifadesinin doru olup olmamasna gre, if ayrac iinde, y
deikeninin 10 ya da 20 deerine eitlii sorgulanr.
Yukardaki durumlarda, koul ilecinin if deyimine tercih edilmesi iyi tekniktir. Bu
durumlarda koul ileci daha okunabilir bir yap oluturur.
Koul ilecinin bilinsizce kullanlmamas gerekir. Eer koul ilecinin rettii deerden
dorudan faydalanlmayacaksa koul ileci yerine if kontrol deyimi tercih edilmelidir.
rnein:

161/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

x > y ? a++ : b++;


Deyiminde koul ilecinin rettii deerden faydalanlmyor. Burada aadaki if deyimi
tercih edilmelidir:
if (x > y)
a++;
else
b++;
Baka bir rnek:
x == y ? printf("eit\n") : printf("eit deil\n");
Bu rnekte, printf ilevinin bir geri dn deeri retmesinden faydalanlarak koul ileci
kullanlm. Koul ileci, x == y ifadesinin doru olup olmamasna gre, ikinci veya
nc ifade olan printf ilevi arlarndan birinin geri dn deerini retir. Bu da
aslnda ekrana yazlan karakter saysdr. Ama ifade iinde, koul ilecinin rettii deerin
kullanlmas sz konusu deildir. Burada da if deyimi tercih edilmelidir:
if (x == y)
printf("eit\n");
else
printf("eit deil\n");
Koul ilecinin ikinci ve nc terimlerinin trleri farkl ise, dier ilelerde olduu gibi
tr dntrme kurallar devreye girer:
int i;
double d;
m = (x == y) ? i : d;
Bu rnekte i deikeni int trden, d deikeni ise double trdendir. x == y karlatrma
ifadesi doru ise, koul ilecinin rettii deerin tr double trdr.
Baz durumlarda, if deyiminin de, koul ilecinin de, kullanlmas gerekmez:
if (x > 5)
m = 1;
else
m = 0;
Yukardaki if deyimi yerine aadaki deyim yazlabilirdi:
m = (x > 5) ? 1 : 0;
Koul ilecinin retecei deerlerin yalnzca 1 veya 0 olabilecei durumlarda, dorudan
karlatrma ileci kullanmak daha iyi teknik olarak deerlendirilmelidir:
m = x > 5;
Baka bir rnek :
return x == y ? 1 : 0;
yerine

162/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

return x == y;
yazlabilirdi.
Koul ilecinin ncelik yn sadan soladr. Bir ifade iinde birden fazla koul ileci varsa,
nce en sadaki deerlendirilir. Aadaki kod parasn inceleyin:
#include <stdio.h>
int main()
{
int x = 1, y = 1,

m;

m = x < 5 ? y == 0 ? 4 : 6 : 8;
printf("m = %d\n", m);
}

return 0;

Yukardaki main ilevinde printf ilevi ars ile m deikeninin deeri olarak ekrana 6
yazlr. fade aadaki gibi ele alnr:
m = x

<

5 ? (y == 0 ? 4 : 6) : 8;

Koul lecinin Kullanmna rnekler

Aada iki saydan byk olanna geri dnen, max2 isimli ilev tanmlanyor.
int max2(int a, int b)
{
return a > b ? a : b;
}

1 1 1 1
pi
1 + + + ... serisi
3 5 7 9
4

e yaknsar. Aada bir dng ile, pi says hesaplanyor.

Dng gvdesinde koul ilecinin kullanmn inceleyin:


#include <stdio.h>
int main()
{
double sum = 0.;
int k;
for (k = 0; k < 10000; ++k)
sum += (k % 2 ? -1. : 1.) / (2 * k + 1);
printf("pi = %lf\n", 4. * sum);
return 0;
}

163/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

NLEMC KOMUTLARI (1)


C derleyicileri iki ayr modlden oluur:
1. nilemci Modl
2. Derleme Modl
nilemcinin, bilgisayarn ilemcisi ya da baka bir donanmsal elemanyla hibir ilgisi
yoktur. nilemci, belirli bir i gren bir yazlm programdr.
nilemci, kaynak dosya zerinde birtakm dzenlemeler ve deiiklikler yapan bir n
programdr. nilemci programnn bir girdisi bir de kts vardr. nilemcinin girdisi
kaynak dosyann kendisidir. nilemci programn kts ise derleme modlnn girdisini
oluturur. Yani kaynak program ilk aamada nilemci tarafndan ele alnr. nilemci
modl, kaynak dosyada eitli metinsel dzenlemeler, deiiklikler yapar. Daha sonra
deitirilmi ya da dzenlenmi olan bu kaynak dosya, derleme modl tarafndan ama
koda dntrlr.

C programlama dilinde # ile balayan btn satrlar, nilemci programa verilen


komutlardr (directives).
nilemci program, nceden belirlenmi bir komut kmesindeki ilemleri yapabilir. Her
bir komut, # atomunu izleyen bir szckle belirlenir. Aada tm nilemci komutlarnn
listesi veriliyor:
#include
#define
#if
#else
#elif
#ifdef
#ifndef
#endif
#undef
#line
#error
#pragma
nilemci komutlarn belirleyen yukardaki szckler, C dilinin anahtar szckleri
deildir. Sra derleyiciye geldiinde bunlar, nilemci tarafndan kaynak dosyadan silinmi
olur. rnein, istenirse include isimli bir deiken tanmlanabilir, ama bunun okunabilirlik
asndan iyi bir fikir olmad sylenebilir. nilemci komutlarn belirten szckler, ancak
# karakterini izledikleri zaman zel anlam kazanr.
nilemci program, ama kod oluturmaya ynelik hibir i yapmaz, kaynak kod iinde
baz metinsel dzenlemeler yapar. Kendisine verilen komutlar yerine getirdikten sonra, #
ile balayan satrlar kaynak dosyadan siler. Derleme modlne girecek programda # ile
balayan satrlar artk yer almaz.
imdilik nilemci komutlarndan yalnzca #include ve #define komutlarn greceksiniz.
Geriye kalan nilemci komutlar ileride ayrntl olarak ele alnacak.

165/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include nilemci Komutu

Bu nilemci komutunun genel szdizimi aadaki gibidir:


#include <dosya ismi>
ya da
#include "dosya ismi"

#include komutu ile, ismi verilen dosyann ierii, bu komutun yazld yere yaptrlr.
Bu komut ile nilemci, belirtilen dosyay diskten okuyarak komutun yazl olduu yere
yerletirir. Bu komutla yaplan i, metin dzenleyici programlardaki "kopyala - yaptr"
(copy paste) ilemine benzetilebilir.
#include nilemci komutuyla, kaynak dosyaya eklenmek istenen dosyann ismi iki ayr
biimde belirtilebilir:
1. Asal ayra iinde:
#include <stdio.h>
#include <time.h>
2. ift trnak iinde
#include "general.h"
#include "genetic.h"
Dosya ismi eer asal ayra iinde verilmise, szkonusu dosya nilemci tarafndan,
yalnzca nceden belirlenmi bir dizin iinde aranr. allan derleyiciye ve sistemin
kurulumuna bal olarak, nceden belirlenmi bu dizin farkl olabilir. rnein:
\tc\include
\borland\include
\c600\include
gibi. Benzer biimde UNIX sistemleri iin bu dizin, rnein:
/usr/include
biiminde olabilir. Standart balk dosyalar, asal ayra iinde kaynak koda eklenir.
Sistemlerin ounda dosya ismi iki trnak iine yazldnda, nilemci ilgili dosyay nce
allan dizinde (current directory) arar. Burada bulamazsa sistem ile belirlenen dizinde
arar. rnein:
C:\sample
dizininde alyor olalm.
#include "strfunc.h"
komutu ile, nilemci strfunc.h isimli dosyay nce C:\sample dizininde arar. Eer burada
bulamazsa sistem tarafndan belirlenen dizinde arar. Programclarn kendilerinin
oluturduklar balk dosyalar, genellikle sisteme ait dizinde olmadklar iin, ift trnak
iinde kaynak koda eklenir.
#nclude nilemci komutu ile kaynak koda eklenmek istenen dosya ismi, dosya yolu
(path) da ierebilir:

166/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <sys\stat.h>
#include "c:\headers\myheader.h"
#include nilemci komutu kaynak programn herhangi bir yerinde bulunabilir. Fakat
standart balk dosyalar gibi, iinde eitli bildirimlerin bulunduu dosyalar iin en iyi yer,
kukusuz programn en tepesidir.
#include komutu, i ie gemi (nested) bir biimde de bulunabilir. rnein ok sayda
dosyay kaynak koda eklemek etmek iin yle bir yntem izlenebilir.
ana.c

project.h

#include "project.h"

#include
#include
#include
#include

int main()
{
/****/
}

<stdio.h>
<conio.h>
<stdlib.h>
<time.h>

ana.c dosyas iine yalnzca project.h dosyas ekleniyor. nilemci bu dosyay kaynak
koda ekledikten sonra yoluna bu dosyadan devam eder.

Balk Dosyalar Neden Kullanlr?

zellikle byk programlar, modl ismi verilen ayr ayr paralar halinde yazlr. Bu
modllerden bazlarnn amac, dier modllere hizmet vermektir. C ve C++ dillerinde,
genel hizmet verecek kodlar (server codes), genel olarak iki ayr dosya halinde yazlr.
lev tanmlamalar, global deiken tanmlamalar uzants .c olan dosyada yer alr. Bu
dosyaya, kodlama dosyas (implementation file) denir. Hizmet alacak kodlar (client
codes) ilgilendiren bildirimler ise bir baka dosyada tutulur. Bu dosyaya, balk dosyas
(header file) denir. Bir balk dosyas, bir modln arayzdr (interface). Modl daryla
olan ilikisini arayz ile kurar.
Verilen hizmetlerden faydalanacak kullanc kodlar, hizmet veren kodlarn kendisini deil,
yalnzca arayzn grr. Hizmet alan kodlar, hizmet veren kodlarn arayzlerine bal
olarak yazlr. Bylece hizmet veren kodlarn kendisi ile arayzleri, birbirinden net olarak
ayrlm olur.
Hizmet veren kodlarn arayzleriyle tanmlarn birbirinden ayrmann ne gibi faydalar
olabilir?
Kullanc kodlar, yani hizmet alan kodlar, hizmet veren ilevlerin tanmlarna gre deil
de, arayzlerine bal olarak yazlr. Bundan aadaki faydalar salanabilir:
1. Hizmet veren kodlar yazanlar, ayn arayze bal kalmak kaydyla, tanm kodlarnda
deiiklik yapabilir. Bu durumda hizmet alan kodlarda bir deiiklik yaplmas gerekmez.
2. Kullanc kodlar yazacak programc, hizmet veren kodlara ilikin uygulama ayrntlarn
bilmek zorunda kalmadndan, daha kolay soyutlama yapar.
3. Birden fazla programcnn ayn projede almas durumunda, proje gelitirme sresi
ksaltlm olur.

167/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#define nilemci Komutu

#define nilemci komutunun ilevi, metin dzenleyici programlardaki "bul - deitir"


(find - replace) zelliine benzetilebilir. Bu komut kaynak kod iindeki bir yazy baka bir
yaz ile deitirmek iin kullanlr.
nilemci, define szcnden sonraki boluklar atarak, boluksuz ilk yaz kmesini elde
eder. Bu yazya STR1 diyelim. Daha sonra satr sonuna kadar olan tm yaz kmesi elde
edilir. Buna da STR2 diyelim. nilemci, kaynak kod iinde STR1 yazs yerine STR2
yazsn yerletirir:
#define

SIZE

100

nilemci komutuyla, nilemci kaynak kod iinde grd her bir SIZE atomu yerine
100 atomunu yerletirir. Derleme modlne girecek kaynak programda, SIZE atomu artk
yer almaz.
#define nilemci komutu kullanlarak ounlukla bir isim, saysal bir deerle yer
deitirilir. Saysal bir deerle deitirilen isme, "simgesel deimez" (symbolic constant)
denir. Simgesel deimezler nesne deildir. Derleme modlne giren kaynak kodda,
simgesel deimezlerin yerini saysal ifadeler alm olur.
#define nilemci komutuyla tanmlanan isimlere, "basit makro" (simple macro) da denir.
Simgesel deimezler, geleneksel olarak byk harf ile isimlendirilir. Bylece kodu
okuyann deikenlerle, simgesel deimezleri ayrt edebilmesi salanr. Bilindii gibi C
dilinde, deiken isimlendirmelerinde arlkl olarak kk harfler kullanlr.
Bir simgesel deimez, baka bir simgesel deimezin tanmlamasnda kullanlabilir.
rnein:
#define MAX
#define MIN

100
(MAX - 50)

Yer deitirme ilemi, STR1'in kaynak kod iinde bir atom halinde bulunmas durumunda
yaplr:
#define SIZE

100

Bu tanmlamadan sonra kaynak kodda


size = MAX_SIZE;
printf("SIZE = %d\n", size);
gibi deyimlerin bulunduunu dnelim. nilemci bu deyimlerin hibirinde bir deiiklik
yapmaz.
size = MAX_SIZE
ifadesinde SIZE ayr bir atom deildir. Atom olan MAX_SIZE'dr. Yer deitirme ilemi
byk kk harf duyarl ile yaplacandan, kaynak kod iinde yer alan size ismi de
deitirilecek atom deildir.
printf("SIZE = %d\n", max_size)
ifadesinde atom olan dizge ifadesidir. Yani dizge iindeki SIZE, tek bana ayr bir atom
deildir.
#define nilemci komutu ile deimezlere ve ilelere ilikin yer deitirme ilemi
yaplamaz.

169/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Aadaki #define nilemci komutlar geerli deildir:


#define +
#define 100

200

Simgesel deimezler, C dilinin deiken isimlendirme kurallarna uygun olarak


isimlendirilmelidir:
#define

BYK

10

tanmlamas geersizdir.
nilemci program, #include komutu ile kaynak koda eklenen dosyann iindeki nilemci
komutlarn da altrr. Bu durumda iinde simgesel deimez tanmlamalar yaplm bir
dosya, #include komutu ile kaynak koda eklendiinde, bu simgesel deimezler de
kaynak kod iinde tanmlanm gibi geerli olur.
#define nilemci komutunda dizgeler de kullanlabilir:
#define HATA_MESAJI
/***/
printf(HATA_MESAJI);
/***/

"DOSYA AILAMIYOR \n"

Simgesel deimez tanmnda kullanlacak dizge uzunsa, kodun okunmasn


kolaylatrmak iin, birden fazla satra yerletirilebilir. Bu durumda, son satr dndaki
satrlarn sonuna "\" atomu yerletirilmelidir.
Okunabilirlik asndan, tm simgesel deimez tanmlamalar alt alta gelecek biimde
yazlmaldr. Seilen simgesel deimez isimleri, kodu okuyan kiiye bunlarn ne amala
kullanld hakknda fikir vermelidir.
Bir simgesel deimezin tanmlanm olmas, kaynak kod iinde deitirilebilecek bir
bilginin olmasn zorunlu hale getirmez. Tanmlanm bir simgesel deimezin kaynak kod
iinde kullanlmamas, herhangi bir hataya yol amaz.

Simgesel Deimezler Kodu Daha Okunabilir Klar

Simgesel deimezler, yazlan kodun okunabilirliini ve alglanabilirliini artrr. Baz


deimezlere isimlerin verilmesi, bu deimezlerin ne amala kullanld hakknda daha
fazla bilgi verilebilir. Aadaki rnee bakalm:
#define PERSONEL_SAYISI

750

void foo()
{
/***/
if (x == PERSONEL_SAYISI)
/***/
}
Kaynak kod iinde PERSONEL_SAYISI simgesel deimezi yerine dorudan 750 deeri
kullanlm olsayd, kodu okuyann, bu deimezin ne anlama geldiini karmas ok
daha zor olurdu, deil mi?

Simgesel Deimezlerle Trlere sim Verilmesi

#define nilemci komutuyla C'nin doal veri trlerine de isimler verilebilir:

170/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#define BYTE
#define BOOL

char
int

BYTE foo(BYTE b);


BOOL isprime(int val);
char trnn aslnda 1 byte' lk bir tamsay tr olduunu biliyorsunuz. char isminin
kullanlmas ounlukla yazlarla ya da karakterle ilgili bir i yapld izlenimini verir.
Oysa bellek bloklar zerinde genel ilemler yapan ilevler de ounlukla char trn
kullanr. Bu durumda yaplan ile ilgili daha fazla bir fikir vermek iin, rnein BYTE ismi
kullanlabilir. C'de BOOL trnn olmadn hatrlyorsunuz. C'de bool veri tr yerine
mantksal bir veri tr olarak int tr kullanlr. Ancak programn okunabilirliini artrmak
iin #define nilemci komutuyla BOOL ismi kullanlabilir.
Bu kullanma seenek olan typedef anahtar szcn ve yeni tr ismi tanmlamalarn
ileride ele alacaz.

levlerin Simgesel Deimezlerle Geri Dnmesi

Okunabilirlii artrmaya ynelik bir baka kullanm da ilevlerin geri dn deerlerine


yneliktir. Baz ilevlerin geri dn deerlerinin bir soruya yant verdiini, baz ilevlerin
geri dn deerlerinin de bir ilemin baars hakknda fikir verdiini biliyorsunuz. Byle
ilevler, geri dn deeri ifadeleri yerine simgesel deimezler kullanrlarsa okunabilirlik
asndan daha iyi olabilir:
return
return
return
return
return

VALID;
INVALID;
TRUE;
FALSE;
FAILED;

gibi.

levlerin Simgesel Deimezlerle arlmas

Baz ilevlere de, aran kod paras tarafndan simgesel deimezler gnderilir.
C'nin standart balk dosyalarnda da bu amala baz simgesel deimezler
tanmlanmtr. rnein stdlib.h balk dosyas iinde
#define EXIT_FAILURE
#define EXIT_SUCCESS

1
0

biiminde tanmlamalar vardr. Yani stdlib.h balk dosyas kaynak koda eklenirse
EXIT_FAILURE simgesel deimezi 1, EXIT_FAILURE simgesel deimezi, 0 yerine
kullanlabilir. Bu simgesel deimezler, standart exit ilevine yaplan arlarda kullanlr:
exit(EXIT_FAILURE);
stdio.h balk dosyas iinde standart fseek ilevine argman olarak gnderilmesi
amacyla simgesel deimez tanmlanmtr:
#define SEEK_SET
#define SEEK_CUR
#define SEEK_END

0
1
2

Bayrak Deikenlerin Simgesel Deimezlerle Deerini Almas

C programlarnda, bayrak deikenleri de ounlukla simgesel deimezlerle deerlerini


alr:

171/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

pos_flag = ON;
validiy_flag = INVALID;
switch kontrol deyimindeki case ifadeleri de ounlukla simgesel deimezlerle
oluturulur. Bu konuyu switch kontrol deyiminde inceleyeceiz.

Simgesel Deimezler Yoluyla Programn Deitirlmesi

Bir deimezin program iinde pek ok yerde kullanld durumlarda, bu deimeze


ynelik bir deitirme ilemi tek yerden yaplabilir. Bylece sz konusu program, bir
simgesel deimeze bal olarak yazlp daha sonra simgesel deimezin deitirilmesiyle
farkl parametrik deerler iin yeniden derlenerek altrlabilir. rnein kullancnn
belirli sayda tahmin yaparak bir sayy bulmasna dayanan bir oyun programn
yazdmz dnelim. Programda, oyuncu 10 tahmin hakkna sahip olsun. Bu durumda
kaynak kodun birok yerinde 10 deeri kullanlm olur, deil mi? Daha sonra oyun
programnda oyuncunun tahmin saysnn 20'ye karlmak istendiini varsayalm.
Kaynak kod iinde oyuncunun tahmin saysn gsteren 10 deimezlerinin deitirilerek
20 yaplmas gerekir. Bu deitirme ileminin programc tarafndan tek tek yaplmas hem
zor hem de hataya aktr. Kaynak kodda kullanlm olan her 10 deimezi, oyuncunun
tahmin hakkn gstermeyebilir. Oysa oyuncunun hakkn gsteren deer yerine bir
simgesel deimez tanmlanp
#define NO_OF_GUESS

10

program bu simgesel deimez kullanlarak yazlrsa, bu simgesel deimez tanmnda


yaplacak deiiklikle tm program iinde 10 deerleri kolayca 20 deerine
dntrlebilir.

Gerek Say Deimezleri Yerine Kullanlan Simgesel Deimezler

Simgesel deimezlerin kullanm, zellikle gerek say deimezlerin kullanlmasnda


olas tutarszlklar, yazm yanllarn engeller.
rnein matematiksel hesaplamalar yapan bir programda, pi saysnn sk sk
kullanldn dnelim. pi says yerine
#define PI

3.14159

simgesel deimezi kullanlabilir. Her defasnda pi says, bir deimez olarak yazlrsa,
her defasnda ayn deer yazlamayabilir. rnein kaynak kodun bir yerinde 3.14159
deimezi yazlmken kaynak kodun bir baka noktasnda yanllkla 3.15159 gibi bir
deer de yazlabilir. Derleyici programn byle tutarszlklar iin mantksal bir uyar
iletmesi olana yoktur. Simgesel deimez kullanm bu tr hatalar ortadan kaldrr.
Yine derleyicilerin ou, math.h balk dosyas iinde de pek ok matematiksel deimez
tanmlar.

Tanabilirlik Amacyla Tanmlanan Simgesel Deimezler

Baz simgesel deimezler hem tanabilirlik salamak hem de ortak arayz oluturmak
amacyla tanmlanr. Standart balk dosyalarndan limits.h iinde kullanlan tamsay
trlerinin sistemdeki snr deerlerini tayan standart simgesel deimezler
tanmlanmtr:
Simgesel
Deimez
CHAR_BIT
SCHAR_MN
SCHAR_MAX

Olabilecek En Kk
Deer
8
-127
127

UCHAR_MAX

255

Anlam
char trndeki bit says
signed char trnn en kk deeri
signed char trnn en byk
deeri
unsigned char trnn en byk
deeri

172/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

SHRT_MIN

-32.767

SHRT_MAX

32.767

USHRT_MAX

65535

INT_MIN
INT_MAX
UINT_MAX

-32.767
32.767
65.535

LONG_MIN

-2.147.483.648

LONG_MAX

-2.147.483.647

ULONG_MAX

4.294.967.295

LLONG_MIN

9.233.372.036.854.775.808

LLONG_MAX

9.233.372.036.854.775.807

ULLONG_MAX

18.446.744.073.709.551.615

CHAR_MIN

SCHAR_MIN ya da 0

CHAR_MAX

SCHAR_MAX ya da UCHAR_MAX

MB_LEN_MAX

signed short int trnn en kk


deeri
signed short int trnn en byk
deeri
unsigned short trnn en byk
deeri
signed int trnn en kk deeri
signed int trnn en byk deeri
unsigned int trnn en byk
deeri
signed long int trnn en kk
deeri
signed long int trnn en byk
deeri
unsigned long int trnn en byk
deeri
signed long long int trnn en
kk deeri (C99)
signed long long int trnn en
byk deeri (C99)
unsigned long long int trnn en
byk deeri (C99)
char trnn en kk deeri.
Sistemdeki char tr iaretliyse bu
simgesel deimezin deeri
SCHAR_MIN deerine eittir. char
tr iaretsiz ise UCHAR_MAX
deerine eittir.
char trnn en byk deeri.
Sistemdeki char tr iaretliyse bu
simgesel deimezin deeri
SCHAR_MAX deerine eittir. char
tr iaretsiz ise UCHAR_MAX
deerine eittir.
oklu byte karakterinin sahip
olabilecei en fazla byte says.
(Bu trn desteklendii lokallerde)

Simgesel Deimezlerin Tanmlanma Yerleri

#define komutu kaynak kodun herhangi bir yerinde kullanlabilir. Ancak tanmland
yerden kaynak kodun sonuna kadar olan blge iinde etki gsterir. nilemci program
dorudan bilinirlik alan kavramna sahip deildir. Bir bloun banda tanmlanan bir
simgesel deimez yalnzca o bloun iinde deil tanmland yerden kaynak kodun
sonuna kadar her yerde etkili olur.
Simgesel deimezler bazen balk dosyasnn iinde bazen de kaynak dosyann iinde
tanmlanr.

Simgesel Deimezlerin Kullanlmasnda Sk Yaplan Hatalar


Tipk bir hata, simgesel deimez tanmlamasnda gereksiz yere '=' karakterini
kullanmaktr:
#define N = 100
Bu durumda nilemci N grd yere
= 100
yazsn yaptrr. rnein

173/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

int a[N];
gibi bir tanmlama yapldn dnelim. nilemci bu tanmlamay
a[= 100];
biimine getirir ki bu da geersizdir.
#define nilemci komutu satrn yanllkla ';' atomu ile sonlandrmak bir baka tipik
hatadr.
#define N

100;

Bu durumda nilemci N grd yere


100;
yerletirir.
int a[N];
tanmlamas
int a[100;];
haline gelir. Bu tanmlama geersizdir. Bu tr hatalarda genellikle derleyici, simgesel
deimez ka yerde kullanlmsa o kadar hata iletisi verir.
Simgesel deimezlerin tanmlanmasnda dikkatli olunmaldr. nilemci modlnn
herhangi bir ekilde aritmetik ilem yapmad, yalnzca metinsel bir yer deitirme
yapt unutulmamaldr:
#define

MAX

10 + 20

int main()
{
int result;
result = MAX * 2;
printf("%d\n", result);
}

return 0;

Yukardaki rnekte result deikenine 60 deil 50 deeri atanr. Ancak nilemci komutu
#define

MAX

(10 + 20)

biiminde yazlsayd , result deikenine 60 deeri atanm olurdu.

Standart C lelerine likin Basit Makrolar

Kaynak metnin yazld ISO 646 gibi baz karakter setlerinde '&', '|', '^' karakterleri
olmadndan, baz C ilelerinin yazmnda sorun olumaktadr.
C89 standartlarna daha sonra yaplan eklemeyle dile katlan iso646 balk dosyasnda,
standart baz C ilelerine dntrlen basit makrolar tanmlanmtr. Aada bu
makrolarn listesi veriliyor:

174/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define

and
and_eq
bitand
bitor
compl
not
not_eq
or
or_eq
xor
xor_eq

&&
&=
&
|
~
!
!=
||
|=
^
^=

175/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

switch DEYM
switch deyimi bir tamsay ifadesinin farkl deerleri iin, farkl ilerin yaplmas amacyla
kullanlr. switch deyimi, zellikle else if merdivenlerine okunabilirlik ynnden bir
seenek oluturur.
Deyimin genel biimi aadaki gibidir:
switch (ifade) {
case ifade1 :
case ifade2 :
case ifade3 :
.......
case ifade_n:
default:
}
switch, case, ve default C dilinin anahtar szckleridir.

switch Deyiminin Yrtlmesi

switch ayrac iindeki ifadenin saysal deeri hesaplanr. Bu saysal deere eit deerde
bir case ifadesi olup olmad yukardan aa doru snanr. Eer byle bir case ifadesi
bulunursa programn ak o case ifadesine geirilir. Artk program buradan akarak ilerler.
switch ayrac iindeki ifadenin saysal deeri hibir case ifadesine eit deilse, eer varsa,
default anahtar szcnn bulunduu ksma geirilir.
#include <stdio.h>
int main()
{
int a;
printf("bir sayi girin : ");
scanf("%d", &a);
switch (a) {
case 1: printf("bir\n");
case 2: printf("iki\n");
case 3: printf("\n");
case 4: printf("drt\n");
case 5: printf("be\n");
}
return 0;
}
Yukardaki rnekte scanf ilevi ile, klavyeden a deikenine 1 deeri alnm olsun. Bu
durumda programn ekran kts u ekilde olur:
bir
iki

drt
be
Eer uygun case ifadesi bulunduunda yalnzca bu ifadeye ilikin deyim(ler)in
yrtlmesi istenirse break deyiminden faydalanlr. break deyiminin kullanlmasyla,
dnglerden olduu gibi switch deyiminden de klr. Daha nce verilen rnee break
deyimleri ekleniyor:

177/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
int main()
{
int a;

printf("bir sayi girin: ");


scanf("%d", &a);
switch (a) {
case 1 : printf("bir\n"); break;
case 2 : printf("iki\n"); break;
case 3 : printf("\n"); break;
case 4 : printf("drt\n"); break;
case 5 : printf("be\n");
}
return 0;

Uygulamalarda, switch deyiminde ounlukla her case ifadesi iin bir break deyiminin
kullanlr. Tabi byle bir zorunluluk yoktur.
case ifadelerini izleyen ":" atomundan sonra istenilen sayda deyim olabilir. Bir case
ifadesini birden fazla deyimin izlemesi durumunda bu deyimlerin bloklanmasna gerek
yoktur. Yani bir case ifadesini izleyen tm deyimler, bir blok iindeymi gibi ele alnr.
case ifadelerinin belirli bir sray izlemesi gibi bir zorunluluk yoktur.

default case

default bir anahtar szcktr. switch deyimi gvdesine yerletirilen default anahtar
szcn ':' atomu izler. Oluturulan bu case'e default case denir.
Edeer bir case ifadesi bulunamazsa programn ak default case iine girer.
Daha nce yazlan switch deyimine default case ekleniyor.
#include <stdio.h>
int main()
{
int a;

printf("bir sayi girin: ");


scanf("%d", &a);
switch (a) {
case 1 : printf("bir\n"); break;
case 2 : printf("iki\n"); break;
case 3 : printf("\n"); break;
case 4 : printf("drt\n"); break;
case 5 : printf("drt\n"); break;
default: printf("hibiri\n");
}
return 0;

Yukarda da anlatld gibi switch ayrac iindeki ifadenin saysal deerine eit bir case
ifadesi bulunana kadar derleme ynnde, yani yukardan aaya doru, tm case
ifadeleri srasyla snanr. case ifadelerinin oluma skl ya da olasl hakknda elde bir
bilgi varsa, olasl ya da skl yksek olan case ifadelerinin daha nce yazlmas
gereksiz karlatrma saysn azaltabilir.

178/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

case ifadelerinin, tamsay trnden (integral types) deimez ifadesi olmas gerekir.
Bilindii gibi deimez ifadeleri, derleme aamasnda derleyici tarafndan net saysal
deerlere dntrlebilir:
case 1 + 3:

/* Geerli */

mmkn nk 1 + 3 deimez ifadesi ama ,


case x + 5:

/* Geersiz */

nk deimez ifadesi deil. Derleyici, derleme aamasnda saysal bir deer


hesaplayamaz.
case 'a' :
Yukardaki case ifadesi geerlidir. 'a' bir karakter deimezidir. case ifadesi tamsay
trnden bir deimez ifadesidir.
case 3.5 :
Yukardaki case ifadesi geersizdir. 3.5 bir gerek say deimezidir.
switch kontrol deyimi yerine bir else if merdiveni yazlabilir. Yani switch deyimi
olmasayd, yaplmak istenen i, bir else if merdiveni ile de yaplabilirdi. Ancak baz
durumlarda else if merdiveni yerine switch deyimi kullanmak okunabilirlii artrr.
rnein:
if (a == 1)
deyim1;
else if (a == 2)
deyim2;
else if (a == 3)
deyim3;
else if (a == 4)
deyim4;
else
deyim5;
Yukardaki else if merdiveni ile aadaki switch deyimi ilevsel olarak edeerdir:
switch (a) {
case 1 :
case 2 :
case 3 :
case 4 :
default:
}

deyim1;
deyim1;
deyim1;
deyim1;
deyim5;

break;
break;
break;
break;

Her switch deyiminin yerine ayn ii grecek ekilde bir else if merdiveni yazlabilir ama
her else if merdiveni bir switch deyimiyle karlanamaz. switch ayrac iindeki ifadenin bir
tamsay trnden olmas zorunludur. case ifadeleri de tamsay trlerinden deimez
ifadesi olmak zorundadr. switch deyimi, tamsay trnden bir ifadenin deerinin deiik
tamsay deerlerine eitliinin snanmas ve eitlik durumunda farkl ilerin yaplmas iin
kullanlr. Oysa else if merdiveninde her trl karlatrma sz konusu olabilir. rnek:

179/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

if (x >
m =
else if
m =
else if
m =
else
m =

20)
5;
(x > 30 && x < 55)
3;
(x > 70 && x < 90)
7;
2;

Yukardaki else if merdiveninin yerine bir switch deyimi yazlamaz.


switch deyimi baz durumlarda else if merdivenine gre ok daha okunabilir bir yap
oluturur, yani switch deyiminin kullanlmas, hereyden nce, kodun daha kolay
okunabilmesini, anlamlandrlmasn salar.
Birden fazla case ifadesi iin ayn ilemlerin yaplmas yle salanabilir.
case 1:
case 2:
case 3:
deyim1;
deyim2;
break;
case 4:
Bunu yapmann daha ksa bir yolu yoktur. Baz programclar kaynak kodun yerleimini
aadaki gibi dzenlerler:
case 1: case 2: case 3: case 4: case 5:
deyim1; deyim2;
Aadaki program nce inceleyin, sonra derleyerek altrn:
void print_season(int month)
{
switch (month) {
case 12:
case 1 :
case 2 : printf("winter"); break;
case 3 :
case 4 :
case 5 : printf("spring"); break;
case 6 :
case 7 :
case 8 : printf("summer"); break;
case 9 :
case 10:
case 11: printf("autumn");
}
}
print_season ilevi, bir ayn sra numarasn, yani yln kanc ay olduu bilgisini alyor,
bu ay yln hangi mevsimi iinde ise, o mevsimin ismini ekrana yazdryor. Ayn i bir else
if merdiveniyle nasl yaplabilirdi? Her if deyiminin koul ifadesi iinde mantksal veya
ileci kullanlabilirdi:

180/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

void print_season(int month)


{
if (month == 12 || month == 1 || month == 2)
printf("winter");
else if (month == 3 || month == 4 || month == 5)
printf("spring");
else if (month == 6 || month == 7 || month == 8)
printf("summer");
else if (month == 9 || month == 10 || month == 11)
printf("autumn");
}
Simgesel deimezler, derleme ileminden nce nilemci tarafndan deitirilecei iin,
case ifadelerinde yer alabilir:
#define TRUE
#define FALSE
#define UNDEFINED

1
0
2

case TRUE
:
case FALSE
:
case UNDEFINED :
Yukardaki case ifadeleri geerlidir.
case ifadeleri olarak karakter deimezleri de kullanlabilir:
#include <stdio.h>
int main()
{
switch (getchar()) {
case '0': printf("sfr\n"); break;
case '1': printf("bir\n"); break;
case '2': printf("iki\n"); break;
case '3': printf("\n"); break;
case '4': printf("drt\n"); break;
case '5': printf("be\n"); break;
default : printf("gecersiz!\n");
}
return 0;
}
case ifadelerini izleyen deyimlerin 15 - 20 satrdan uzun olmas okunabilirlii zayflatr.
Bu durumda yaplacak ilemlerin ilev arlarna dntrlmesi iyi bir tekniktir.
switch (x) {
case ADDREC:
addrec();
break;
case DELREC:
delrec();
break;
case FINDREC:
findrec();
break;
}

181/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yukardaki rnekte case ifadesi olarak kullanlan ADDREC, DELREC, FINDREC daha nce
tanmlanm simgesel deimezlerdir. Her bir case iin yaplan ilemler, birer ilev iinde
sarmalanyor.
char ch = getch();
switch (ch) {
case 'E' : deyim1; break;
case 'H' : deyim2; break;
default : deyim3;
}
Bir switch deyiminde ayn saysal deere sahip birden fazla case ifadesi olamaz. Bu
durum derleme zamannda hata oluturur.
switch deyimi, baka bir switch deyiminin ya da bir dng deyiminin gvdesini
oluturabilir:
#include <stdio.h>
#include <conio.h>
#define

ESC

0X1B

int main()
{
int ch;

while ((ch = getch()) != ESC)


switch (rand() % 7 + 1) {
case 1: printf("Pazartesi\n"); break;
case 2: printf("Sali\n"); break;
case 3: printf("Carsamba\n"); break;
case 4: printf("Persembe\n"); break;
case 5: printf("Cuma\n"); break;
case 6: printf("Cumartesi\n"); break;
case 7: printf("Pazar\n");
}
return 0;

Yukardaki main ilevinde switch deyimi, dtaki while dngsnn gvdesini oluturuyor.
switch deyimi, dng gvdesindeki tek bir deyim olduundan, dtaki while dngsnn
bloklanmasna gerek yoktur. Tabi while dngsnn bloklanmas bir hataya neden olmaz.
Ancak case ifadeleri iinde yer alan break deyimiyle yalnzca switch deyiminden klr.
while dngsnn de dna kmak iin case ifadesi iinde goto deyimi kullanlabilir.
imdi de aadaki program inceleyin. Programda display_date isimli bir ilev
tanmlanyor. lev gn, ay ve yl deeri olarak ald bir tarih bilgisini ngilizce olarak
aadaki formatta ekrana yazdryor:
5th Jan 1998
include <stdio.h>
void display_date(int day, int month, int year)
{
printf("%d", day);

182/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

switch (day) {
case 1 :
case 21 :
case 31 : printf("st
case 2 :
case 22 : printf("nd
case 3 :
case 23 : printf("rd
default : printf("th
}

switch (month) {
case 1 : printf("Jan
case 2 : printf("Feb
case 3 : printf("Mar
case 4 : printf("Apr
case 5 : printf("May
case 6 : printf("Jun
case 7 : printf("Jul
case 8 : printf("Aug
case 9 : printf("Sep
case 10: printf("Oct
case 11: printf("Nov
case 12: printf("Dec
}
printf("%d", year);

"); break;
"); break;
"); break;
");

");
");
");
");
");
");
");
");
");
");
");
");

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

int main()
{
int day, month, year;
int n = 20;

while (n-- > 0) {


printf("gun ay yil olarak bir tarih girin : ");
scanf("%d%d%d", &day, &month, &year);
display_date(day, month, year);
putchar('\n');
}
return 0;

levin tanmnda iki ayr switch deyimi kullanlyor. lk switch deyimiyle, gn deerini
izleyen (th, st, nd, rd) sonekleri yazdrlrken, ikinci switch deyimiyle, aylara ilikin
ksaltmalar (Jan, Feb. Mar.) yazdrlyor.
case ifadelerini izleyen deyimlerden biri break deyimi olmak zorunda deildir. Baz
durumlarda break deyimi zellikle kullanlmaz, uygun bir case ifadesi bulunduunda daha
aadaki case lerin iindeki deyimlerin de yaplmas zellikle istenir. Aadaki program
derleyerek altrn:
#include <stdio.h>
int isleap(int y)
{
return y % 4 == 0 && (y % 100 != 0 || y % 400 == 0);
}
int day_of_year(int day, int month, int year)
{
int sum = day;
183/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

switch (month - 1) {
case 11: sum += 30;
case 10: sum += 31;
case 9 : sum += 30;
case 8 : sum += 31;
case 7 : sum += 31;
case 6 : sum += 30;
case 5 : sum += 31;
case 4 : sum += 30;
case 3 : sum += 31;
case 2 : sum += 28 + isleap(year);
case 1 : sum += 31;
}
return sum;

int main()
{
int day, month, year;
int n = 5;
while (n-- > 0) {
printf("gun ay yil olarak bir tarih girin : ");
scanf("%d%d%d", &day, &month, &year);
printf("%d yilinin %d. gunudur!\n", year, day_of_year(day, month,
year));
}
}

return 0;

day_of_year ilevi dardan gn, ay ve yl deeri olarak gelen tarih bilgisinin ilgili yln
kanc gn olduunu hesaplayarak bu deerle geri dnyor. lev iinde kullanlan
switch deyimini dikkatli bir ekilde inceleyin. switch deyiminin ayrac iinde, dardan
gelen ay deerinin 1 eksii kullanlyor. Hibir case iinde bir break deyimi kullanlmyor.
Uygun bir case ifadesi bulunduunda, daha aada yer alan tm case iindeki deyimler
de yaplr. Bylece, dardan gelen ay deerinden daha dk olan her bir ayn ka
ektii bilgisi, gn toplamn tutan sum deikenine katlyor.

184/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

goto DEYM
Dier programlama dillerinde olduu gibi C dilinde de programn ak, bir koula bal
olmakszn kaynak kod iinde baka bir noktaya ynlendirilebilir. Bu, C dilinde goto
deyimi ile yaplr:
goto deyiminin genel szdizimi aadaki gibidir:
<goto etiket;>
....
<etiket:>
<deyim;>
goto, C dilinin 32 anahtar szcnden biridir. Etiket (label), programcnn verdii bir
isimdir. phesiz isimlendirme kurallarna uygun olarak seilmelidir. Programn ak, bu
etiketin yerletirilmi olduu yere ynlendirilir. Etiket, goto anahtar szcnn
kullanld ilev iinde herhangi bir yere yerletirilebilir. Etiket isminden sonra ':' atomu
yer almak zorundadr. Etiketi izleyen deyim de goto kontrol deyiminin szdiziminin bir
parasdr. Etiketten sonra bir deyimin yer almamas bir szdizim hatasdr.
Etiketin goto anahtar szcnden daha sonraki bir kaynak kod noktasna yerletirilmesi
zorunluluu yoktur. Etiket goto anahtar szcnden nce de tanmlanm olabilir:
#include <stdio.h>
int main()
{
/***/
goto GIT;
/***/
GIT:
printf("goto deyimi ile buraya gelindi\n");
}

return 0;

Yukardaki programda, etiket goto anahtar szcnden daha sonra yer alyor.
int main()
{
GIT:
printf("goto deyimi ile gelinecek nokta\n");
/***/
goto GIT;
/***/
}

return 0;

Yukardaki programda, etiket goto anahtar szcnden daha nce yer alyor.
goto etiketleri, geleneksel olarak byk harf ile, birinci stuna dayal olarak yazlr.
Bylece kaynak kod iinde daha fazla dikkat ekerler.
goto etiketleri bir ilev iinde, bir deyimden nce herhangi bir yere yerletirilebilir. Yani
etiket, ayn ilev iinde bulunmak kouluyla, goto anahtar szcnn yukarsna ya da
aasna yerletirilebilir. Bu zelliiyle goto etiketleri, yeni bir bilinirlik alan kural
oluturur. Bir isim, ilev iinde nerede tanmlanrsa tanmlansn o ilev iinde her yerde
bilinir. Bu bilinirlik alan kuralna "ilev bilinirlik alan" (function scope) denir.

185/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

goto etiketleri bulunduu bloun isim alanna eklenmez. goto etiket isimleri ayr bir isim
alannda deerlendirilir. Bir blok iindeki goto etiketi ile ayn isimli bir yerel deiken
olabilir:
void func()
{
int x;
goto x;
x:
x = 20;
}
Yapsal programlama tekniinde goto deyiminin kullanlmas nerilmez. nk goto
deyiminin kullanlmas bir takm sakncalar dourur:
1. goto deyimi programlarn okunabilirliini bozar. Kodu okuyan kii goto deyimiyle
karlatnda ilevin iinde etiketi arayp bulmak zorunda kalr ve program bu noktadan
okumay srdrr.
2. goto deyimlerinin kullanld bir programda bir deiiklik yaplmas ya da programn,
yaplacak eklemelerle, gelitirilmeye allmas daha zor olur. Programn herhangi bir
yerinde bir deiiklik yaplmas durumunda, eer program iinde baka yerlerden
deiikliin yapld yere goto deyimleri ile srama yaplm ise, bu noktalarda da bir
deiiklik yaplmas gerekebilir. Yani goto deyimi program paralarnn birbirine olan
bamlln artrr, bu da genel olarak istenen bir ey deildir.
Bu olumsuzluklara karn, baz durumlarda goto deyiminin kullanlmas programn
okunabilirliini bozmak bir yana, dier seeneklere gre daha okunabilir bir yapnn
olumasna yardmc olur:
ie birden fazla dng varsa, ve iteki dnglerden birindeyken, yalnzca bu dngden
deil, btn dnglerden birden klmak isteniyorsa goto deyimi kullanlmaldr.
Aadaki kod parasnda i ie dng bulunuyor. En iteki dngnn iinde func ilevi
arlarak ilevin geri dn deeri snanyor. lev eer 0 deerine geri dnerse
programn ak goto deyimiyle tm dnglerin dna ynlendiriliyor:
#include <stdio.h>
int test_func(int val);
int main()
{
int i, j, k;
for (i = 0; i < 100; ++i) {
for (j = 0; j < 100; ++j) {
for (k = 0; k < 20; ++k) {
/*...*/
if (!test_func(k))
goto BREAK;
/*...*/
}
}
}
BREAK:
printf("dng dndaki ilk deyim\n");
return 0;
}

186/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yukardaki ilev iinde i ie ayr dng deyimi yer alyor. En iteki dngnn iinde
arlan bir ilev ile bir snama ilemi yaplm, snamann olumsuz sonulanmas
durumunda, programn ak en dtaki dng deyiminin sonrasna ynlendiriliyor.
Oysa goto deyimi kullanmasayd, ancak bir bayrak (flag) deikenin kullanlmasyla ayn
ama gerekletirilebilirdi. Her dngnn knda bayrak olarak kullanlan deikenin
deerinin deitirilip deitirilmedii snanmak zorunda kalnrd.
#include <stdio.h>
#define
#define

BREAK
NO_BREAK

0
1

int test_func(int val);


int main()
{
int i, j, k;
int flag = NO_BREAK;
for (i = 0; i < 100; ++i) {
for (j = 0; j < 100; ++j) {
for (k = 0; k < 20; ++k) {
/*...*/
if (!test_func(k)) {
flag = BREAK;
break;
}
/*...*/
}
if (flag == BREAK)
break;
}
if (flag == BREAK)
break;
}
printf("dng dndaki ilk deyim\n");
}

return 0;

goto deyiminin kullanlmas okunabilirlik ynnden daha iyidir.


Aadaki rnekte ise goto deyimiyle hem switch deyiminden hem de switch deyiminin
iinde bulunduu for dngsnden klyor:
#define
#define
#define
#define
#define

ADDREC
LISTREC
DELREC
SORTREC
EXITPROG

1
2
3
4
5

int get_option(void);
void add_rec(void);
void list_rec(void);
void del_rec(void);
void sort_rec(void);
int main()
{
int option;
187/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

for (;;) {
option = get_option();
switch (option) {
case ADDREC
:add_rec();break;
case LISTREC
:list_rec();break;
case DELREC
:del_rec(); break;
case SORTREC
:sort_rec(); break;
case EXITPROG :goto EXIT;
}
}
EXIT:
return 0;
}
Yukardaki main ilevinde option deikeninin deeri EXITPROG olduunda programn
ak, goto deyimiyle sonsuz dngnn dna gnderiliyor. goto deyimi yerine break
deyimi kullanlsayd, yalnzca switch deyiminden klm olurdu.
goto deyimiyle, bir ilevin iindeki bir noktadan, yine kendi iindeki bir baka noktaya
srama yaplabilir. Byle sramalara yerel sramalar (local jumps) denir. Bir ilevin
iinden baka bir ilevin iine sramak baka aralarla mmkndr. Byle sramalara
yerel olmayan sramalar (non-local jumps) denir. C dilinde, yerel olmayan sramalar
ismi setjmp ve longjmp olan standart ilevlerle yaplr. Bu sramalar ounlukla "Olaan
d hatalarn ilenmesi" (exception handling) amacyla kullanlr.

188/529

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

RASTGELE SAYI RETM ve KONTROL


DEYMLERNE LKN GENEL UYGULAMALAR
Rastgele say retimi matematiin nemli konularndan biridir. Rastgele saylar ya da
daha doru ifadeyle, rastgele izlenimi veren saylar (szde rastgele saylar - pseudo
random numbers) istatistik, ekonomi, matematik, yazlm gibi pek ok alanda kullanlr.
Rastgele saylar bir rastgele say reticisi (random number generator) tarafndan retilir.
Rastgele say reticisi aslnda matematiksel bir ilevdir. Sz konusu ilev, bir balang
deerini alarak bir deer retir. Daha sonra retmi olduu her deeri yeni girdi olarak
alr, yeniden bir say retir. reticinin rettii saylar rastgeledir.

rand levi

Standart rand ilevi rastgele say retir. Bu ilevin bildirimi aadaki gibidir:
int rand(void);
C standartlar rand ilevinin rastgele say retimi konusunda kullanaca algoritma ya da
teknik zerinde bir koul koymamtr. Bu konu derleyiciyi yazanlarn seimine bal
(implementation dependent) braklmtr. rand ilevinin bildirimi, standart bir balk
dosyas olan stdlib.h iindedir. Bu yzden rand ilevinin arlmas durumunda bu balk
dosyas "include" nilemci komutuyla kaynak koda eklenmelidir.
#include <stdlib.h>
rand ilevi her arldnda [0, RAND_MAX] aralnda rastgele bir tamsay deerini geri
dndrr. RAND_MAX stdlib.h balk dosyas iinde tanmlanan bir simgesel deimezdir.
C standartlar bu simgesel deimezin en az 32767 deerinde olmasn art komaktadr.
Derleyicilerin hemen hepsi RAND_MAX simgesel deimezini 32767 olarak, yani 2 byte
iaretli int trnn en byk deeri olarak tanmlar:
#define

RAND_MAX

32767

Aadaki program parasnda, 0 ile RAND_MAX arasnda 10 adet rastgele say retilerek
ekrana yazdrlyor. Program derleyerek altrn:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int k;
for (k = 0; k < 10; ++k)
printf("%d ", rand());
return 0;
}
Yukardaki kaynak kodla oluturulan programn her altrlmasnda ekrana ayn saylar
yazlr. rnein yukardaki program, DOS altnda Borland Turbo C 2.0 derleyicisi ile
derleyip altrldnda ekran kts aadaki gibi oldu:
346 130 10982 1090

11656

7117

17595

6415

22948

31126

189

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

srand levi

Oluturulan program her altrldnda neden hep ayn say zinciri elde ediliyor? rand
ilevi rastgele say retmek iin bir algoritma kullanyor. Bu algoritma derleyiciden
derleyiciye deise de, rastgele say retiminde kullanlan ana tema ayndr. Bir balang
deeri ile ie balanr. Buna tohum deeri (seed value) denir. Bu deer zerinde baz
ilemler yaplarak rastgele bir say elde edilir. Tohum deer zerinde yaplan ilem bu kez
elde edilen rastgele say zerinde yinelenir.
rand ilevi arlarn ieren bir program her altrldnda ayn tohum deerinden
balanaca iin ayn say zinciri elde edilir.
Bir baka standart ilev olan srand ilevi, rastgele say reticisinin tohum deerini
deitirmeye yarar. srand ilevinin stdlib.h balk dosyasnda yer alan bildirimi aadaki
gibidir:
void srand (unsigned seed);
srand ilevine gnderilen deer, ilev tarafndan rastgele say reticisinin tohum deeri
yaplr. srand ilevine argman olarak baka bir tohum deeri gnderildiinde ilevin
rettii rastgele say zinciri deiir.
Aada rand ve srand ilevleri tanmlanyor:
#define

RAND_MAX

32767

unsigned long int next = 1;


int rand()
{
next = next * 1103515245 + 12345;
return (unsigned int)(next / 65536) % 32768;
}
void srand(unsigned int seed)
{
next = seed;
}
srand ilevi arlmaz ise balang tohum deeri 1'dir.
Yukardaki programa srand ilevi arsn ekleyerek yeniden derleyin, altrn:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int k;
srand(100);
for (k = 0; k < 10; ++k)
printf("%d ", rand());
}

return 0;

Program bu ekliyle DOS altnda Borland Turbo C 2.0 derleyicisi ile derleyip
altrldnda ekran kts aadaki gibi oldu:
1862

11548

3973

4846

9095

16503

6335

13684

21357

21505

190

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Ancak bu kez oluturulan program da her altrldnda yine yukardaki say zinciri elde
edilir, deil mi? rand ilevinin kullanmakta olduu nceden seilmi (default) tohum
deeri kullanlmasa da, bu kez her defasnda srand ilevine gnderilmi olan tohum
deeri kullanlr. Program birka kere altrp gerekten hep ayn say zincirinin retilip
retilmediini grn.
Baz durumlarda, programn her altrlmasnda ayn rastgele say zincirinin retilmesi
istenmez. rnein bir oyun programnda programn altrlmasyla hep ayn saylar
retilirse, oyun hep ayn biimde oynanr. Programn her almasnda farkl bir say
zincirinin elde edilmesi iin, srand ilevinin rastgele say reticisinin tohum deerini
programn her almasnda baka bir deer yapmas gerekir. Bu amala ou zaman
standart time ilevi ilevinden faydalanlr.
time standart bir C ilevidir, bildirimi standart bir balk dosyas olan time.h dosyas
iindedir. Parametre deikeni gsterici olan time ilevini, ancak ileride ayrntl olarak ele
alacaz. imdilik time ilevini iimizi grecek kadar inceleyeceiz. time ilevi kendisine 0
deeri gnderildiinde, nceden belirlenmi bir tarihten (sistemlerin ounda 01.01.1970
tarihinden) ilevin arld ana kadar geen saniye saysn geri dndrr. levin geri
dn deeri, derleyicilerin ounda long trden bir deerdir. inde rastgele say
retilecek programda, srand ilevine argman olarak time ilevinin geri dn deeri
gnderilirse, program her altnda, belirli bir zaman gemesi nedeniyle, rastgele say
reticisi baka bir tohum deeriyle ilkdeerini alr. Bylece programn her
altrlmasnda farkl say zinciri retilir:
srand(time(0));
srand ilevine yaplan bu ar, derleyicilerin ounda standart olmayan randomize isimli
bir makro olarak tanmlanmtr:
randomize();
Yukardaki ilev ars yerine bu makro da kullanlabilir. Makrolar konusu ileride ayrntl
olarak ele alnacak.
Yukardaki daha nce yazlan rnek program her altnda farkl say zinciri retecek
duruma getirelim:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
int k;
srand(time(0));
for (k = 0; k < 10; ++k)
printf("%d ", rand());
return 0;
}
Programlarda bazen belirli bir aralkta rastgele say retilmesi istenir. Bu amala kalan
ileci kullanlabilir. Aadaki ifadeleri inceleyin:
rand() % 2
Yalnzca 0 ya da 1 deerini retir.

191

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

rand() % 6
0 - 5 aralnda rastgele bir deer retir
rand() % 6 + 1
1 - 6 aralnda rastgele bir deer retir. (rnein bir zar deeri)
rand() % 6 + 3
3 - 8 aralnda rastgele bir deer retir.
Ancak derleyici programlarn salad rastgele say reticilerinin rettikleri rastgele
saylarn, dk anlaml bitleri ounlukla rastgele kabul edilemez. Bu durumda
yukardaki ifadeler, retilmesi gereken tm saylar iin eit bir dalm salamaz.
Dalmn daha dzgn olabilmesi iin baz yntemler kullanlabilir:
rand() % N
ifadesi yerine
rand()/(RAND_MAX / N + 1)
ya da
(int)((double)rand() / ((double)RAND_MAX + 1) * N)
ifadeleri yazlabilir.
Ya da aadaki gibi bir ilev tanmlanabilir:
#include <stdio.h>
#include <stdlib.h>
#define

10

int mrand()
{
unsigned int x = (RAND_MAX + 1u) / N;
unsigned int y = x * N;
unsigned int r;

while ((r = rand()) >= y)


;
return r / x;

srand(time(0)) arsnn bir dng iinde yer almas sk yaplan bir hatadr.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int zar_at()
{
srand(time(0));
return rand() % 6 + 1 +
}

rand() % 6 + 1;

192

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

int main()
{
int k;
for (k = 0; k < 10; ++k)
printf("%d\n", zar_at());
}

return 0;

Yukarda yazlan programda yer alan zar_at isimli ilev, bir ift zar atldnda elde iki
zarn toplam deeriyle geri dnyor. srand(time(0)) ars zar_at ilevi iinde yaplyor.
main ilevi iinde oluturulan for dngsyle 10 kez zar_at ilevi arlyor. levin her
arsnda time ilevi hep ayn geri dn deerini retir. Bu durumda srand ilevine hep
ayn argman geildiinden rand ilevi arlar da hep ayn iki sayy retir. Yani ekrana
10 kez ayn deer yazdrlr. srand(time(0)) arsnn main ilevi iindeki for
dngsnden nce yaplmas gerekirdi, deil mi?
Aadaki main ilevinde uzunluklar 3 - 8 harf arasnda deien ngiliz alfabesindeki
harfler ile oluturulmu rastgele 10 szck ekrana yazdrlyor:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define
#define
#define

TIMES
MIN_WORD_LEN
MAX_WORD_LEN

10
3
8

void write_word(void)
{
int len = rand() % (MAX_WORD_LEN - MIN_WORD_LEN + 1) + MIN_WORD_LEN;

while (len--)
putchar('A' + rand() % 26);

int main()
{
int k;

srand(time(0));
for (k = 0; k < TIMES; ++k) {
write_word();
putchar('\n');
}
return 0;

Aada bu kez yazdrlan szcklerin iinde sesli harf olmamas salanyor:


int isvowel(int c)
{
return c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U';
}
void write_word(void)
{
int len = rand() % (MAX_WORD_LEN - MIN_WORD_LEN + 1) + MIN_WORD_LEN;
int ch;

193

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

while (len--) {
while (isvowel(ch = rand() % 26 + 'A'))
;
putchar(ch);
}

Aada rastgele bir tarihi ekrana yazdran print_random_date isimli bir ilev
tanmlanyor. lev her arldnda 1.1.MIN_YEAR, 31.12.MAX_YEAR tarihleri arasnda
rastgele ancak geerli bir tarih bilgisini ekrana yazyor:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define
#define

MAX_YEAR
MIN_YEAR

2010
1900

void print_random_date()
{
int d, m, y;

y = rand() % (MAX_YEAR - MIN_YEAR + 1) + MIN_YEAR;


m = rand() % 12 + 1;
switch (m) {
case 4 : case 6 : case 9 : case 11:
d = rand() % 30 + 1; break;
case 2 : d = rand() % (isleap(y) ? 29 : 28) + 1; break;
default: d = rand() % 31 + 1;
}
printf("%d/%d/%d\n", d, m, y);

int isleap(int y)
{
return y % 4 == 0 && y % 100 != 0 || y % 400 == 0;
}
int main()
{
int k;
srand(time(0));
for (k = 0; k < 20; ++k)
print_random_date();
}

return 0;

Olaslk problemleri, olasla konu olayn bir bilgisayar program ile gerekletirilmesi
yoluyla zlebilir. yi bir rastgele say reticisi kullanld takdirde, olasla konu olay,
bir bilgisayar program ile oynatlr, olay bilgisayarn ilem yapma hzndan faydalanlarak
yksek saylarda yinelemeye sokulur. phesiz hesaplanmak istenen olaya ilikin olaslk
deeri, yaplan yineleme saysna ve rastgele say reticisinin niteliine bal olur.
Aadaki kod yaz tura atlmas olaynda tura gelme olasln hesaplyor:

194

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

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

TIMES
HEADS

30000
1

int main()
{
int heads_counter = 0;
int k;
srand(time(0));
for (k = 0; k < TIMES; ++k)
if (rand() % 2 == HEADS)
heads_counter++;
printf("tura gelme olasl = %lf", (double) heads_counter / TIMES);
}

return 0;

Yukardaki program TIMES simgesel deimezinin farkl deerleri iin altrldnda


ekran kts aadaki ekilde oldu:
#define
tura gelme
#define
tura gelme
#define
tura gelme
#define
tura gelme
#define
tura gelme
#define
tura gelme
#define
tura gelme

TIMES
100
olasl = 0.480000
TIMES
500
olasl = 0.496000
TIMES
2500
olasl = 0.506800
TIMES
10000
olasl = 0.503500
TIMES
30000
olasl = 0.502933
TIMES
100000
olasl = 0.501450
TIMES
1000000
olasl = 0.500198

Aada bir baka olaslk almas yaplyor:


Craps hemen hemen dnyann her yerinde bilinen, iki zarla oynanan bir kumardr.
Oyunun kurallar yledir :
Zarlar atacak oyuncu oyunu kasaya kar oynar. Atlan iki zarn toplam deeri 7 ya da 11
ise oyuncu kazanr. Atlan iki zarn toplam deeri 2, 3, 12 ise oyuncu kaybeder. (Buna
craps denir!)
ki zarn toplam deeri yukardakilerin dnda bir deer ise (yani 4, 5, 6, 8, 9, 10) oyun
u ekilde srer :
Oyuncu ayn sonucu buluncaya kadar zarlar tekrar atar. Eer ayn sonucu bulamadan
nce oyuncu 7 atarsa (yani atlan iki zarn toplam deeri 7 olursa) oyuncu kaybeder.
Eer 7 gelmeden nce oyuncu ayn sonucu tekrar atmay baarrsa , kazanr.
Birka rnek :
Oyuncunun att zarlar
11
3
9 8 6 3 12 5 8 4 2 4 9
6 5 8 9 2 3 7
7
10 4 8 11 8 3 6 5 4 9 10

Oyun sonucu
Oyuncu kazanr
Oyuncu kaybeder
Oyuncu kazanr
Oyuncu kaybeder
Oyuncu kazanr
Oyuncu kazanr

195

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Aadaki program, bu oyunu oynayan oyuncunun kazanma olasln hesaplyor:


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

NKEZ

1000000

int zar_at()
{
int zar1 = rand() % 6 + 1;
int zar2 = rand() % 6 + 1;
return zar1 + zar2;
}
/* oyuncu kazanrsa 1 deerine, oyuncu kaybederse 0 deerine geri dner */
int oyun()
{
int zar_toplam;
zar_toplam = zar_at();
switch (zar_toplam) {
case 7 :
case 11: return 1;
case 2 :
case 3 :
case 12: return 0;
}
return oyun_devami(zar_toplam);
}
/* oyuncu 4, 5, 6, 8, 9, 10 atmissa oyunun devam.
oyuncu kazanrsa 1 deerine, oyuncu kaybederse 0 deerine geri dner */
int oyun_devami(int zar_toplam)
{
int yeni_zar;
for (;;) {
yeni_zar = zar_at();
if (yeni_zar == zar_toplam)
return 1;
if (yeni_zar == 7)
return 0;
}
}
int main()
{
int k;
int kazanma_sayisi = 0;
srand(time(0));
for (k = 0; k < NKEZ; ++k)
kazanma_sayisi += oyun();
printf("kazanma olasiligi = %lf\n", (double)kazanma_sayisi / NKEZ);
}

return 0;

196

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Rastgele Gerek Say retimi

Rastgele gerek say reten bir standart C ilevi yoktur. Ancak RAND_MAX simgesel
deimezinden faydalanarak
(double)rand() / RAND_MAX
ifadesi ile 0 1 aralnda rastgele bir gerek say retilebilir. Aada rastgele gerek
say reten drand isimli bir ilev tanmlanyor. levi inceleyerek, rastgele bir gerek
sayy nasl rettiini anlamaya aln:
#define

PRECISION

2.82e14

double drand()
{
double sum = 0;
double denom = RAND_MAX + 1;
double need;

for (need = PRECISION; need > 1; need /= (RAND_MAX + 1.)) {


sum += rand() / denom;
denom *= RAND_MAX + 1.;
}
return sum;

int main()
{
int k;
for (k = 0; k < 10; ++k)
printf("%lf\n", drand());
return 0;
}
Aada pi says Monte Carlo yntemi diye bilinen yntemle bulmaya allyor. Bu
yntemde birim kare iinde yarap karenin kenar uzunluuna eit bir daire paras
olduu dnlr. Birim kare iinde rastgele alnan bir nokta, ya daire parasnn iinde
ya da dnda olur. Rastgele alnan bir noktann daire parasnn iinde olma olasl,
yarap 1 birim olan bir dairenin alannn drtte birinin, kenar 1 birim olan karenin
alanna orandr. Bu da

deerine eittir. O zaman n tane rastgele nokta alp bu


4

noktalarn ka tanesinin dairenin iinde olduunu bulursak, bu deerin n saysna orannn


4 kat saysn verir:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define

NTIMES

10000000

int main()
{
double x, y;
int k;
int inside_counter = 0;
srand(time(0));
for (k = 0; k < NTIMES; ++k) {
x = (double)rand() / RAND_MAX;

197

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

y = (double)rand() / RAND_MAX;
if (x * x + y * y <= 1)
inside_counter++;

}
printf("hesaplanan pi degeri = %lf\n", 4. * inside_counter / NTIMES);
return 0;
}

198

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

DZLER
Veri Yaps Nedir

Bir konuyla ilgili, mantksal iliki iindeki verilerin bellekte saklanmasna ynelik
dzenlemelere veri yaps denir. Veri yaplar bellekte belirli bir dzen iinde tutulmu
verilere ulalabilmesine, bu veriler zerinde baz ilemlerin etkin bir biimde yaplmasna
olanak salar.

Dizi Nedir

Bellekte bitiik bir biimde bulunan, ayn trden nesnelerin oluturduu veri yapsna dizi
(array) denir. Dizi veri yapsnn en nemli zellii, mantksal bir iliki iindeki ayn trden
verilerin bellekte bitiik (contigous) olarak tutulmasdr. Bunun da uygulamalarda
salad fayda udur: Dizinin bir elemanna, elemann konum bilgisiyle deimez bir
zamanda ulalabilir. Yani dizinin eleman says ne olursa olsun, konumu bilinen bir
elemana ulam zaman ayndr. Bu da baz uygulamalarn etkin bir ekilde
gerekletirilmesini kolaylatrr.

C Dilinde Diziler

C dilinde dizi (array), ayn trden bir ya da daha fazla nesnenin bellekte dizi veri yaps
biiminde tutulmasn salayan aratr.
C'de bir dizinin tanmlanmasyla birden fazla sayda nesne tek bir deyimle tanmlanabilir.
10 elemana sahip bir dizi tanmlamak yerine, phesiz isimleri farkl 10 ayr nesne de
tanmlanabilir. Ama 10 ayr nesne tanmlandnda bu nesnelerin bellekte bitiik olarak
yerlemeleri gvence altna alnm bir zellik deildir. Oysa dizi tanmlamasnda, dizinin
eleman olan btn nesnelerin bellekte bitiik olarak yer almalar gvence altna alnm
bir zelliktir. Dizi de bir veri tr olduuna gre, dizilerin de kullanlmalarndan nce
tanmlanmalar gerekir.

Dizilerin Tanmlanmas

Dizi tanmlamalarnn genel biimi:


<tr> <dizi ismi> [<eleman says>];
Yukardaki genel biimde keli ayra, eleman saysnn seimlik olduunu deil, eleman
says bilgisinin keli ayra iine yazlmas gerektiini gsteriyor.
tr
dizi ismi
eleman says

: Dizi elemanlarnn trn gsteren anahtar szcktr.


: simlendirme kurallarna uygun olarak verilecek herhangi bir isimdir.
: Dizinin ka elemana sahip olduunu gsterir.

rnek dizi bildirimleri:


double a[20];
int ave[10];
char path[80];
Yukardaki tanmlamalarda
a, 20 elemanl, her bir eleman double trden olan bir dizidir.
ave, 10 elemanl, her bir eleman int trden olan bir dizidir.
path, 10 elemanl, her bir eleman char trden olan bir dizidir.
Tanmlamada yer alan, eleman says belirten ifadenin bir tamsay trnden deimez
ifadesi olmas zorunludur. Bir baka deyile derleyici bu ifadenin deerini derleme
zamannda elde edebilmelidir:

199

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

int
int
int
int
int

x = 100;
a[x];
/* Geersiz */
b[5.];
/* Geersiz */
c[10 * 20];
d[sizeof(int) * 100];

Yukardaki deyimlerden a ve b dizilerinin tanmlamalar geersizdir. a dizisinin tanmnda


boyut belirten ifade olarak deimez ifadesi olmayan bir ifade kullanlyor. b dizisinin
tanmnda ise boyut belirten ifade bir gerek say trndendir. c dizisinin tanmnda ise bir
hata sz konusu deildir. 10 * 20 bir deimez ifadesidir. d dizisinin tanm da bir hata
oluturmaz nk sizeof ilecinin rettii deer derleme zamannda elde edilir.
Dizi bildirimlerinde eleman saysn belirten ifade yerine sklkla simgesel deimezler
kullanlr:
#define ARRAY_SIZE 100
int a[ARRAY_SIZE];
Program iinde dizi boyutu yerine hep ARRAY_SIZE simgesel deimezi kullanlabilir.
Bylece programda daha sonra dizi boyutuna ilikin bir deiiklik yaplmak istendiinde,
yalnzca simgesel deimezin deerinin deitirilmesi yeterli olur.
Dier deiken bildirimlerinde olduu gibi, virgl ayracyla ayrlarak, birden fazla dizi, tr
belirten szcklerin bir kez kullanlmasyla tanmlanabilir:
int x[100], y[50], z[10];
x, y ve z, elemanlar int trden olan dizilerdir.
Diziler ve dier nesneler trleri ayn olmak kaydyla tek bir tanmlama deyimiyle
tanmlanabilir:
int a[10], b, c;
a int trden 10 elemanl bir dizi, b ve c int trden nesnelerdir.
Dizi elemanlarnn her biri ayr birer nesnedir. Dizi elemanlarna keli ayra ileciyle []
ulalabilir. Keli ayra ileci bir gsterici ilecidir. Bu ile "Gstericiler" konusunda
ayrntl bir ekilde ele alnacak.
Keli ayra ilecinin terimi dizi ismidir. Aslnda bu bir adres bilgisidir, nk bir dizi ismi
ileme sokulduunda, ilem ncesi derleyici tarafndan otomatik olarak dizinin ilk
elemannn adresine dntrlr. Keli ayra iinde dizinin kanc indisli elemanna
ulalacan gsteren bir tamsay ifadesi olmaldr.
C dilinde bir dizinin ilk eleman, dizinin sfr indisli elemandr.
T bir tr bilgisi olmak zere
T a[SIZE];
gibi bir dizinin ilk eleman a[0] son eleman ise a[SIZE - 1]'dir. rnekler:
dizi[20]
ave[0]
total[j]

/* a dizisinin 20 indisli yani 21. eleman olan nesne */


/* ave dizisinin 0 indisli yani birinci eleman olan nesne */
/* total dizisinin j indisli eleman olan nesne*/

Grld gibi "bir dizinin n. eleman" ve "bir dizinin n indisli eleman" terimleri dizinin
farkl elemanlarn belirtir. Bir dizinin n indisli eleman o dizinin n + 1 . elemandr.

200

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Bir dizi tanmlamas ile karlaan derleyici, tanmlanan dizi iin bellekte yer ayrr.
Ayrlacak yer phesiz
dizinin eleman says * bir elemann bellekte kaplad yer
kadar byte olur. rnein:
int a[5];
gibi bir dizi tanmlamas yapldn dnelim. Windows iletim sisteminde allyorsa
derleyici a dizisi iin bellekte 4 * 5 = 20 byte yer ayrr.
Dizi indis ifadelerinde ++ ya da -- ileleri sk kullanlr:
int a[20];
int k = 10;
int i = 5;
a[k++] = 100;
deyimiyle dizinin 10 indisli elemanna yani dizinin 11. elemanna 100 deeri atanyor.
Daha sonra k deikeninin deeri 1 artrlarak 11 yaplyor.
a[--i] = 200;
deyimiyle dizinin 4 indisli elemanna yani dizinin 5. elemanna 200 deeri atanyor. Daha
sonra i deikeninin deeri 1 azaltlarak 4 yaplyor.
Keli ayra ilecinin kullanlmasyla artk dizinin herhangi bir eleman dier deikenler
gibi kullanlabilir. Aadaki rnekleri inceleyin:
a[0] = 1;
a dizisinin ilk elemanna 1 deeri atanyor.
printf("%d\n", b[5]);
b dizisinin 6. elemannn deeri ekrana yazdrlyor:
++c[3];
c dizisinin 4. elemannn deeri 1 artrlyor:
d[2] = e[4];
d dizisinin 3. elemanna e dizisinin 5. eleman atanyor:
Diziler zerinde ilem yapmak iin sklkla dng deyimleri kullanlr. Bir dng deyimi
yardmyla bir dizinin tm elemanlarna ulamak, ok karlalan bir durumdur.
Aada SIZE elemanl a isimli bir dizi iin for ve while dng deyimlerinin kullanld baz
kalplar gsteriliyor:
a dizisinin btn elemanlarna 0 deeri atanyor:
for (i = 0; i < SIZE; ++i)
a[i] = 0;

201

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Ayn i bir phesiz bir while dng deyimiyle de yaplabilirdi:


i = 0;
while (i < SIZE)
a[i++] = 0;
Aada a dizisinin elemanlarna standart scanf ileviyle standart giri biriminden deer
alnyor:
for (i = 0; i < SIZE; i++)
scanf("%d", &a[i]);
ya da
i = 0;
while (i < SIZE)
scanf("%d", &a[i++]);
Aada a dizisinin elemanlarnn toplam hesaplanyor:
for (total = 0, i = 0; i < SIZE; i++)
total += a[i];
ya da
total = 0;
i = 0;
while (i < SIZE)
total += a[i++];

Dizilerin Tarlmas

Bir dizi tanmlamasn gren derleyici dizi iin bellekte dizinin tm elemanlarnn saca
byklkte bir alan ayrr:
double a[10];
Gibi bir tanmlama yapldnda, allan sistemde double trnn bellekte 8 byte yer
kaplad var saylrsa, dizi iin bellekte bitiik (contiguous) toplam 80 byte'lk bir yer
ayrlr.
Dizinin son eleman a[9] olur. ok sk yaplan bir hata, dizinin son elemanna ulamak
amacyla yanllkla bellekte derleyici tarafndan ayrlmam bir yere deer atamak, yani
diziyi tarmaktr:
a[10] = 5.;
deyimiyle bellekte ne amala kullanld bilinmeyen 8 byte' lk bir alana, yani gvenli
olmayan bir bellek blgesine deer aktarma giriiminde bulunulur. Dizi tamalar derleme
zamannda kontrol edilmez. Byle hatalar programn alma zaman ile ilgilidir.

Dizilere lkdeer Verilmesi

Deiken tanmlamalarnda tanmlanan bir deikenin "ilkdeer verme szdizimi" diye


isimlendirilen bir kural ile belirli bir deerle balatlmas salanabiliyordu.
Tanmlanan dizilere de ilkdeer verilebilir:
double sample[5] = {1.3, 2.5, 3.5, 5.8, 6.0};
char str[4] = {'d', 'i', 'z', 'i'};
unsigned a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

202

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Dizilere yukardaki gibi ilkdeer verildiinde, verilen deerler dizinin ilk elemanndan
balayarak dizi elemanlarna srayla atanm olur.
Dizilerin tm elemanlarna ilkdeer verme zorunluluu yoktur. Dizinin eleman saysndan
daha az sayda elemana ilkdeer verilmesi durumunda kalan elemanlara 0 deeri atanm
olur. Bu kural hem yerel hem de global diziler iin geerlidir.
Bu durumda bir dizinin btn elemanlarna 0 deeri verilmek isteniyorsa bunun en ksa
yolu aadaki gibidir:
int a[20] = {0};
Yalnzca dizinin ilk elemanna 0 ilkdeeri veriliyor. Bu durumda derleyici dizinin kalan
elemanlarna otomatik olarak 0 deeri yerletirecek kodu retir.
Dizi elemanlarna ilkdeer verilmesinde kullanlan ifadeler, deimez ifadeleri (constant
expression) olmaldr.
int a[10] = {b, b + 1, b + 2};

/* Geersiz */

gibi bir ilkdeer verme ilemi geersizdir.


[Yukardaki tanmlama C++ dilinin kurallarna uygundur. C++ dilinde dizi elemanlarna deimez ifadeleriyle
ilkdeer vermek zorunlu deildir]
Bir diziye ilkdeer verme ileminde, dizi eleman saysndan daha fazla sayda ilkdeer
vermek geersizdir:
int b[5] = {1, 2, 3, 4, 5, 6};

/* Geersiz */

Yukardaki rnekte b dizisi 5 elemanl olmasna karn, ilkdeer verme deyiminde 6 deer
kullanlyor. Bu durum derleme zamannda hata oluturur.
lkdeer verme ileminde dizi boyutu belirtilmeyebilir. Bu durumda derleyici dizi
uzunluunu, verilen ilkdeerleri sayarak kendi hesaplar. Dizinin o boyutta aldn kabul
eder. rnein:
int a[] = {1, 2, 3, 4, 5};
Derleyici yukardaki deyimi grdnde a dizisinin 5 elemanl olduunu kabul eder. Bu
durumda yukardaki gibi bir bildirimle aadaki gibi bir bildirim edeerdir:
int a[5] = {1, 2, 3, 4, 5};
Baka rnekler :
char name[] = {'B' 'E ', 'R', 'N', 'A', '\0'};
unsigned short count[ ] = {1, 4, 5, 7, 8, 9, 12, 15, 13, 21};
Derleyici name dizisinin boyutunu 6, count dizisinin boyutunu ise 10 olarak varsayar.
Diziye ilkdeer verme listesi bir virgl atomuyla sonlandrlabilir:
int a[] = { 1, 4, 5, 7, 8, 9, 12, 15, 13,
2, 8, 9, 8, 9, 4, 15, 18, 25,
};

Yerel ve Global Diziler

Bir dizi de dier nesneler gibi yerel ya da global olabilir. Yerel diziler bloklarn iinde
tanmlanan dizilerdir. Global diziler ise global isim alannda, yani tm bloklarn dnda
tanmlanr. Global bir dizinin tm elemanlar, global nesnelerin zelliklerine sahip olur.

203

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yani dizi global ise, dizi eleman olan nesneler dosya bilinirlik alanna (file scope) ve statik
mre (static storage duration) sahip olurlar. Global bir dizi sz konusu olduunda eer
dizi elemanlarna deer verilmemise, dizi elemanlar 0 deeriyle balatlr. Ama yerel
diziler sz konusu olduunda, dizi eleman olan nesneler blok bilinirlik alanna (block
scope) mr asndan ise otomatik mr karakterine (automatic storage class) sahip
olur. Deer atanmam dizi elemanlar iinde p deerler (garbage values) bulunur.
Aadaki program yazarak derleyin:
#include <stdio.h>
#define
int g[SIZE];

SIZE

10

int main()
{
int y[SIZE];
int i;
for (i = 0; i < SIZE; ++i)
printf("g[%d] = %d\n", i, g [i]);
for (i = 0; i < SIZE; ++i)
printf("y[%d] = %d\n", i, y [i]);
}

return 0;

Dizilerin Birbirine Atanmas

Dizilerin elemanlar nesnedir. Ancak bir dizinin tamam bir nesne olarak ilenemez:
int a[SIZE], b[SIZE];
gibi bir tanmlamadan sonra, a dizisi elemanlarna b dizisinin elemanlar kopyalanmak
amacyla, aadaki gibi bir deyimin yazlmas szdizim hatasdr.
a = b;

/* Geersiz */

Yukardaki gibi bir atama derleme zaman hatasna neden olur. nk dizilerin isimleri
olan a ve b nesne gstermez. Dizinin bellekte kaplad toplam alan dorudan tek bir
nesne olarak ilenemez. Yani dizinin elemanlar birer nesnedir ama dizinin tamam bir
nesne deildir. C'de dizi isimleri dizilerin bellekte yerletirildikleri bloun balangcn
gsteren, dizinin tr ile ayn trden adres deerleridir. Dolaysyla deitirilebilir sol taraf
deeri (modifiable L value) deillerdir.
ki dizi birbirine ancak bir dng deyimi ile kopyalanabilir:
for (i = 0; i < SIZE; ++i)
a[i] = b[i];
Yukardaki dng deyimiyle b dizisinin her bir elemannn deeri a dizisinin e indisli
elemanna atanyor. Dizilerin kopyalanmas iin baka bir yntem de bir standart C ilevi
olan memcpy ilevini kullanmaktr. Bu ilev "gstericiler" konusunda ele alnacak.

Dizilerin Kullanmna likin rnekler

Ayn trden nesneler bir dizi altnda tanmlanrlarsa, bir dng deyimi yardmyla dizi
elemanlarnn tamamn ileme sokan kodlar kolay bir biimde yazlabilir. Aadaki rnei
dikkatle inceleyin:

204

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define SIZE

10

int main()
{
int a[SIZE];
int toplam = 0;
int k;
srand(time(0));
for (k = 0; k < SIZE; ++k) {
a[k] = rand() % 100;
printf("%d ", a[k]);
}
for (k = 0; k < SIZE; ++k)
toplam += a[k];
printf("\na elemanlari toplami = %d\n", toplam);
}

return 0;

main ilevinde yer alan ilk for dng deyimiyle a dizisinin elemanlarna standart rand
ilevi arlaryla 0 99 aralnda rastgele deerler atanyor. Yine ayn dng iinde
dizinin her bir elemannn deeri ekrana yazdrlyor. Bunu izleyen ikinci for deyimiyle a
dizisinin her bir elemannn deeri srasyla toplam isimli deikene katlyor.
Aadaki programda ise int trden bir dizinin en kk deere sahip olan elamannn
deeri bulunuyor:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define SIZE

10

int main()
{
int a[SIZE];
int toplam = 0;
int k, min;
srand(time(0));
for (k = 0; k < SIZE; ++k) {
a[k] = rand() % 100;
printf("%d ", a[k]);
}
min = a[0];
for (k = 1; k < SIZE; ++k)
if (min > a[k])
min = a[k];
printf("\nen kucuk eleman = %d\n", min);
return 0;
}
Algoritmay biliyorsunuz. min isimli deiken, dizinin en kk elemannn deerini
tutmas iin tanmlanyor. nce dizinin ilk elemannn dizinin en kk eleman olduu var
saylyor. Daha sonra bir for dng deyimiyle dizinin 1 indisli elemanndan balanarak

205

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

dizinin dier elemanlarnn deerlerinin min deikeninin deerinden daha kk olup


olmad snanyor. Eer dizinin herhangi bir elemann deeri min deikeninin
deerinden daha kk ise min deikeninin deeri deitiriliyor ve yeni bulunan
elemann deeri min deikenine atanyor. Dng knda artk min deikeni, dizinin en
kk elemannn deerini tutar, deil mi?
Aadaki programda ise int trden bir dizinin tek ve ift say olan elemanlarnn aritmetik
ortalamalar ayr ayr hesaplanyor:
#include <stdio.h>
#define SIZE

10

int main()
{
int a[SIZE] = {2, 3, 1, 7, 9, 12, 4, 8, 19, 10};
int sum_of_odds = 0;
int sum_of_even = 0;
int no_of_odds = 0;
int k;
for (k = 0; k < SIZE; ++k)
if (a[k] % 2) {
sum_of_odds += a[k];
no_of_odds++;
}
else
sum_of_even += a[k];
if (no_of_odds)
printf("Teklerin ortalamasi = %lf\n",(double)sum_of_odds
/no_of_odds);
else
printf("Dizide tek sayi yok!\n");
if (SIZE - no_of_odds)
printf("Ciftlerin ortalamasi = %lf\n",(double)sum_of_even /(SIZE no_of_odds));
else
printf("Dizide cift sayi yok!\n");
return 0;
}
Aadaki programda bir dizi iinde arama yaplyor:
#include <stdio.h>
#define SIZE

10

int main()
{
int a[SIZE] = {2, 3, 1, 7, 9, 12, 4, 8, 19, 10};
int k;
int searched_val;
printf("aranacak degeri girin : ");
scanf("%d", &searched_val);
for (k = 0; k < SIZE; ++k)
if (a[k] == searched_val)
break;

206

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

if (k < SIZE)
printf("a[%d] = %d\n", k, a[k]);
else
printf("aranan deger dizide yok!\n");
return 0;
}
searched_val isimli deiken, dizide aranacak deeri tutmak iin tanmlanyor. Bu
deikenin deeri standart scanf ileviyle klavyeden alnyor. Daha sonra oluturulan bir
for dngsyle, dizinin her bir elemannn aranan deere eitlii dng gvdesinde yer
alan bir if deyimiyle snanyor. Eer dizinin herhangi bir eleman aranan deere eit ise
break deyimi ile dngden klyor. Dng knda eer dng deikeni olan k, SIZE
deerinden kk ise aranan deer bulunmu yani dngden break deyimi ile klmtr.
Dngden break deyimi ile klmamsa k deikenin deeri SIZE deerine eit olur,
deil mi?
Dizinin elemanlar dizinin iinde srasz yer alyorsa, bir deerin dizide bulunmad
sonucunu karmak iin dizinin tm elemanlarna baklmaldr.
Ancak dizi sral ise binary search ismi verilen bir algoritmann kullanlmas arama
ileminin ok daha verimli yaplmasn salar:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define

SIZE

100

int main()
{
int a[SIZE];
int k, mid, searched_val;
int val = 1;
int low = 0;
int high = 1;
srand(time(0));
for (k = 0; k < SIZE; ++k) {
a[k] = val;
val += rand() % 10;
printf("%d ", a[k]);
}
printf("\naranacak degeri girin : ");
scanf("%d", &searched_val);
while (low <= high) {
mid = (low + high) / 2;
if (a[mid] == searched_val)
break;
if (a[mid] > searched_val)
high = mid - 1;
else
low = mid + 1;
}
if (low > high)
printf("%d degeri dizide bulunamadi!\n", searched_val);
else
printf("a[%d] = %d\n", mid, searched_val);
}

return 0;

207

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yukardaki main ilevinde sral bir dizinin iinde arama yapmak amacyla binary search
isimli algoritma kullanlyor. Dizi sralanm olduuna gre, dizinin ortadaki elemanna
baklmasyla, dizideki elemanlarn yars artk sorgulama d braklr, deil mi?
low deikeni arama yaplacak dizi parasnn en dk indisini, high deikeni ise en
byk indisini tutuyor. Daha sonra low deeri, high deerinden kk ya da eit olduu
srece dnen bir while dngs oluturulduunu gryorsunuz. mid deikeni arama
yaplacak dizi parasnn ortadaki elemannn indisini tutuyor. Dizinin mid indisli
elemannn aranan deer olup olmadna baklyor. Aranan deer bulunamamsa iki
olaslk vardr: mid indisli dizi eleman aranan deerden byk ise high deikeninin
deeri mid - 1 yaplyor. Bylece arama yaplacak dizi boyutu yarya drlyor. mid
indisli dizi eleman aranan deerden kk ise low deikeninin deeri mid + 1 yaplyor.
Bylece yine arama yaplacak dizi boyutu yarya drlyor.
while dngs knda eer low deeri high deerinden bykse aranan deer
bulunamam demektir. Aksi halde dizinin mid indisli eleman aranan deerdir.

Dizilerin Sralanmas

Dizinin elemanlarn kkten bye ya da bykten ke sralamak iin farkl


algoritmalar kullanlabilir. Aada, algsal karmakl ok yksek olmayan "kabarck
sralamas" (bubble sort) isimli algoritma ile bir dizi sralanyor:
#include <stdio.h>
#define SIZE

10

int main()
{
int a[SIZE] = {2, 3, 1, 7, 9, 12, 4, 8, 19, 10};
int i, k, temp;
for (i = 0; i < SIZE - 1; ++i)
for (k = 0; k < SIZE -1 - i; ++k)
if (a[k] > a[k + 1]) {
temp = a[k];
a[k] = a[k + 1];
a[k + 1] = temp;
}
for (k = 0; k < SIZE; ++k)
printf("%d ", a[k]);
}

return 0;

Ayn algoritma bir do while dngs kullanlarak da kodlanabilirdi:


#include <stdio.h>
#define SIZE
#define UNSORTED
#define SORTED

10
0
1

int main()
{
int a[SIZE] = {12, 25, -34, 45, -23, 29, 12, 90, 1, 20};
int i, k, temp, flag;
do {
flag = SORTED;
for (k = 0; k < SIZE - 1; ++k)
if (a[k] > a[k + 1]) {

208

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

temp = a[k];
a[k] = a[k + 1];
a[k + 1] = temp;
flag = UNSORTED;

}
} while (flag == UNSORTED);

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


printf("a[%d] = %d\n", i, a[i]);
return 0;
}
Aadaki programda bir dizinin elemanlar kkten bye "araya sokma" (insertion
sort) algoritmasyla sraya diziliyor:
#include <stdio.h>
#define SIZE

10

int main()
{
int a[SIZE] = {2, 3, 1, 7, 9, 12, 4, 8, 19, 10};
int i, k, temp;
for (i = 1; i < SIZE; ++i) {
temp = a[i];
for (k = i; k > 0 && a[k - 1] > temp; --k)
a[k] = a[k - 1];
a[k] = temp;
}
for (i = 0; i < SIZE; ++i)
printf("%d ", a[i]);
}

return 0;

Sralama ynn kkten bye yapmak yerine bykten ke yapmak iin iteki
dngy aadaki gibi deitirmek yeterli olur.
for (k = i; k > 0 && dizi[k - 1] < temp; --k)
Aadaki programda ise diziyi kkten bye sralamak iin "seme sralamas"
(selection sort) algoritmas kullanlyor:
#include <stdio.h>
#define SIZE

10

int main()
{
int a[SIZE] = {2, 3, 1, 7, 9, 12, 4, 8, 19, 10};
int i, k, min, index;
for (k = 0; k < SIZE; ++k) {
min = a[k];
index = k;
for (i = k + 1; i < SIZE; ++i)
if (a[i] < min) {

209

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

min = a[i];
index = i;

}
a[index] = a[k];
a[k] = min;
}

for (k = 0; k < SIZE; ++k)


printf("%d ", a[k]);
return 0;
}
Aadaki programda dizinin deeri tek olan elemanlar kkten bye olacak ekilde
dizinin bana, dizinin ift olan elemanlar ise kkten bye dizinin sonuna
yerletiriliyor:
#include <stdio.h>
#define SIZE

10

int main()
{
int a[SIZE] = {2, 3, 1, 7, 9, 12, 4, 8, 19, 10};
int i, k, temp;
for (i = 0; i < SIZE - 1; ++i)
for (k = 0; k < SIZE - 1 - i; ++k)
if (a[k] % 2 == a[k + 1] % 2 && a[k] > a[k + 1] ||
a[k] % 2 == 0 && a[k + 1] % 2 != 0) {
temp = a[k];
a[k] = a[k + 1];
a[k + 1] = temp;
}
for (k = 0; k < SIZE; ++k)
printf("%d ", a[k]);
}

return 0;

Amac gerekletirmek iin yine "kabarck sralamas" algoritmasnn kullanldn, ancak


takas yapmak iin snanan koul ifadesinin deitirildiini fark ettiniz mi?
Aadaki programda bir dizi ters evriliyor:
#include <stdio.h>
#define SIZE

10

int main()
{
int a[SIZE] = {2, 3, 1, 7, 9, 12, 4, 8, 19, 10};
int k;
for (k = 0; k < SIZE / 2; ++k) {
int temp = a[k];
a[k] = a[SIZE - 1 - k];
a[SIZE - 1 - k] = temp;
}
for (k = 0; k < SIZE; ++k)
210

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

printf("%d ", a[k]);


}

return 0;

Dizinin ters evrilmesi iin dizi boyutunun yars kadar dnen bir dng iinde, dizinin
batan n. eleman ile sondan n. eleman takas ediliyor.
Aada tanmlanan urand isimli ilev her arldnda 0 - MAX deerleri arasnda farkl
bir rastgele say retiyor. levin MAX adet tamsayy rettikten sonra arldnda hata
durumunu bildirmek iin -1 deerine geri dnyor:
#include <stdio.h>
#define

MAX

100

int flags[MAX] = {0};


int urand(void)
{
int k, val;
for (k = 0; k < MAX; ++k)
if (flags[k] == 0)
break;
if (k == MAX)
return -1;
while (flags[val = rand() % MAX])
;
++flags[val];
}

return val;

int main()
{
int k;
srand(time(0));
for (k = 0; k < MAX; ++k)
printf("%d ", urand());
printf("\n\n%d\n", urand());
}

return 0;

lev, bir tamsaynn daha nce retilip retilmediini anlayabilmek iin flags isimli bir
global bayrak dizisini kullanyor. flags dizisinin bir elemannn deeri 0 ise o indise karlk
gelen deerin ilev tarafndan henz retilmedii anlalyor. Dizi elemannn deeri eer
1 ise, o deerin daha nce retildii anlalyor.
while (flags[val = rand() % MAX])
;
dngsnden flags dizisinin val deikenine atanan rastgele indisli bir elemannn deeri
sfr olduunda klr, deil mi?

211

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Aadaki program, rastgele retilen bir saysal loto kuponunu ekrana yazyor:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define

KOLON_SAYISI

void kolon_yaz()
{
int numaralar[50] = {0};
int k, no;
for (k = 0; k < 6; ++k) {
while (numaralar[no = rand() % 49 + 1])
;
numaralar[no]++;
}
for (k = 1; k < 50; ++k)
if (numaralar[k])
printf("%2d ", k);
}
int main()
{
int k;
srand(time(0));

for (k = 0; k < KOLON_SAYISI; ++k) {


printf("kolon %2d : ", k + 1);
kolon_yaz();
printf("\n");
}
return 0;

kolon_yaz isimli ilev, tek bir kolonu ekrana yazdryor. levde numaralar isimli yerel
dizinin, yine bir bayrak dizisi olarak kullanldn gryorsunuz. Dizinin herhangi bir
indisli elemannn deerinin 0 olmas, o indis deerinin daha nce retilmeyen bir say
olduunu gsteriyor. for dngs iinde yer alan while dngs, daha nce retilmeyen
bir say bulununcaya kadar dnyor. Bylece 6 kez dnen for dngsyle 6 farkl say
retilmi oluyor.
Aadaki programda bir dizinin en byk ikinci elemannn deeri bulunuyor:
#include <stdio.h>
#define
SIZE

10

int main()
{
int a[SIZE] = {12, 34, 3, 56, 2, 23, 7, 18, 91, 4};
int k;
int max1 = a[0];
int max2 = a[1];
if (a[1] > a[0]) {
max1 = a[1];
max2 = a[0];
}

212

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

for (k = 2; k < SIZE; ++k)


if (a[k] > max1) {
max2 = max1;
max1 = a[k];
}
else if (a[k] > max2)
max2 = a[k];
printf("en buyuk ikinci deger = %d\n", max2);
return 0;
}
Aadaki programda yalnzca bir dizinin iinde tek (unique) olan elemanlarn deerleri
ekrana yazdrlyor.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define

SIZE

100

int main()
{
int a[SIZE];
int i, k;
int counter;
srand(time(0));
for (k = 0; k < SIZE; ++k) {
a[k] = rand() % 30;
printf("%d ", a[k]);
}
printf("\n*******************************************************\n");
for (i = 0; i < SIZE; ++i) {
counter = 0;
for (k = 0; k < SIZE; ++k)
if (a[k] == a[i])
if (++counter == 2)
break;
if (counter == 1)
printf("%d ", a[i]);
}
printf("\n");
}

return 0;

Aadaki program SIZE elemanl bir dizinin tm elemanlarna 0 - MAX aralnda


birbirinden farkl rastgele deerler yerletiriyor:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define SIZE
#define MAX

50
100

213

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

int main()
{
int a[SIZE];
int k;
srand(time(0));
for (k = 0; k < SIZE; ++k) {
int val;
while (1) {
int i;
val = rand() % MAX;
for (i = 0; i < k; ++i)
if (val == a[i])
break;
if (i == k)
break;
}
a[k] = val;
}
/* dizi yazdrlyor */
for (k = 0; k < SIZE; ++k)
printf("%d ", a[k]);
printf("\n");
return 0;
}
Aadaki programda sral iki dizi, bir sral dizi biiminde birletiriliyor:
#include <stdio.h>
#define SIZE

10

int main()
{
int a[SIZE] = {2, 3, 6, 7, 8, 9, 13, 45, 78, 79};
int b[SIZE] = {1, 2, 4, 5, 7, 9, 10, 18, 33, 47};
int c[SIZE + SIZE];
int k;
int index1 = 0, index2 = 0;
for (k = 0; k < SIZE + SIZE; ++k)
if (index1 == SIZE)
c[k] = b[index2++];
else if (index2 == SIZE)
c[k] = a[index1++];
else {
if (a[index1] < b[index2])
c[k] = a[index1++];
else
c[k] = b[index2++];
}
for (k = 0; k < SIZE + SIZE; ++k)
printf("%d ", c[k]);
}

return 0;

214

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

char Trden Diziler ve Yazlar

Karakter dizileri, char trden dizilerdir. Karakter dizilerinin, baz ek zellikleri dnda,
dier dizi trlerinden bir fark yoktur. char trden diziler, daha ok, ilerinde yaz tutmak
iin tanmlanr.
char str[100];
Yukardaki tanmlamada str dizisi, btn elemanlar char trden olan 100 elemanl bir
dizidir. char trden bir dizi iinde bir yaz tutmak, dizinin her bir elemanna srayla yaznn
bir karakterinin sra numarasn atamak anlamna gelir. Bu arada char trden bir dizinin
iinde bir yaz tutmann zorunlu olmadn, byle bir dizi pekala kk tamsaylar tutmak
amacyla da kullanlabilir.
Yukarda tanmlanan dizi iinde "Ali" yazs tutulmak istensin:
str[0] = 'A';
str[1] = 'l';
str[2] = 'i';
Dizi 100 karakterlik olmasna karn dizi iinde 100 karakterden daha ksa olan yazlar da
tutulabilir. Peki dizi iinde saklanan yazya nasl eriilebilir? Yaznn uzunluk bilgisi
bilinmiyor. rnein yaz ekrana yazdrlmak istendiinde, int trden diziler iin daha nce
yazlan aadaki gibi bir dng deyiminin kullanldn dnelim:
for (k = 0; k < 100; ++k)
putchar(s[k]);
Byle bir dng ile yalnzca Ali yazs ekrana yazdrlmaz, dizinin dier 97 elemannn da
grntleri, yani p deerler ekrana yazdrlr, deil mi?
C dilinde karakterler zerinde ilemlerin hzl ve etkin bir biimde yaplabilmesi iin
"sonlandrc karakter" (null character) kavramndan faydalanlr.
Sonlandrc karakter, ASCII tablosunun ya da sistemde kullanlan karakter setinin sfr
numaral ('\x0' ya da '\0') karakteridir. Dolaysyla saysal deer olarak 0 saysna
eittir. Grnts yoktur. Sonlandrc karakter '0' karakteri ile kartrlmamaldr.
'0' karakterinin ASCII karakter setindeki kod numaras 48'dir. Dolaysyla tamsay
olarak deeri 48'dir. Oysa '\0' karakterinin ASCII sra numaras 0'dr. Dolaysyla
tamsay olarak deeri 0'dr. Aadaki program derleyerek altrn:
#include <stdio.h>
int main()
{
printf("%d\n", '0');
printf("%d\n", '\0');
}

return 0;

Yukardaki ilk printf ilevinin arlmasyla ekrana 48 deeri yazdrlrken, ikinci printf
ilevinin arlmasyla ekrana 0 deeri yazdrlr.

char Trden Dizilere lkdeer Verilmesi

char trden dizilere ilkdeer verme ilemi (initializing) aadaki biimlerde yaplabilir:
Dier trden dizilerde olduu gibi virgllerle ayrlan ilkdeerler, kme ayrac iinde yer
alr:

215

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

char name[7] = {'N', 'e', 'c', 'a', 't', 'i', '\0'};


Dier dizilerde olduu gibi dizi eleman saysndan daha fazla sayda elemana ilkdeer
vermek geersizdir.
char name[5] = {'N', 'e', 'c', 'a', 't', 'i'};

/* Geersiz */

Dizi eleman says kadar elemana ya da dizi eleman saysndan daha az sayda elemana
ilkdeer verilebilir. Daha az sayda elemana ilkdeer verilmesi durumunda ilkdeer
verilmemi elemanlar, dier dizilerde olduu gibi, 0 deeriyle balatlr. 0 deerinin
sonlandrc karakter olduunu biliyorsunuz:
char name[5] = {'A', 'l', 'i'};

Dizi elemanlarna ilkdeer verilirken dizi boyutu belirtilmeyebilir. Bu durumda derleyici


dizi boyutunu verilen ilkdeerleri sayarak saptar. Derleyici diziyi bu boyutta alm
varsayar.
char name[ ] = {'A', 'l', 'i'};
Yukardaki tanmlama deyimiyle derleyici, name dizisinin 3 elemanl olarak aldn
varsayar.
char trden dizilerin tanmlanmasnda dizinin boyut deeri yazlmadan, dizinin
elemanlarna virgllerle ayrlm deerlerle ilkdeer verilmesi durumunda, derleyici
sonlandrc karakteri dizinin sonuna otomatik olarak yerletirmez. Bu durumda yaznn
sonunda bulunmas gereken sonlandrc karakter ilkdeer olarak listede bulunmak
zorundadr:
char name[] = {'A', 'l', 'i', '\0'};
Ayn durum dizinin boyutu ile verilen ilkdeerlerin saysn ayn olduunda da geerlidir:
char isim[7] = {'N', 'e', 'c', 'a', 't', 'i', '\0'};
Bu ekilde ilkdeer vermek zahmetli olduundan, ilkdeer vermede ikinci bir biim
oluturulmutur. Karakter dizilerine ilkdeerler ift trnak iinde de verilebilir:
char name[] = "Ali";
Bu biimin dierinden fark, derleyicinin sonuna otomatik olarak sonlandrc karakteri
yerletirmesidir.

216

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yukardaki rnekte derleyici, name dizisini 4 elemanl olarak alm varsayar. Dizinin
eleman saysndan daha fazla sayda elemana ilkdeer vermek geersizdir.
char city[5] = "stanbul";

/* Geersiz */

Bu durumun bir istisnas vardr. Eer dizinin eleman says kadar elemana ift trnak
iinde ilkdeer verilirse bu durum geerlidir. Derleyici bu durumda sonlandrc karakteri
dizinin sonuna yerletirmez.
[Bu durum C dili standartlarna yneltilen eletirilerden biridir. C++ dilinde bu durum szdizim hatasdr.]
char name[3] = "Ali";

/* C'de geerli, C++'da geersiz */

'\0' karakteri, karakter dizileri zerinde yaplan ilemleri hzlandrmak iin kullanlr.
rnein int trden bir dizi kullanldnda, dizi elemanlar zerinde dngleri kullanarak
ilem yaparken dizi uzunluunun mutlaka bilinmesi gerekir. Ama char trden diziler sz
konusu olduunda artk dizi uzunluunu bilmek gerekmez, nk yaznn sonunda '\0'
karakter bulunacandan, kontrol ifadeleriyle bu durum snanarak yaznn sonuna gelinip
gelinmedii anlalabilir. Ancak '\0' karakterin, karakter dizilerinde yazlarn son eleman
olarak kullanlmasnn bir zarar da diziye fazladan bir karakter, yani '\0' karakteri
eklemek zorunluluudur. Bu nedenle SIZE elemanl bir dizide en fazla SIZE 1
uzunluunda bir yaz saklanabilir.
C dilinde bir yazy klavyeden alan ya da bir yazy ekrana yazan standart ilevler bulunur.

gets ilevi

Daha nce ele alnan getchar, getch ve getche ilevleri klavyeden tek bir karakter
alyorlard. gets, klavyeden karakter dizisi almakta kullanlan standart bir C ilevidir.
Kullanc, klavyeden karakterleri girdikten sonra enter tuuna basmaldr. lev, klavyeden
girilecek karakterlerin yerletirilecei dizinin ismini parametre olarak alr. Daha nce de
belirtildii gibi dizi isimleri aslnda bir adres bilgisi belirtir. gets ilevinin de parametresi
aslnda char trden bir adrestir. Ancak gstericilerle ilgili temel kavramlar henz
anlatlmad iin imdilik gets ilevini yalnzca iinize yarayacak kadar reneceksiniz.
rnein :
char s[20];
gets(s);
ile klavyeden enter tuuna baslana kadar girilmi olan tm karakterler, name dizisi iine
srayla yerletirilir. Klavyeden "Necati" yazsnn girildiini varsayalm:
gets ilevi, klavyeden girilen karakterleri diziye yerletirdikten sonra dizinin sonuna
sonlandrc karakteri yerletirir.

217

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

gets ilevi, dizi iin hibir ekilde dizinin tamasna ynelik bir kontrol yapmaz. gets ilevi
ile dizi eleman saysndan daha fazla karakter girilirse, dizi taaca iin beklenmeyen
sonularla karlalabilir. Bu tr durumlar gstericiler konusunda "gsterici hatalar"
bal altnda ayrntl olarak inceleyeceiz.
gets ilevi '\0' karakterini dizinin sonuna ekledii iin, SIZE boyutunda bir dizi iin gets
ileviyle alnacak karakter says en fazla SIZE 1 olmaldr. nk sonlandrc karakter
de dier karakterler gibi bellekte bir yer kaplar. rnek :
char isim[6];
gets(isim);
ile klavyeden Necati isminin girildiini dnelim:
isim dizisinin tanmlanmasyla derleyici bu dizi iin bellekte 6 byte yer ayrr (isim[0]
...isim[5]).

gets ilevi bu durumda '\0' karakterini, derleyicinin dizi iin ayrmad bir bellek
hcresine yazar. Bu tr durumlara "dizinin bir tarlmas hatas" (off bye one) denir.
Tama durumuyla ilgili olarak ortaya kacak hatalar, derleme zamanna deil alma
zamanna (run time) ilikindir.
Aadaki program inceleyin:
#include
#define

<stdio.h>
SIZE

100

int main()
{
char str[SIZE];
int ch;
int index = 0;
printf("bir yaz girin: ");
printf("\n\n");
while ((ch = getchar()) != '\n')
str[index++] = ch;
str[index] = '\0';
return 0;
}
Yukardaki main ilevinde klavyeden alnan bir yaz str dizisi iinde saklanyor. Klavyeden
'\n' karakteri alnana kadar, girilen tm karakterler str dizisinin elemanlarna srayla
atanyor. Klavyeden '\n' karakteri alndnda, diziye yazlan son karakterden sonra,
dizideki yaznn sonunu iaretlemesi amacyla '\0' karakter yazlyor.
Klavyeden alnan bir yaz, char trden bir dizinin iine standart scanf ileviyle de
yerletirilebilir. Bu amala %s format karakterleri kullanlr. Ancak bu durumda klavyeden

218

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

girilen karakterlerin hepsi diziye yerletirilmez. Klavyeden alnan ilk boluk karakteri ile
diziye yerletirme ilemi sona erer. Aadaki program inceleyin:
#include <stdio.h>
int main()
{
char name[20];
char fname[30];
int no;
printf("isim soyisim ve numara girin : ");
scanf("%s%s%d", name, fname, &no);
/***/
return 0;
}
Programn alma zamannda scanf ilevi arldnda aadaki giriin yapldn
dnelim. ('_' karakteri boluk karakterini gsteriyor):
__Necati___Ergin___564
Bu durumda Necati yazs name dizisine, Ergin yazs fname dizisine, 564 tamsay deeri
ise no isimli deikene yerletirilir.

puts ilevi

puts, standart bir C ilevidir. Bu ilev, bir karakter dizisinde tutulan yazy ekrana
yazdrmak iin kullanlr. Yazy saklayan karakter dizisinin ismini (dizi ismi derleyici
tarafndan otomatik olarak dizinin balang adresine dntrlmektedir) parametre
olarak alr. puts ilevi, karakter dizisini ekrana yazdktan sonra imleci sonraki satrn
bana geirir:
#include <stdio.h>
int main()
{
char name[20];
printf("bir isim girin : ");
gets(name);
puts(name);
return 0;

}
Yukardaki rnekte gets ilevi ile klavyeden alnan yaz, puts ilevi ile ekrana yazdrlyor.
Karakter dizileri iinde tutulan yazlar ekrana yazdrmak iin, standart printf ilevi de
kullanlabilir. Bu durumda formatlama karakterleri olarak %s kullanlarak dizinin ismi
(dizinin balang adresi) ile elenir.
printf("%s\n", name);
ile
puts(name);

219

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

ayn ii yapar. Ancak printf ilevi, dizi iinde tutulan yazy ekrana yazdrdktan sonra
imleci alt satra tamaz.
puts(name);
deyimi yerine aadaki kod paras da yazlabilirdi:
for (i = 0; name[i] != '\0'; ++i)
putchar(name[i]);
putchar('\n');
puts ilevi ve %s format karakteriyle kullanldnda printf ilevi, sonlandrc karakter
grene kadar btn karakterleri ekrana yazar. Bu durumda, yaznn sonundaki
sonlandrc karakter herhangi bir ekilde ezilirse her iki ilev de ilk sonlandrc karakteri
grene kadar yazma ilemini srdrr. Aadaki program inceleyin:
#include <stdio.h>
int main()
{
char city[] = "Ankara";
city[6] = '!';
puts(city);
}

return 0;

city[6] = '!';
atamasyla Ankara yazsnn sonundaki sonlandrc karakter ezilerek zerine ! karakteri
yazlyor. Daha sonra arlan puts ilevi ekrana
Ankara!
yazsn yazdktan sonra ilk sonlandrc karakteri grene kadar ekrana yazmay srdrr.
Gstericiler konusunda bu durumun bir gsterici hatas oluturduunu greceksiniz. puts
ve printf ilevleri, karakter dizilerini yazarken yalnzca sonlandrc karakteri dikkate alr.
Bu ilevler karakter dizilerinin uzunluklaryla ilgilenmez.

Karakter Dizileriyle lgili Baz Kk Uygulamalar

Aadaki programda bir karakter dizisi iinde tutulan yaznn uzunluu bulunuyor:
#include <stdio.h>
#define

SIZE

100

int main()
{
char str[SIZE];
int k;
int len = 0;
printf ("bir yazi girin : ");
gets(str);
printf("yazi = (%s)\n", str);
for (k = 0; str[k] != '\0'; ++k)
len++;
printf("(%s) yazisinin uzunlugu = %d\n", str, len);

220

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

return 0;

Programda yer alan


for (k = 0; str[k] != '\0'; ++k)
len++;
dng deyiminin yrtlmesinden sonra, dng deikeni olan k'nn deeri de yaznn
uznluu olur, deil mi?
Aadaki programda char trden bir dizi iine alnan yaz, ekrana tersten yazdrlyor:
#include <stdio.h>
#define

SIZE

100

int main()
{
char s[SIZE];
int k;
printf("bir yaz girin :");
gets(s);
for (k = 0; s[k] != '\0'; ++k)
;
for (--k; k >= 0; --k)
putchar(s[k]);
}

return 0;

Aadaki programda nce bir karakter dizisine bir yaz alnyor. Daha sonra yaznn
kk harf karakterleri byk harfe, byk harf karakterleri kk harfe dntrlyor:
#include <stdio.h>
#include <ctype.h>
#define

SIZE

100

int main()
{
char str[SIZE];
int k;
printf ("bir yazi girin : ");
gets(str);
printf("yazi = (%s)\n", str);
for (k = 0; str[k] != '\0'; ++k)
str[k] = isupper(str[k]) ? tolower(str[k]) : toupper(str[k]);
printf("donustulmus yazi = (%s)\n", str);
return 0;
}
Aadaki programda bir karakter dizisine klavyeden alnan yaz ters evriliyor:
221

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
#define

SIZE

100

int main()
{
char str[SIZE];
int k, temp, len;
printf ("bir yazi girin : ");
gets(str);
for (len = 0; str[len] != '\0'; ++len)
;

for (k = 0; k < len / 2; ++k) {


temp = str[k];
str[k] = str[len - 1 - k];
str[len - 1 - k] = temp;
}
printf("ters cevrilmis yazi = (%s)\n", str);
return 0;

Yukardaki kodda kullanlan algoritmay inceleyin. Birinci for dngs ile yaznn uzunluu
bulunuyor. Daha sonra yaznn uzunluunun yars kadar dnen bir for dng deyimi
oluturuluyor. Dngnn her turunda yaznn batan n. karakteri ile sondan n. karakteri
yer deitiriliyor. Yaz uzunluu tek say ise, yaznn ortasndaki karakter yerinde kalr.
Yaznn sonundaki sonlandrc karakter
str[len]
olduuna gre, yaznn son karakteri
str[len 1]
karakteridir, deil mi?
Aadaki programda ise klavyeden girilen bir yaznn iinde bulunan tm ngilizce harfler
saylyor ve ka tane olduklar ekrana yazdrlyor:
#include <stdio.h>
#include <ctype.h>
#define

SIZE

500

int main()
{
char str[SIZE];
int letter_counter[26] = {0};
int k;
printf("bir yazi girin : ");
gets(str);
for (k = 0; str[k] != '\0'; ++k)
if (isalpha(str[k]))
letter_counter[toupper(str[k]) - 'A']++;
for (k = 0; k < 26; ++k)
if (letter_counter[k])
printf("%3d tane %c\n", letter_counter[k], 'A' + k);
return 0;

222

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

main ilevi iinde kullanlan letter_counter isimli dizi, bir saya dizisi olarak kullanlyor.
Dizinin 1. eleman 'A', 'a' karakterlerinin, dizinin 2. eleman 'B', 'b' karakterlerinin,
dizinin sonuncu eleman 'Z', 'z' karakterlerinin sayac olarak grev yapyor. Bu yerel
dizi, ilkdeer verme deyimiyle sfrlanyor. lk for dng deyimiyle, yaznn tm
karakterleri dolalyor, yaznn herhangi bir karakteri eer bir harf karakteri ise, byk
harfe dntrlerek bu karakterden 'A' deeri karlyor. Elde edilen deerin
letter_counter dizisine indis yapldn ve letter_counter dizisinin bu indisli elemannn
deerinin 1 artrldn gryorsunuz.
kinci for dng deyimiyle ise bu kez saya dizisinin, deeri 0 olmayan elemanlarnn
deerleri ekrana yazdrlyor.
Aadaki programda ise bir diziye alnan bir yaz iinden rakam karakterleri siliniyor.
Kodu inceleyin:
#include <stdio.h>
#include <ctype.h>
#define

SIZE

500

int main()
{
char str[SIZE];
int k;
int index = 0;
printf("bir yazi girin : ");
gets(str);
printf("yazi = (%s)\n", str);
for (k = 0; str[k] != '\0'; ++k)
if (!isdigit[k])
str[index++] = str[k];
str[index] = '\0';
printf("yazi = (%s)\n", str);
}

return 0;

Yazdan rakam karakterlerini silmek iin yaz, bulunduu yere yeniden kopyalanyor.
Ancak kopyalama yaplrken, rakam karakterleri kopyalanmyor. index isimli deiken,
dizinin neresine yazlacan gsteriyor. Eer bir karakter rakam karakteri deilse, bu
karakter dizinin index indisli elemanna atanyor, sonra index deikeninin deeri 1
artrlyor. Ancak yaznn tamamn dolaan for dngsnden ktktan sonra, silme
ileminden sonra oluan yaznn sonuna, sonlandrc karakter ekleniyor.
Aadaki programda bir yaznn toplam szck says bulunuyor:
#include <stdio.h>
#define
#define
#define

SIZE
OUTWORD
INWORD

200
0
1

int is_sep(int ch);


int main()

223

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

{
char str[SIZE];
int word_counter = 0;
int k;
int word_flag = OUTWORD;
printf("bir yazi girin : ");
gets(str);
for (k = 0; str[k] != '\0'; ++k)
if (is_sep(str[k]))
word_flag = OUTWORD;
else if (word_flag == OUTWORD) {
word_flag = INWORD;
word_counter++;
}
printf("toplam %d sozcuk var!\n", word_counter);
}

return 0;

int is_sep(int ch)


{
char seps[] = " \t.,;:?!";
int k;
for (k = 0; seps[k] != '\0'; ++k)
if (ch == seps[k])
return 1;
return 0;
}
is_sep ilevi, sra numarasn ald bir karakterin, szckleri birbirinden ayran ayra
karakterlerinden biri olup olmadn snyor.
main ilevi iinde tanmlanan word_flag isimli bayrak deikeni, bir szcn iinde mi
dnda m olunduunu gsteriyor. Bu deikene ilkdeer olarak, kelimenin dnda (OUT)
deerinin verildiini gryorsunuz.
Bir for dng deyimiyle yaznn her bir karakterinin ayra karakteri olup olmad
snanyor. Eer ayra karakteri ise word_flag deikenine OUT deeri atanyor. Eer
karakter ayra karakteri deilse ve ayn zamanda bayran deeri OUT ise, bayraa IN
deeri atanyor ve szck saysn tutan sayacn deeri 1 artrlyor.
Aadaki programda, bir yaznn iinde ardk olarak yer alan e karakterlerin says bire
indiriliyor:
#include <stdio.h>
#define

SIZE

100

int main()
{
char str[SIZE];
int index = 0;
int k;
printf("bir yazi girin : ");
gets(str);
for (k = 0; str[k] != '\0'; ++k)

224

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

if (str[k] != str[k + 1])


str[++index] = str[k + 1];
printf("yazi = (%s)\n", str);
return 0;
}

225

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

sizeof leci

sizeof, bir ifadenin trnn bellekte ka byte yer kaplad deerini reten bir iletir.
sizeof ileci tek terimli nek konumunda bir iletir.
sizeof ilecinin terimi aadakilerden biri olabilir:
1. Terim olarak tr belirten szckler kullanlabilir. Bu durumda terimin ayra iine
alnmas zorunludur. rnekler:
sizeof(int)
sizeof(double)
sizeof(long)
le bu durumda terimi olan tr bilgisinin kullanlan sistemde ka byte yer kaplayaca
deerini retir. rnein Windows ya da UNIX sistemlerinde
sizeof(int)
gibi bir ifadenin deeri 4'tr.
2. Terim olarak bir ifade kullanlabilir. Bu durumda terimin ayra iine alnmas zorunlu
deildir. Ancak programclarn ou okunabilirlik asndan terimi ayra iine almay
yeler:
double x;
sizeof (x)
sizeof(17.8)
sizeof(func())
le bu durumda, terimi olan ifadenin ait olduu trn, kullanlan sistemde ka byte yer
kaplayaca deerini retir. rnein Windows ya da UNIX sistemlerinde
sizeof(x)
gibi bir ifadenin deeri 8'dir. Byle bir ifade doal olarak, ilgili sistemde x nesnesinin
bellekte ka byte yer kapladn belirlemekte de kullanlabilir. sizeof ileci en ok bu
biimiyle kullanlr. Yani ilecin terimi nesne gsteren bir ifade seilerek, terimi olan
nesnenin bellekte ka byte yer kaplad renilir.
3. sizeof ileci terim olarak bir dizi ismi aldnda, byte olarak o dizinin toplam
uzunluunu deer olarak retir:
double a[10];
sizeof(a)
ifadesi 80 deerini retir.
Dier taraftan sizeof ilecinin terim olarak dizinin bir elemann alarak rettii deer, dizi
hangi trden ise o trn kullanlan sistemdeki byte olarak uzunluu olur. Yani yukardaki
rnekte
sizeof(a[0])
ifadesi 8 deerini retir.
Bu durumda

226

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

sizeof(a) / sizeof(a[0])
ifadesi dizi boyutunu verir. rnek:
for (i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
a[i] = 0;
a bir dizi ismi olmak zere, yukardaki dng, a dizisinin eleman says kadar dner.
Yukardaki dngde dizi boyutunun ak biimde yazlmas yerine
sizeof(a) / sizeof(a[0]
biiminde yazlmas size artc gelebilir. Byle bir yazm biiminin bir faydas olabilir mi?
Dizi tanmlamalarnda, ilkdeer verilen dizilerin boyutlarnn belirtilmesine gerek
olmadn, derleyicinin dizi boyutunu verilen ilkdeerlerin saysndan kardn
biliyorsunuz. Aadaki kodu inceleyin:
#include <stdio.h>
int main()
{
int a[] = {2, 5, 7, 8, 9, 23, 67};
int k;
for (k = 0; k < sizeof(a) / sizeof(a[0]); ++k)
printf("%d ", a[k]);
printf("\n");
}

return 0;

Yukardaki main ilevi iinde a isimli int trden bir dizi tanmlanyor. Tanmlanan diziye
ilkdeer veriliyor. Derleyici verilen ilkdeerlerin saysn sayarak dizinin boyutunu 8 olarak
saptar ve kodu buna gre retir. main ilevi iinde yer alan for dng deyimi, dizinin
eleman says kadar, yani 8 kez dner.
imdi kaynak kodda deiiklik yapldn, a dizisine birka eleman daha eklendiini
dnelim:
int a[] = {2, 5, 7, 8, 9, 23, 67, 34, 58, 45, 92};
Bu durumda for dng deyiminde bir deiiklik yaplmasna gerek kalmaz. nk
derleyici bu kez dizinin boyutunu 11 olarak hesaplar. for dng deyimi iinde kullanlan
sizeof(a) / sizeof(a[0]
ifadesi de bu kez 11 deerini retir.

sizeof lecinin ncelii

Tek terimli tm ilelerin, ile ncelik tablosunun ikinci seviyesinde yer aldn
biliyorsunuz. sizeof da ikinci seviyede bulunan bir iletir.

sizeof Bir lev Deildir

sizeof ilecinin terimi ou kez bir ayra iine yazldndan, ilecin kullanm bir ilev
ars grntsne benzer:
sizeof(y)
Ancak sizeof bir ilev deil bir iletir. sizeof C dilinin 32 anahtar szcnden biridir.
227

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

sizeof lecinin rettii Deerin Tr

sizeof ilecinin rettii deer unsigned int trdendir. lecin rettii deerin trn signed
int kabul etmek hataldr. lecin rettii deer, signed int trden negatif bir sayyla
ileme sokulduunda tr dnm iaretsiz yne yaplr:
-2 * sizeof(int)
-2, iaretli int trden bir deimezdir. sizeof(int) ifadesinin rettii deer ise unsigned int
trden 4 deeridir. lem ncesi yaplacak otomatik tr dnm ile -2 deeri unsigned
int trne dntrlr. lem unsigned int trde yaplr. Yani ilemin sonucu 8 olmaz.
[Aslnda sizeof operatrnn rettii deer standart bir typedef tr olan size_t trndendir. Standart typedef
trleri "Tr simleri Bildirimleri ve typedef Belirleyicisi " isimli blmde ele alnyor.]

sizeof lecinin Terimi Olan fadenin Yan Etkisi

sizeof ilecinin terimi olan ifade yan etki gstermez. Aadaki rnei inceleyin:
#include <stdio.h>
int func()
{
printf("func()\n");
}

return 1;

int main()
{
unsigned int x = sizeof(func());
printf("x = %u\n", x);
}

return 0;

main ilevi iinde, func ilevi arlmaz. sizeof ileci, terimi olan ifadeye yalnzca bir tr
bilgisi olarak bakar. rnek kodda yer alan
func()
ifadesinin tr int trdr.

sizeof leci Ne Amala Kullanlr

Belirli bir trden nesnenin bellekte ka byte yer kaplayaca, sistemden sisteme farkllk
gsterebilir. Tr uzunluu gvence altnda bulunan tek doal tr, char trdr. char
trden bir nesne tm sistemlerde 1 byte yer kaplar. Tr uzunluklarnn sistemden sisteme
farkl olabilmesi, baz uygulamalarda tanabilirlik sorunlarna yol aabilir. sizeof ilecinin,
genel olarak bu tr tanabilirlik sorunlarn ortadan kaldrmaya ynelik olarak kullanld
sylenebilir.

228

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

GSTERCLER
Birinci blmde yazlan kodlarda nesnelerin deerleri kullanld. rnein deikenlerin
deerleri ilevlere argman olarak gnderildi. levler nesnelerin deerlerini geri
dndrd. "Gstericiler" (pointers) ile artk nesnelerin deerlerinin yan sra nesnelerin
adresleri zerinde de durulacak.
Nasl, oturduunuz evin adresinden sz ediliyorsa, programda kullandnz nesnelerin de
adreslerinden sz edilebilir. Bir nesnenin adresi o nesnenin bellekteki konumunu gsteren
bir bilgidir.
te C dilinde yazlan birok kod, nesnelerin adresi olan bilgileri kullanlr. Yazlmsal baz
amalarn gerekletirilmesi iin, nesnelerin adresleri deikenlerde saklanr, ilevlere
gnderilir, ilev arlaryla ilevlerden geri dn deeri olarak elde edilir.
Her nesne bellekte yer kapladna gre belirli bir adrese sahiptir. Nesnelerin adresleri,
sistemlerin ounda, derleyici ve program ykleyen iletim sistemi tarafndan ortaklaa
belirlenir. Nesnelerin adresleri program yklenmeden nce kesin olarak bilinemez ve
programc tarafndan da nceden saptanamaz. Programc nesnelerin adreslerini ancak
programn almas srasnda (run time) renebilir. rnein:
char ch;
Gibi bir tanmlamayla karlaan derleyici bellekte ch deikeni iin 1 byte yer ayrr.
Derleyicinin ch deikeni iin bellekte hangi byte' ayraca nceden bilinemez. Bu ancak
programn almas srasnda renilebilir. Yukardaki rnekte ch deikeninin yerel yerel
olduunu dnelim. ch deikeni, tanmlanm olduu bloun kodu yrtlmeye
balandnda yaratlr, bloun kodunun yrtlmesi bittiinde de mr sona erer.
Aadaki ekil ch deikeninin 1A02 adresinde olduu varsaylarak izilmitir:
1A00
1A01

ch

1A02
1A03
1A04

Tanmlanan nesne 1 byte'dan daha uzunsa, o zaman nesnenin adresi nasl belirlenir?
int b;

1 byte'tan uzun olan nesnelerin adresleri, onlarn ilk byte'larnn adresleriyle belirtilir.
Yukardaki rnekte b deikeninin adresi 1C02'dir. Zaten b deikeninin int trden olduu
bilindiine gre dier parasnn 1C03 adresinde olaca da aktr (int trden bir
nesnenin ilgili sistemde 2 byte yer kaplad varsaylyor).
Benzer biimde long trden olan y deikeninin bellekteki yerleiminin aadaki gibi
olduu varsaylrsa, adresinin 1F02 olduu sylenebilir:

229

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

int trden bir deiken tanmlanm olsun:


int x;
Byle bir nesnenin adresinin yazlmsal olarak kullanlabilmesi iin, bu bilginin bir biimde
ifade edilmesi, bellekte tutulmas, yorumlanmas gerekir.
x deikeninin adresi olan bilginin de, bir tr olmaldr. Byle bir tr bilgisi, nesnenin
kendi trnden tretilir (derived type) ve C'de aadaki biimde gsterilir:
(int *)
double trden bir nesnenin adresi olabilecek bir bilginin tr de
(double *)
olarak gsterilir.
x, T trnden bir nesne olmak zere x nesnesinin adresi olan bilginin trnn
(T *) tr olduu kabul edilir.

Gsterici Nesneler

Yazlmsal baz amalar gerekletirmek iin nesnelerin adreslerinin de deikenlerde


tutulmas gerekir. Nasl bir tamsay deeri tamsay trlerinden bir deikende
tutuluyorsa, bir adres bilgisi de, tr bir adres bilgisi olan deikende saklanr.
int x;
Yukarda tanmlanan x nesnesinin tr int trdr. Byle bir nesnenin adresi olan bilgi
(int *) trnden olduuna gre bu bilgi doal olarak int * trnden olan bir deikende
saklanmaldr.

Gsterici Deikenlerin Bildirimleri


int *ptr;
Yukarda ptr isimli bir deiken tanmlanyor. ptr deikeni int trden bir nesnenin adresi
olan bilgiyi tutabilecek bir deikendir. ptr deikeninin deeri, int trden bir nesnenin
adresi olan bilgidir. ptr deikenine int trden bir nesnenin adresi olabilecek bilgi
atanmaldr.
Benzer ekilde double trden bir nesnenin adresi olan bilgiyi saklamak iin de
double *dp;
gibi bir deiken tanmlanabilir.
Gsterici deikenler, adres bilgilerini saklamak ve adreslerle ilgili ilemler yapmak iin
kullanlan nesnelerdir. Gsterici deikenlerin deerleri adrestir.
Gsterici deikenlerin bildirimlerinin genel biimi yledir:

230

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

<tr> *<gsterici ismi>;


<tr>, gstericinin (iindeki adresin) trdr. char, int, float... gibi herhangi bir tr
olabilir.
Burada * atomu tr bilgisinin bir parasdr.
Aada rnek gsterici bildirimleri yer alyor:
float *f;
char *ps;
int *dizi;
unsigned long *Pdword;
Gsterici bildirimleri, dier trlere ilikin bildirimlerden * atomu ile ayrlr.
char s;
bildiriminde s, char trden bir deiken iken
char *ps;
bildiriminde ps, char trden bir gstericidir, yani tr char * olan bir nesnedir. Bu
deikene char trden bir nesnenin adresi atanmaldr. Byle bir bildirimden u bilgiler
karlabilir:
ps bir nesnedir, yani bellekte bir yer kaplar. ps nesnesi iin bellekte ayrlan yerdeki 1'ler
ve 0'lar char trden bir nesnenin adresinin, saysal deeri olarak yorumlanr.
Tanmlamada yer alan '*' bir ile deildir. Szdizim kural olarak nesnenin bir gsterici
olduunu anlatr.
Gsterici bildirimleri ile normal bildirimler bir arada yaplabilir. rnein:
int *p, a;
Burada p int trden bir gsterici deikendir, ama a int trden bir normal bir deikendir.
Ayn trden birden fazla gstericinin bildirimi yaplacaksa, araya virgl atomu konularak,
her gsterici deikenin bildirimi * atomu ile yaplmaldr.
char *p1, *p2
Yukardaki bildirimde p1 ve p2 char trden gsterici deikenlerdir.
double *p1, *p2, d, a[20];
Yukardaki bildirimde p1 ve p2 double trden gsterici deikenler, d double trden bir
deiken ve a ise elemanlar double trden 20 elemanl bir dizidir.

Gsterici Deikenlerin Uzunluklar

Bir gsterici nesnesinin tanm ile karlaan derleyici dier tanmlamalarda yapt gibibellekte o gsterici deikeni iin yer ayrr. Derleyicilerin gstericiler iin ayrdklar
yerlerin uzunluu donanma bal olup sistemden sisteme deiebilir. 32 bit sistemlerde
(rnein UNIX ve Windows 3.1 sonras sistemlerde) gsterici deikenler 4 byte
uzunluundadr. 8086 mimarisinde ve DOS altnda alan derleyicilerde ise gsterici
deikenler 2 byte ya da 4 byte olabilirler. DOS'ta 2 byte uzunluundaki gstericilere
yakn gstericiler (near pointer), 4 byte uzunluundaki gstericilere ise uzak gstericiler
(far pointer) denir.
Gstericilerin uzunluklar trlerinden bamszdr.

231

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Aadaki program derleyerek altrn:


#include <stdio.h>
int main()
{
char *cp, ch;
int *ip, i;
double *dp, d;
printf("sizeof(ch) = %u\n", sizeof(ch));
printf("sizeof(i) = %u\n", sizeof(i));
printf("sizeof(d) = %u\n", sizeof(d));
printf("sizeof(cp) = %u\n", sizeof(cp));
printf("sizeof(ip) = %u\n", sizeof(ip));
printf("sizeof(dp) = %u\n", sizeof(dp));
printf("sizeof(char *) = %u\n", sizeof(char *));
printf("sizeof(int *) = %u\n", sizeof(int *));
printf("sizeof(double *) = %u\n", sizeof(double *));
}

return 0;

Yukardaki programda hem char, int, double trlerinden hem de char *, int *, double *
trlerinden nesnelerin tanmlandn gryorsunuz. Daha sonra printf ileviyle bu
nesnelerin sizeof deerleri ekrana yazdrlyor. T trnden bir nesnenin sizeof deeri ne
olursa olsun T* trnden bir nesnenin sizeof deeri hep ayndr, deil mi? Yukardaki
program UNIX iletim sistemi iin derlenip altrldnda ekran kts aadaki gibi
olur:
sizeof(ch) = 1
sizeof(i) = 4
sizeof(d) = 8
sizeof(cp) = 4
sizeof(ip) = 4
sizeof(dp) = 4
sizeof(char *) = 4
sizeof(int *) = 4
sizeof(double *) = 4

Adres Bilgisi Olan fadeler

Baz ifadeleri adres trndendir. Yani bu ifadelerin deeri adrestir. Bir gsterici
deikene, tr adres olan ifade yani bir adres deeri atanmaldr.

int *ptr;
gibi tanmlanan bir deiken, iinde int trden bir deikenin adresi olan bilgiyi
saklayacak deikendir. Byle bir adres bilgisi ptr deikenine nasl atanabilir?

Adres Deimezleri
1200,int trden bir tamsay deimezidir. Byle bir deimez, rnein int trden bir
nesneye atanabilir:
int x = 1200;
Tr dntrme ilemiyle bir tamsay deimezi bir adres bilgisine dntrlebilir:
(int *)1200
232

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yukardaki ifadenin tr (int *) trdr. Byle bir ifade int trden bir nesnenin adresi
olabilecek bir bilgidir. int trden 1200 deimezi tr dntrme ileciyle int trden bir
nesnenin adresi olabilecek bir tre dntrlmtr. Adres deimezlerinin yazmnda
geleneksel olarak onaltlk say sistemi kullanlr:
(double *)0x1AC4
Yukardaki ifade, double trden bir nesnenin adresi olabilecek bir bilgidir. Adres bilgisinin
tamsay ksmnn yazlmasnda onaltlk say sisteminin kullanldn gryorsunuz.

Gstericilerle lgili Tr Uyumu

Bir gsterici deikene ayn trden bir adres bilgisi yerletirilmelidir. rnein :
int *p;
p = 100;
Burada p gsterici deikenine adres olmayan bir deer atanyor. Byle bir atamann
yanl olduu kabul edilir. Derleyicilerin hemen hepsi bu durumu mantksal bir uyar iletisi
ile bildirir. Bu durum ileride ayrntl olarak ele alnacak.
[Byle bir atama C++ dilinde geerli deildir.
int *p;
p = (char *) 0x1FC0;
Burada int trden p gstericisine char trden bir adres bilgisi atanyor. Yanl olan bu
durum da derleyicilerin ou tarafndan mantksal bir uyar iletisi ile iaretlenir.
[C++ derleyicileri byle bir atama durumunda da szdizim hatas iletisi vererek ama dosya retimini reddeder]
int *p;
p = (int *) 0x1FC4;

/* geerli ve uygun bir atamadr */

Bir adres bilgisi gstericiye atandnda adresin saysal bileeni gsterici iine yerletirilir.
int *p;
p = (int *) 0x1FC4;
Burada bellekte p gsterici deikeninin tutulduu yere 0x1FC4 saysal deeri yerletirilir.

Gsterici deikenler ilerinde adres bilgileri tadna gre bir gstericiye ayn trden
baka bir gsterici deikenin deerinin atanmas da tamamen uygundur.
int *p, *q;
p = (int *) 0x1AA0;
q = p;
Yukardaki atama ile q gstericisine p gstericisinin deeri atanyor. Yani bu atama
deyiminden sonra q gstericisinin de iinde (int *) 0x1AA0 adresi bulunur.
int k;

233

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

gibi bir tanmlama yapldnda k deikeni int trdendir. indeki deer int trden bir
deer olarak yorumlanr.
20
gibi, tek bir deimezden oluan bir ifade de int trdendir, nk 20 int trden bir
deimezdir. Baka bir deyile k ifadesiyle 20 ifadesinin trleri ayndr. Her iki ifadenin
tr de int trdr. Ancak k ifadesi nesne gsteren bir ifade iken 20 ifadesi nesne
gstermeyen bir ifadedir, yani bir sa taraf deeridir.
Yine bir adres deimezinden oluan
(int *) 0x1A00
ifadesinin tr de int trden bir adrestir, yani (int *) trnden bir ifadedir. Ancak bu
ifade de sol taraf deeri deildir.
Grld gibi gsterici deikenleri, belirli bir adres trnden nesnelerdir. Yani deerleri
adres olan deikenlerdir.

234

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Gsterici leleri

C dilinin baz ileleri adres bilgileri ile ilgili olarak kullanlr. Gstericiler ile ilgili kodlar bu
ileleri kullanr. Gsterici ileleri unlardr:
*
&
[]
->

ierik ileci
adres ileci
keli ayra ileci
ok ileci

indirection operator (dereferencing operator)


address of operator
index operator (subscript operator)
arrow operator

ok ileci yap trnden adreslerle kullanld iin bu ile "yaplar" konusunda ayrntl
olarak incelenecek.

Adres leci

Adres ileci (adress of operator), nek konumunda tek terimli (unary prefix) bir iletir.
le ncelik tablosunun ikinci seviyesinde yer alr. Bu ilecin rettii deer, terimi olan
nesnenin adresidir. Adres ilecinin terimi mutlaka bir nesne olmaldr. nk yalnzca
nesnelerin -sol taraf deerlerinin- adres bilgilerine ulalabilir. Adres ilecinin teriminin
nesne olmayan bir ifade olmas geersizdir.
int k;
gibi bir tanmalamadan sonra yazlan
&k
ifadesini ele alalm. Bu ifadenin rettii deer int trden bir adres bilgisidir.
Bu ifadenin tr (int *) trdr.
& ileci dier tek terimli ileler gibi, ile ncelik tablosunun 2. seviyesinde bulunur. Bu
ncelik seviyesinin ncelik ynnn "sadan sola" olduunu biliyorsunuz.
Bir gsterici deikeni, iinde bir adres bilgisi tutan bir nesne olduuna gre, bir gsterici
deikene adres ilecinin rettii bir adres bilgisi atanabilir.
int x = 20;
int *ptr;
ptr = &x;
Byle bir atamadan sonra unlar sylenebilir:
ptr nesnesinin deeri x deikeninin adresidir. ptr nesnesi x deikeninin adresini tutar.
Adres ileci ile elde edilen adres, ayn trden bir gsterici deikene atanmaldr. rnein
aadaki programda bir gsterici deikene farkl trden bir adres atanyor:
char ch = 'x';
int *p;
p = &ch;

/* Yanl */

Tabi bu ilecin rettii adres bilgisi de sol taraf deeri deildir. rnein:
int x;
++&x

/* Geersiz */

gibi bir ilem hata ile sonulanr. Artrma ilecinin terimi nesne olmaldr. Yukardaki
ifadede ++ ilecinin terimi olan &x ifadesi bir nesne deildir. Yalnzca bir adres deeridir.

235

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Adres Deerlerinin Ekrana Yazdrlmas

Standart printf ilevi ile doal veri trlerinden ifadelerin deerlerinin ekrana
yazdrlabileceini biliyorsunuz. Bir ifadenin deerini ekrana yazdrmak iin, printf
ileviyle birinci argman olarak geilen dizge iinde nceden belirlenmi format
karakterlerinin (conversion specifiers) kullanldn hatrlayn. Acaba bir adres bilgisi de
uygun format karakteri kullanlarak ekrana yazdrlabilir mi? Evet! Standart printf
ilevinde bu ama iin %p format karakterleri kullanlr. %p format karakterleri ile
elenen argman bir adres bilgisi ise, printf ilevi ilgili adres bilgisinin yalnzca saysal
bileenini onaltlk say sisteminde ekrana yazdrr.
Aadaki program derleyerek altrn:
#include <stdio.h>
int main()
{
int *ptr;
int x = 20;
ptr = &x;
printf("x nesnesinin adresi = %p\n", &x);
printf("ptr deikeninin deeri = %p\n", ptr);
printf("ptr nesnesinin adresi = %p\n", &ptr);
}

return 0;

ptr bir nesne olduu iin ptr nesnesi de adres ilecinin terimi olabilir, deil mi? ptr
nesnesinin deeri olan adres, x nesnesinin adresidir. Ama ptr nesnesinin kendi
adresinden de sz edilebilir. Bir gsterici deikenin deeri olan adres ile gsterici
deikenin kendi adresi farkl eylerdir.
printf("ptr nesnesinin adresi = %p\n", &ptr);
arsyla ptr deikeninin kendi adresi ekrana yazdrlyor.

Dizi simlerinin Adres Bilgisine Dntrlmesi

C dilinde dizi isimleri bir ileme sokulduunda derleyici tarafndan otomatik olarak bir
adres bilgisine dntrlr.
char s[5];
gibi bir dizi tanmlamasnda sonra, dizinin ismi olan s bir ileme sokulduunda bu dizinin
ilk elemannn adresine dntrlr.
Dizi isimleri derleyici tarafndan, diziler iin bellekte ayrlan bloklarn balang yerini
gsteren bir adres bilgisine dntrlr. Yukardaki rnekte dizinin bellekte aadaki
ekilde yerletirildiini dnn:

s[0]
s[1]
s[2]
s[3]
s[4]

1C00
1C01
1C02
1C03
1C04

Bu durumda dizi ismi olan s, char trden 1C00 adresine edeerdir. Yani bu adresi bir
adres deimezi eklinde yazlm olsayd:
(char *)0x1COO

236

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

biiminde yazlrd.
Bu durumda s ifadesi ile &s[0] ifadesi ayn adres bilgisidir, deil mi?
Gsterici deikenlere kendi trlerinden bir adres bilgisi atamak gerektiine gre
aadaki atamalarn hepsi geerli ve dorudur:
int a[100];
long l[20];
char s[100];
double d[10];
int *p;
long *lp;
char *cp;
double *dp;
p = a;
lp = l;
cp = s;
dp = d;
Bir gstericiye yalnzca ayn trden bir dizinin ismi atanabilir. rnein:
int *p;
char s[] = "Necati";
p = s;
/YANLI */

Dizi simleri Nesne Gstermez


int a[100];
int *ptr;
gibi bir tanmlamadan sonra
a
gibi bir ifade kullanlrsa, bu iafade derleyici tarafndan otomatik olarak int * trne
dntrlr. Yani bu ifadenin tr de (int *) trdr.
ptr
ifadesi nesne gsteren bir ifadeyken, yani bir sol taraf deeriyken,
a
ifadesi nesne gstermeyen bir ifade deeridir. Deitirilebilir sol taraf deeri (modifiable L
value) olarak kullanlamaz. rnein
a++
ifadesi geersizdir.
C dilinde hibir deikenin ya da dizinin programn alma zamannda bulunaca yer
programc tarafndan belirlenemez. Programc deikeni tanmlar, derleyici onu herhangi
bir yere yerletirebilir.
Dizi isimleri gstericiler gibi sol taraf deeri olarak kullanlamaz. rnein, s bir dizi ismi
olmak zere

237

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

++s;
deyimi geersizdir.

* erik leci

erik ileci (indirection operator / dereferencing operator) de, nek konumunda bulunan
tek terimli (unary prefix) bir iletir. erik ilecinin terimi bir adres bilgisi olmaldr. Bir
adres ifadesi, * ilecinin terimi olduunda, elde edilen ifade bellekte o adreste bulunan,
nesneyi temsil eder. Dolaysyla, * ileci ile oluturulan bir ifade bir nesneye karlk gelir,
sol taraf deeri olarak kullanlabilir.
int a;
gibi bir bildirimde a nesnesinin tr int trdr. nk a nesnesi iinde int trden bir veri
tutulur.
int *p;
bildiriminde p'nin tr int trden bir adrestir. Yani p nesnesinin tr (int *) trdr. p
nesnesinin iinde (int *) trnden bir veri tutulur.
char *ptr;
gibi bir bildirimden iki ey anlalr:
ptr char trden bir gstericidir. ine char trden bir adres bilgisi yerletirilmek iin
tanmlanmtr. ptr gstericisi * ileci ile birlikte kullanldnda elde edilen nesne char
trdendir. Yani *ptr char trden bir nesnedir.
rnein:
int *p;
p = (int *) 0x1FC2;
*p = 100;
Burada *p'nin tr int trdr. Dolaysyla *p = 100 gibi bir ilemden (DOS altnda)
yalnzca 0x1FC2 byte' deil, 0x1FC2 ve 0x1FC3 byte'larnn her ikisi birden etkilenir.
Gstericinin iindeki adresin saysal bileeni nesnenin dk anlaml byte'nn adresini
ierir. Bu durumda bir gsterici deikene, bellekteki herhangi bir blgenin adresi
atanabilir. Daha sonra * ileci ile o bellek blgesine eriilebilir.
* ilecinin terimi bir adres bilgisi olmak zorundadr. Yani terim adres deimezi olabilir,
dizi ismi olabilir, bir gsterici deiken olabilir veya adres ileci ile elde edilmi bir adres
ifadesi olabilir.
erik ileci yalnz gsterici nesneleriyle deil, adres bilgisinin her biimi ile (adres
deimezleri ve dizi isimleri vs.) kullanlabilir. Bu ile, terimi olan adresteki nesneye
erimekte kullanlr. le ile elde edilen deer, terimi olan adreste bulunan nesnenin
deerdir.
erik ileci ile retilen bir ifade nesne belirtir. Nesnenin tr terim olan nesnenin adresi
ile ayn trdendir.
Aadaki program derleyerek altrn, ekran ktsn yorumlayn:
#include <stdio.h>
int main()
{
char s[] = "Balkesir";
238

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

int a[] = {1, 2, 3, 4, 5};


int x = 10;
int *ptr;
putchar(*s);
printf("%d\n", *a);
*&x = 20;
printf("x = %d\n", x);
ptr = &x;
*ptr = 30;
printf("x = %d\n", x);
}

return 0;

Yukardaki programda,
i) s char trden bir dizinin ismi olduuna gre char trden bir adrese dntrlr. Bu
adres s dizisinin balang adresidir. *s ifadesi bu adresteki nesne olduuna gre, *s
ifadesi dizimizin ilk eleman olan nesnedir, yani *s ifadesinin deeri 'B'dir, deil mi?
ii) a int trden bir dizinin ismi olduuna gre int trden bir adrese dntrlr. Bu adres
a dizisinin balang adresidir. *a ifadesi bu adresteki nesne olduuna gre, *a ifadesi int
trden dizimizin ilk eleman olan nesnedir, yani *a ifadesi a[0] nesnesidir. Bu nesnenin
deeri 1'dir.
iii) *&x ifadesinde ise iki ayr ile kullanlyor. Adres ve ierik ileleri. Bu ilelerin her
ikisi de ile ncelik tablosunda ikinci seviyede yer alyor. le ncelik tablosunun ikinci
seviyesine ilikin ncelik yn sadan sola olduuna gre, ifadenin deerlendirilmesinde
nce adres ileci deer retir. Adres ilecinin rettii deer x nesnesinin adresidir, ierik
ilecinin terimi bu adres olur. erik ileci o adresteki nesneye ulatna gre *&x ifadesi
x nesnesinin adresindeki nesne, yani x nesnesinin kendisidir.
iv) ptr gstericisine x nesnesinin adresi atanyor. erik ilecinin terimi ptr nesnesi
olduundan, ptr nesnesinin deeri olan adresteki nesneye ulalr. Bu durumda da *ptr
nesnesi yine x nesnesinin kendisidir, deil mi?
erik ilecinin ncelik tablosunun ikinci dzeyinde olduunu biliyorsunuz. s bir dizi ismi
olmak zere
*s + 1;
ifadesinde nce ierik ileci deer retir. erik ilecinin rettii deer toplama ilecinin
terimi olur. Oysa ifade
*(s + 1)
biiminde olsayd nce + ileci ele alnrd.
Derleyiciler * atomu ieren bir ifadede * atomunun arpma ileci mi yoksa adres ileci
mi olduunu ifade iindeki kullanmna bakarak anlar. arpma ileci iki terimli iken ierik
ileci tek terimli nek konumunda bir iletir.
*s * 2
ifadesinde birinci '*' ierik ileci iken ikincisi * aritmetik arpma ilecidir.

239

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Bir Gstericinin Bir Nesneyi Gstermesi


int x = 20;
int *ptr ;
ptr = &x;
*ptr = 30;
Yukardaki kod parasnda ptr gstericisine int trden x nesnesinin adresi atanyor. Bu
atamadan sonra ptr gstericisinin deeri x nesnesinin adresidir. Bu durumda "ptr x
deikenini gsteriyor" denir.
ptr x'i gsteriyor ise *ptr, x nesnesinin kendisidir. Daha genel bir syleyile, ptr bir
gsterici deiken ise *ptr o gstericinin gsterdii nesnedir!
Tanmlanan bir deikene deikenin ismiyle dorudan ulaabildiiniz gibi, onu gsteren
bir gstericiyi ierik ilecine terim yaparak dolayl bir biimde ulaabilirsiniz, deil mi?
lecin ngilizce ismi olan "indirection operator" de bu durumu vurgular.

Parametre Deikeni Gsterici Olan levler

Gstericiler daha ok bir ilevin parametre deikeni olarak kullanlr. Bir gsterici bir
nesne olduuna gre bir ilevin parametre deikeni herhangi bir trden gsterici olabilir:
void func(int *p)
{
/***/
}
levlerin parametre deikenleri, ilev arlaryla kendilerine geilen argman
ifadeleriyle ilkdeerlerini aldna gre, bir ilevin parametre deikeni bir gsterici ise
ilev de ayn trden bir adres bilgisi ile arlmaldr.
Byle bir ilev, parametre deikenine adresi kopyalanan yerel bir deikenin deerini
deitirebilir:
#include <stdio.h>
void func(int *ptr)
{
*ptr = 20;
}
int main()
{
int a = 10;
func(&a);
printf("%d\n", a);
}

return 0;

Yukardaki rnekte main ilevi iinde tanmlanan yerel a isimli deikenin adresi func
ilevine gnderiliyor. func ilevi arldnda, yaratlan parametre deikeni ptr
ilkdeerini &a ifadesinden alr. levin koduna geildiinde artk parametre deikeni olan
ptr gsterici deikeni, adresi gnderilen a nesnesini gsterir. Bu durumda
*ptr
ifadesi a nesnesinin kendisidir.

240

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

*ptr = 20;
deyimiyle a nesnesine 20 deeri atanr, deil mi?
Bir ilev bir deer elde edip aran ileve bu deeri iletmek isterse iki yntem
kullanlabilir:
i. Elde edilen deer arlan ilev tarafndan geri dn deeri olarak retilir.
ii. Elde edilen deer aran ilevin gndermi olduu adrese yerletirilir. Tabi bunun iin
arlan ilevin parametre deikeninin bir gsterici olmas gerekir. Aada kendisine
gnderilen bir saynn faktoriyelini hesaplayarak bu deeri parametre olarak gnderilen
adrese kopyalayan bir ilev yazlyor:
#include <stdio.h>
void factorial(int n, long *p);
int main()
{
long a;
int k;
for (k = 0; k < 14; ++k) {
factorial(k, &a);
printf ("%2d! = %ld\n", k, a);
}
}

return 0;

void factorial(int n, long *p)


{
*p = 1;
if (n == 0 || n == 1)
return;
while (n > 1)
*p *= n--;
}
a bir yerel deiken olsun. C dilinde bir ilev
func(a);
biiminde arlmsa, arlan bu ilevin, a deikenini deitirme ans yoktur. Bu tr
ilev arsna "deer ile arma" (call by value) denir. "levler" konusunda
anmsayacanz gibi bu durumda a deikeninin deeri func ilevinin parametre
deikenine kopyalanarak aktarlr. Yani func ilevinin parametre deikeni x nesnesinin
kendisi deildir. func ilevinin kodu grlmese de ilev arsndan sonra yerel a
deikeninin deerinin deimedii sylenebilir.
levin a deikeninin deitirebilmesi iin
func(&a);
biiminde arlmas gerekir. rnein standart scanf ilevine & ileci ile bir nesnenin
adresinin argman olarak yollanmasnn nedeni budur. Bu biimde yaplan ilev arsna

241

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

C'de "adres ile arma" (call by reference) denir. Byle bir arda ileve bir nesnenin
adresi gnderilir. levin parametre deikeni de bu adresi tutacak bir gsterici olur.
int trden iki yerel nesnenin deerleri takas edilmek istensin. Bu i, bulunulan ilev iinde
aadaki gibi yaplabilir:
int main()
{
int a = 10, b = 20, temp;

temp = a;
a = b;
b = temp;
/*....*/

Takas ileminin bir ilev tarafndan yaplmas istenirse, aadaki gibi bir ilev i grr
myd?
void swap(int x, int y)
{
int temp = x;
x = y;
y = temp;
}
int main()
{
int a = 10, b = 20;
swap(a, b);
printf("a = %d\nb = %d\n", a, b);
}

return 0;

Yukardaki program altrdnda ekrana


a = 10
b = 20
yazar! Yazlan swap ilevi a ve b deikenlerinin deerlerini deitirmez. Yerel nesneler
olan a ve b deikenlerinin deerleri ancak bu deikenlerin adresleri bir ileve
gnderilerek deitirilebilirdi. Oysa yukardaki swap ilevi a ve b deikenlerinin
deerlerini parametre deikenleri olan x ve y deikenlerine kopyalyor. Yani deerleri
deitirilen parametre deikenleri olan x ve y.
Takas ilemini yapacak ilev kendisini aracak kod parasndan adres deerleri alaca
iin gsterici parametre deikenlerine sahip olmal:
void swap(int *p1, int *p2)
{
int temp = *p1;
*p1 = *p2;
*p2 = temp;
}

242

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Adreslerle lemler - Adreslerin Artrlmas ve Eksiltilmesi


(Gsterici Aritmetii)

C dilinde bir adres bilgisi bir tamsay ile toplanabilir, bir adres bilgisinden bir tamsay
kartlabilir. Byle bir ifade toplanan ya da kartlan adres trndendir. rnein int
trden bir nesnenin adresi ile 1 tamsays toplanrsa yine int trden bir nesnenin adresi
bilgisi elde edilir.
Bir adres bilgisine 1 toplandnda, adresin saysal bileeni adrese sahip nesnenin
trnn uzunluu kadar artar. Bu durumda rnein DOS iletim sisteminde char trden
bir gstericinin deeri, 1 artrldnda adresin saysal bileeni 1, int trden bir gsterici 1
artrldnda ise adresin saysal bileeni 2 artar, double trden bir gsterici 1
artrldnda ise adresin saysal bileeni 8 artar.
Bir gsterici deikenin bellekte bir nesneyi gsterdiini dnelim. Bu gsterici
deikenin deeri 1 artrlrsa bu kez gsterici deikeni, gsterdii nesneden bir sonraki
nesneyi gsterir duruma gelir.
#include <stdio.h>
int main()
{
int k;
int a[10];
for (k = 0; k < 10; ++k) {
*(a + k) = k;
printf("%d ", a[k]);
}
}

return 0;

Yukardaki rnekte main ilevi iinde tanmlanan a dizisinin elemanlarna gsterici


aritmetii kullanlarak ulalyor.
*(a + k)
a adresinden k uzaklktaki nesne anlamna gelir. Bu da dizinin k indisli elemandr, deil
mi? Dizi int trden deil de double trden olsayd dizinin elemanlarna yine byle
ulalabilirdi, deil mi?
Gsterici aritmetii trden bamsz bir soyutlama salar.
ki adres bilgisinin toplanmas geersizdir. Ancak ayn dizi zerindeki iki adres bilgisi
birbirinden kartlabilir. ki adres birbirinden kartlrsa sonu bir tamsay trndendir.
ki adres birbirinden kartldnda nce adreslerin saysal bileenleri kartlr, sonra elde
edilen deer adresin ait olduu trn uzunluuna blnr. rnein a int bir dizi olmak
zere trden bir adres olmak zere:
&a[2] - &a[0] ifadesinden elde edilen deer 2 dir.
Aadaki programda gsterici aritmetii sorgulanyor. Program derleyerek altrn ve
ekran ktsn inceleyerek yorumlamaya aln:
#include <stdio.h>
int main()
{
char s[10];
int a[10];
double d[10];

243

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

printf("%p\n",
printf("%p\n",
printf("%p\n",
printf("%d\n",
printf("%d\n",
printf("%d\n",
}

(char *)0x1AC0 + 1);


(int *)0x1AC0 + 1);
(double *)0x1AC0 + 1);
&s[9] - &s[0]);
&a[9] - &a[0]);
&d[9] - &d[0]);

return 0;

Adres deerlerinin karlatrlmas

Ayn blok zerindeki iki adres, karlatrma ileleriyle karlatrlabilir:


#include <stdio.h>
int main()
{
int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int *ptr = a;
while (ptr < a + 10) {
printf("%d ", *ptr);
++ptr;
}
return 0;
}

[] Keli Ayra leci :

Daha nce dizi elemanlarna erimekte kullandmz keli ayra aslnda iki terimli bir
gsterici ilecidir. Keli ayra ileci (index / subscript operator) ile ncelik tablosunun
en yksek ncelik seviyesindedir. lecin birinci terimi keli ayratan nce yer alr. Bu
terim bir adres bilgisi olur. kinci terim ise keli ayra iine yazlacak tam say trnden
bir ifade olur.
p[n]
ifadesi ile
*(p + n)
tamamen edeer ifadelerdir.
Yani keli ayra ileci, bir adresten n ilerideki nesneye erimek iin kullanlr. [] ileci ile
elde edilen nesnenin tr terimi olan adresin tr ile ayn trdendir. Aadaki programn
ekrana ne yazdracan nce tahmine etmeye aln. Daha sonra program derleyip
altrn:

244

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
int main()
{
int a[5] = {1, 2, 3, 4, 5};
int *ptr = a + 2;
printf("%d\n", ptr[-1]);
printf("%d\n", ptr[0]);
printf("%d\n", ptr[1]);
}

return 0;

[] ilecinin birinci terimi dizi ismi olmak zorunda deildir. Daha nce de belirtildii gibi bir
dizinin ismi bir ifade iinde kullanldnda derleyici tarafndan o dizinin ilk elemannn
adresine yani dizinin balang adresine dntrlr.
[] ileci ile ncelik tablosunun en yksek dzeyinde bulunur. rnein:
&p[n]
ifadesinde nce keli ayra ileci deer retir. lecin rettii deer, bir nesneye
ilikindir. Adres ilecinin ncelik seviyesi keli ayra ilecinden daha dk olduu iin,
ilecin ulat nesne bu kez adres ilecinin terimi olur.
phesiz [] iindeki ifadenin saysal deeri negatif olabilir. rnein
p[-2]
geerli bir ifadedir. Benzer ekilde bu ifade
*(p - 2)
ifadesi ile ayn anlamdadr.
Aadaki rnekte keli ayra ileci ile adres ileci ayn ifade iinde kullanlyor.
#include <stdio.h>
int main()
{
char ch = 'A';
(&ch)[0] = 'B'
putchar(ch);
}

return 0;

++ ve -- lelerinin Gsterici leleriyle Birlikte Kullanlmas

C dilinin bir ok kod kalbnda gsterici ileleriyle ile artrma ya da eksiltme ileci birlikte
kullanlr.
1. erik ileci ile ++ ilecinin ayn ifade iinde yer almas
a) ++*p durumu

245

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
int main()
{
int a[5] = {1, 2, 3, 4, 5};
int k;
int *ptr = a;
++*ptr;
for (k = 0; k < 5; ++k)
printf("%d ", a[k]);
}

/* 2 2 3 4 5 */

return 0;

++*ptr ifadesinde iki ile kullanlyor: erik ileci ile artrma ileci. Her iki ile de ile
ncelik tablosunun ikinci seviyesinde bulunur. kinci seviyenin ncelik yn sadan sola
olduuna gre nce daha sada bulunan ierik ileci deer retir. erik ileci ptr
gstericisinin gsterdii nesneye ular bylece bu nesne, artrma ilecine terim olur. Bu
durumda ptr gstericisinin gsterdii nesnenin deeri 1 artrlr. Ksaca
++*ptr;
deyimi , "ptr'nin gsterdii nesnenin deerini 1 artr" anlamna gelir.
*++p durumu
p gstericisinin 1 fazlas olan adresteki nesneye ulalr. Yani ifadenin deeri p
gstericisinin gsterdii nesneyi izleyen nesnenin deeridir. Tabi ifadenin
deerlendirilmesinden sonra ++ ilecinin yan etkisinden dolay p gstericisinin deeri 1
artrlr. Yani ptr bir sonraki nesneyi gsterir. Aadaki rnei dikkatle inceleyin:
#include <stdio.h>
int main()
{
int a[5] = {1, 2, 3, 4, 5};
int k;
int *ptr = a;
*++ptr = 10;
*ptr = 20;
for (k = 0; k < 5; ++k)
printf("%d ", a[k]);

/* 1 20 3 4 5 */

return 0;
}
x = *++p;
deyimi ile x deikenine artrlm adresteki bilgi atanr.
*p++ durumu
++ ileci ve * ilecinin ikisi de ikinci ncelik seviyesindedir. Bu ncelik seviyesine ilikin
ncelik yn sadan soladr. nce ++ ileci ele alnr ve bu ile ifadenin geri kalan
ksmna p gstericisinin artmam deerini retir. Bu adresteki nesneye ulalr daha
sonra p gstericisinin deeri 1 artrlr. *p++ ifadesinin deeri p gstericisinin gsterdii

246

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

nesnenin deeridir. ++ ilecinin yan etkisinden dolay ifadenin deerlendirilmesinden


sonra p gstericisinin deeri 1 artrlr. Yani p bir sonraki nesneyi gsterir. Aadaki
rnei inceleyin:
#include <stdio.h>
int main()
{
int a[5] = {1, 2, 3, 4, 5};
int k;
int *ptr = a;
*ptr++ = 10;
*ptr = 20;
for (k = 0; k < 5; ++k)
printf("%d ", a[k]);
}

/* 10 20 3 4 5 */

return 0;

Adres ileci ile ++ ilecinin ayn ifade iinde yer almas


&x++
/* Geersiz*/
x++ ifadesinin rettii deer adres ilecinin terimi olur. x++ ifadesinin rettii deer sol
taraf deeri deildir. Adres ilecinin teriminin sol taraf deeri olmas gerekir. Bu durumda
derleme zamannda hata oluur.
&++x
/* Geersiz */
++x ifadesinin rettii deer adres ilecinin terimi olur. ++x ifadesinin rettii deer sol
taraf deeri deildir ve adres ilecinin teriminin sol taraf deeri olmas gerekir. fade
geersizdir.
[C++ dilinde nek ++ ilecini bir sol taraf deeri rettii iin bu ifade C++ da geerlidir.]
++&x
/* Geersiz */
Adres ilecinin rettii deer nek konumundaki artrma ilecinin terimi olur. ++ ilecinin
teriminin nesne gsteren bir ifade olmas gerekir. Oysa &x ifadesi nesne gsteren bir
ifade deildir. fade geersizdir.
Adres ileci (&) ile artrma (++) ya da eksiltme (--) ilelerinin her trl bileimi derleme
zamannda hata olumasna neden olur.
Keli ayra ileci ile ++ ilecinin ayn ifade iinde yer almas
++p[i] durumu
Keli ayra ileci birinci ncelik seviyesinde, ++ ileci ise ikinci ncelik seviyesindedir.
Bu durumda derleyici tarafndan nce keli ayra ileci ele alnr. p[i] ifadesi bir nesne
gsterir. Dolaysyla ++ ilecinin terimi olmasnda bir saknca yoktur. Sz konusu ifade
p[i] = p[i] + 1;
anlamna gelir. Yani p[i] nesnesinin deeri 1 artrlr.
p[i]++ durumu
x = p[i]++;
nce p[i] nesnesinin artmam deeri retilir, ifadenin geri kalannda p[i] nesnesinin
artmam deeri kullanlr. Yani yukardaki rnekte x deikenine p[i] nesnesinin
artrlmam deeri atanr, daha sonra p[i] nesnesi 1 artrlr.

247

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

p[++i] durumu
x = p[++i];
nce ++i ifadesinin deeri elde edilir. Bu ifadenin deeri i'nin deerinin 1 fazlasdr. Daha
sonra p adresinden (i + 1) uzaklktaki nesneye ulalr. ++ ilecinin yan etkisi olarak i
deikeninin deeri 1 artrlr.
p[i++] durumu
x = p[i++];
nce i++ ifadesinin deeri elde edilir. Bu ifadenin deeri i'nin kendi deeridir. Daha sonra
p adresinden i uzaklktaki nesneye ulalr. ++ ilecinin yan etkisi olarak i deikeninin
deeri 1 artrlr.

Gsterici Deikenlere lkdeer Verilmesi

Dier trden deikenlerde olduu gibi gsterici deikenlere de tanmlanmalar srasnda


ilkdeer verilebilir. Gstericilere ilkdeer verme ilemi gstericinin trnden bir adres
bilgisi ile yaplmaldr.
rnekler:
char s[100];
double x;
int *ptr = (int *) 0x1A00;
char * str = (char *) 0x1FC0;
char *p = s;
double *dbptr = &x;
int i, *ptr = &i;
Son deyimde tanmlanan i isimli deiken int trden, ptr isimli deiken ise int *
trdendir. ptr deikenine ayn deyimle tanmlanan i deikeninin adresi atanyor.

Dizilerin levlere Gstericiler Yoluyla Geirilmesi

Bir dizinin balang adresi ve boyutu bir ileve gnderilirse ilev dizi zerinde ilem
yapabilir. levin dizinin balang adresini alacak parametresi ayn trden bir gsterici
deiken olmaldr. levin dier parametresi dizinin boyutunu tutacak int trden bir
deiken olabilir.
Bir dizinin balang adresini parametre olarak alan ilev, dizi elemanlarna keli ayra
ileci ya da ierik ileci ile eriebilir. Ancak dizi elemanlarnn ka tane olduu bilgisi ilev
tarafndan bilinemez. Bu nedenle dizi uzunluu ikinci bir argman olarak ileve gnderilir.
rnek:

248

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
void display_array (const int *p, int size)
{
int i;

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


printf("%d ", p[i]);

int main()
{
int a[5] = {3, 8, 7, 6, 10};
display_array(a, 5);
return 0;
}
Yukarda tanmlanan display_array ilevi int trden bir dizinin balang adresini ve
boyutunu alyor, dizinin tm elemanlarnn deerlerini ekrana yazdryor. Parametre
deikeni olan p gstericisinin bildiriminde yer alan const anahtar szcne daha sonra
deinilecek.
Aada ayn ilev iini yaparken bu kez ierik ilevini kullanyor:
void display_array (const int *p, int size)
{
while (size--)
printf("%d ", *p++);
}

Gsterici Parametre Deikenlerinin Tanmlanmas


Bir ilevin parametre deikeninin gsterici olmas durumunda, bu gsterici iki farkl
biimde tanmlanabilir:
void func(int *ptr);
void func(int ptr[]);
Derleyici asndan iki biim arasnda hibir farkllk yoktur. Ancak baz programclar, ilev
dardan bir dizinin balang adresini istiyorsa ikinci biimi tercih ederler:
void sort_array(int ptr[], int size);
Bu biim yalnzca ilev paraemtresi olan gstericilere ilikindir. Global ya da yerel
gstericiler bu biimde tanmlanamaz:
void foo(void)
{
int ptr[]; /* Geersiz */
}
Aada int trden dizilerle ilgili baz faydal ilemler yapan ilevler tasarlanyor. levlerin
tanmlarn dikkatli bir ekilde inceleyin. levlerin bazlarnn parametreleri olan
gstericilerin bildiriminde const anahtar szcnn kullanldn greceksiniz. const
anahtar szcn imdilik gznne almayn. Bu anahtar szck ileride ayrntl bir
biimde ele alnacak.

249

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Diziler zerinde lem Yapan levlere rnekler

Aada bir dizinin elemanlarna rastgele deerler yerletirmek amacyla bir ilev
tanmlanyor:
void set_random_array(int *ptr, int size, int max_val)
{
int k;

for (k = 0; k < size; ++k)


ptr[k] = rand() % (max_val + 1);

Bu ilev balang adresini ve boyutunu ald dizinin elemanlarn 0 max_val aralnda


rastgele deerlerle dolduruyor.
int sum_array(const int *ptr, int size)
{
int sum = 0;
int k;
for (k = 0; k < size; ++k)
sum += ptr[k];
return sum;
}
sum_array ilevi dizinin elemanlarnn toplam deeriyle geri dnyor. Dizinin tm
elemanlarnn deeri sum isimli yerel nesneye katlyor. lev sum nesnesinin deeri ile
geri dnyor.
int max_array(const int *ptr, int size)
{
int max = *ptr;
int k;
for (k = 1; k < size; ++k)
if (ptr[k] > max)
max = ptr[k];
}

return max;

int min_array(const int *ptr, int size)


{
int min = *ptr;
int k;
for (k = 1; k < size; ++k)
if (ptr[k] < min)
min = ptr[k];
}

return min;

max_array ilevi adresini ve boyutunu ald dizinin en byk elemannn deeri ile geri
dnyor. min_array ilevi ise, benzer ekilde en kk elemann deeriyle geri dnyor.

250

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

void sort_array(int *ptr, int size)


{
int i, k, temp;
for (i = 0; i < size - 1; ++i)
for (k = 0; k < size - 1 - i; ++k)
if (ptr[k] > ptr[k + 1]) {
temp = ptr[k];
ptr[k] = ptr[k + 1];
ptr[k + 1] = temp;
}
}
sort_array ilevi adresini ve boyutunu ald diziyi" kabarck sralamas" algoritmasyla
kkten bye doru sralyor.
Aada yazlan ilevleri snayan bir main ilevi gryorsunuz. Tm ilevlerin tanmn
main ilevinin tanm ile birlikte derleyerek program altrn:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define

SIZE

100

int main()
{
int a[ARRAY_SIZE];
srand(time(0));
set_random_array(a, SIZE, 1000);
printf("dizi 0 - 1000 araliginda
printf("dizi yazdiriliyor!\n");
display_array(a, SIZE);
printf("dizinin toplami = %d\n",
printf("dizinin en buyuk elemani
printf("dizinin en kucuk elemani
sort_array(a, SIZE);
printf("dizi siralama isleminden
display_array(a, SIZE);

rastgele sayilarla dolduruldu!\n");


sum_array(a, ARRAY_SIZE));
= %d\n", max_array(a, SIZE));
= %d\n", min_array(a, SIZE));
sonra yazdiriliyor!\n");

return 0;
}

levlerin Kendilerine Geilen Adres Bilgilerini Baka levlere


Gemeleri

levler baka ilevleri arabilir, ardklar ilevlere kendi parametre deikenlerine


geilen bilgileri argman olarak gnderebilir. phesiz bu durum parametreleri gsterici
olan ilevler iin de geerlidir.
int trden bir dizinin aritmetik ortalamasn hesaplamak amacyla mean_array isimli bir
ilev tanmlayalm. Dizinin aritmetik ortalamasn bulmak iin nce toplamn bulmak
gerekir, deil mi?

double mean_array(const int *ptr, int size)


{
return (double)sum_array(ptr, size) / size;
}
mean_array ilevi, kendisine geilen dizi adresi ile dizi boyutunu, dizinin toplamn
hesaplamak amacyla sum_array ilevine argman olarak geiyor.

251

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

sort_array ilevinde ise, dizinin ardk iki eleman doru srada deil ise bu elemanlar
takas ediliyor. nce int trden iki nesnenin deerini takas edecek bir ilev yazalm.
Yazdmz bu ilevi sort_array ilevi iinde aralm:
void swap(int *p1, int *p2)
{
int temp = *p1;
*p1 = *p2;
*p2 = temp;
}
void sort_array(int *ptr, int size)
{
int i, k;

for (i = 0; i < size - 1; ++i)


for (k = 0; k < size - 1 - i; ++k)
if (ptr[k] > ptr[k + 1])
swap(ptr + k, ptr + k + 1);

sort_array ilevinde
if (ptr[k] > ptr[k + 1])
swap(ptr + k, ptr + k + 1);
deyimine dikkat edin. Bu deyimle, dardan adresi alnan dizinin k indisli eleman, k + 1
indisli elemanndan daha bykse, dizinin k ve k + 1 indisli eleman olan nesnelerin
deerleri swap ilevi arlarak takas ediliyor. swap ilevine argman olarak iki nesnenin
de adresi geiliyor. swap ilevi aadaki gibi de arlabilirdi, deil mi?
swap(&ptr[k], &ptr[k + 1]);
Aada bir diziyi ters eviren reverse_array isimli ilev tanmlanyor:
void reverse_array(int *ptr, int size)
{
int *pend = ptr + size - 1;
int n = size / 2;

while (n--)
swap(ptr++, pend--);

pend gsterici deikenine dizinin son elemannn balang adresi atanyor.


while dngs dizinin eleman saysnn yars kadar dnyor. Dngnn her turunda,
dizinin batan n. eleman ile sondan n. eleman takas ediliyor. ptr ve pend gsterici
deikenleri, sonek konumunda olan ++ ve -- ilelerinin terimi oluyor. Dngnn her
turunda ilelerin yan etkisi nedeniyle, ptr gstericisi bir sonraki nesneyi gsterirken,
pend gstericisi bir nceki nesneyi gsteriyor.

Geri Dn Deeri Adres Trnden Olan levler

Bir ilevin parametre deikeni bir adres trnden olabildii gibi, bir ilevin geri dn
deeri de bir adres trnden olabilir. Byle bir ilevin tanmnda, ilevin geri dn
deerinin trnn yazlaca yere bir adres tr yazlr.
rnein int trden bir nesnenin adresini dndren func isimli ilev aadaki gibi
tanmlanabilir:

252

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

int *func(void)
{
/***/
}
func ilevinin geri dn deeri tr yerine int * yazldn gryorsunuz. Yukardaki ilev
tanmndan * atomu kaldrlrsa, ilevin int trden bir deer dndrd anlalr.
Adrese geri dnen bir ilev ne anlama gelir? lev arld yere, int trden bir nesnenin
adresini iletir. lev ar ifadesi, ilevin geri dn deerine yani bir adres bilgisine
edeerdir. levin geri dn deeri bir nesnede saklanmak istenirse ayn trden bir
gsterici deikene atanmaldr:
int *ptr;
ptr = func();
Benzer biimde:
levlerin geri dn deerlerini geici bir nesne yardmyla oluturduklarn biliyorsunuz.
Bir ilevin geri dn deerinin tr, geri dn deerini iinde tayacak geici nesnenin
trdr. Bu durumda, bir adres trne geri dnen bir ilevin, geri dn deerini iinde
tutacak geici nesne de bir gstericidir.
Bir adres bilgisiyle geri dnen ilevlere C programlarnda ok rastlanr. Standart C
ilevlerinin bazlar da, adres trnden bir deer dndrr.
Aadaki kod parasn inceleyin:
#include <stdio.h>
int g = 10;
int *foo()
{
return &g;
}
int main()
{
int *ptr;
printf("g = %d\n", g);
ptr = foo();
*ptr = 20;
printf("g = %d\n", g);
}

return 0;

foo ilevi arldnda global g isimli deikenin adresini dndryor. lev geri dn
deerini
return &g;
deyimiyle retiyor. &g ifadesi (int *) trndendir. Bu ifadenin deeri yine (int *)
trnden olan geici nesneye atanyor. main ilevi iinde arlan foo ilevinin geri
dndrd adres, ptr gsterici deikenine atanyor.
Bir dizinin en byk elemann bulup bu elemann deerine geri dnen getmax isimli ilev
daha nce yazlmt. Aada ayn ilev bu kez en byk dizi elemannn adresine geri
dnecek ekilde yazlyor:

253

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

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

SIZE

20

int *getmax(const int *p, int size)


{
int *pmax, i;

pmax = (int *)p;


for (i = 1; i < size; ++i)
if (p[i] > *pmax)
pmax = (int *)(p + i);
return pmax;

int main()
{
int a[SIZE];
int k;
srand(time(0));
for (k = 0; k < SIZE; ++k) {
a[k] = rand() % 1000;
printf("%d ", a[k]);
}
printf("\n");
printf("max = %d\n", *getmax(a, SIZE));
}

return 0;

levin kodunu inceleyin. Yerel pmax gsterici deikeni, dizinin en byk elemannn
adresini tutmak iin tanmlanyor. Balangta dizinin ilk eleman en byk kabul
edildiinden, pmax gstericisine nce dizinin ilk elemannn adresi atanyor:
pmax = (int *)p
atamasyla dardan alnan dizinin balang adresinin pmax isimli gstericiye atandn
gryorsunuz. Daha sonra oluturulan for dngsyle srasyla dizinin dier
elemanlarnn, pmax gstericisinin gsterdii nesneden daha byk olup olmadklar
snanyor. pmax'n gsterdii nesneden daha byk bir dizi eleman bulunduunda, bu
elemann adresi pmax gstericisine atanyor.
pmax = (int *)(p + i)
atamasnda p + i ifadesinin &p[i] ifadesine edeer olduunu biliyorsunuz.
Dng knda pmax gsteri deikeni dizinin en byk elemannn adresini tutar, deil
mi?
main ilevinde SIZE uzunluunda bir dizi nce rastgele deerle dolduruluyor. Daha sonra
dizi elemanlarnn deerleri ekrana yazdrlyor.
Aadaki ilev arsyla ekrana getmax ilevinin geri dndrd adresteki nesnenin
deeri yazdrlyor.
printf("max = %d\n", *getmax(a, SIZE));
Bu da dizinin en byk elemannn deeridir, deil mi?
254

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Bir ilevin bir adres bilgisine geri dnmesinin baka faydalar da olabilir. Hesaplanmak
istenen bir deeri darya iletmek yerine, hesaplanan bu deeri iinde tutacak bir
nesnenin adresi darya iletilebilir. Nasl olsa bir nesnenin adresi elimizdeyken o nesnenin
deerine de ulaabiliriz, deil mi?
Type szc bir tr belirtiyor olsun. Type trnden bir deer dndren bir ilevin
bildirimi aadaki gibidir:
Type foo(void);
Byle bir ilevin geri dn deerini saklamak iin bu kez Type trnden bir nesneye ilev
ar ifadesini atamak gerekir.
Type val = foo();
Type trden bir nesne bellekte 100 byte yer kaplyor olsun. Bu durumda, arlan foo
ilevinin almas srasnda return deyimine gelindiinde 100 byte'lk bir geici nesne
oluturulur. return ifadesinden bu geici nesneye yaplan atama 100 byte'lk bir bloun
kopyalanmasna neden olur. Geici nesnenin val isimli deikene aktarlmas da, yine 100
byte'lk bir bellek blounun kopyalanmasna neden olur.
imdi de aadaki bildirime bakalm:
Type *foo(void);
Bu kez ilev hesaplad nesnenin deerini iinde tayan Type trnden bir nesnenin
adresini dndryor. Bu durumda, ilevin geri dn deerini iinde tayacak geici
nesne yalnzca, 2 byte ya da 4 byte olur, deil mi? Yani 100 byte'lk bir blok kopyalamas
yerine yalnzca 2 ya da 4 byte'lk bir kopyalama sz konusudur.
Byle bir ilevin geri dn deerini saklamak iin, ilev ar ifadesinin bu kez Type *
trnden bir nesneye atanmas gerekir.
Type *ptr;
ptr = foo();
foo ilevinin hesaplad deeri iinde tutan Type trnden nesnenin adresi, Type
trnden bir gsterici deikene atanyor. Type trnn sizeof deeri ne olursa olsun bu
ilem, yalnzca bir gstericinin sizeof deeri kadar byklkte bir bloun kopyalanmasna
neden olur, deil mi?
Bir ilevin, bir deerin kendisini darya iletmesi yerine o deeri iinde tutan nesnenin
adresini darya iletmesi, bellek ve zaman kullanm asndan maliyeti drr.
Bir de baka bir faydadan sz edelim. Bir ilevden bir nesnenin deerini alnrsa, bu
deeri tayan nesne deitirilemez. Ancak bir ilevden bir nesnenin adresi alnrsa, adresi
alnan nesne deitirilebilir.
Yukarda yazlan getmax ilevi bize dizinin en byk elemannn adresini dndryordu,
deil mi? Aadaki main ilevini inceleyin:

255

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

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

SIZE

100

void set_random_array(int *ptr, int size, int max_val);


void display_array(const int *ptr, int size);
int *getmax(const int *ptr, int size);
int main()
{
int a[SIZE];
srand(time(0));
set_random_array(a, SIZE, 1000);
display_array(a, SIZE);
*getmax(a, SIZE) = -1;
display_array(a, SIZE);
*getmax(a, SIZE) = -1;
display_array(a, SIZE);
}

return 0;

Aadaki deyime bakalm:


*getmax(a, SIZE) = -1;
levin geri dndrd adresin, ierik ilecine terim yapldn gryorsunuz. Bu
ifadeyle ilevin geri dndrd adresteki nesneye ulalarak bu nesneye 1 deeri
atanyor. Yani dizinin en byk elemannn deeri -1 yaplyor. Dizinin en byk elemann
deerini geri dndren bir ilevle bu iin yaplmas mmkn olamazd.
imdi aadaki program dikkatle inceleyin ve yazlan selec_sort isimli ilevde ne
yapldn anlamaya aln:

256

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

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

SIZE

100

void swap(int *p1, int *p2);


void display_array (const int *p, int size);
void set_random_array(int *ptr, int size, int max_val);
int *getmax(const int *ptr, int size);
void select_sort(int *ptr, int size)
{
int k;
for (k = 0; k < size - 1; ++k)
swap (getmax(ptr + k, size - k), ptr + k);
}
int main()
{
int a[SIZE];
srand(time(0));
set_random_array(a, SIZE, 1000);
printf("siralanmadan once\n");
display_array(a, SIZE);
select_sort(a, SIZE);
printf("siralanmadan sonra\n");
display_array(a, SIZE);
}

return 0;

Yerel Nesnelerin Adresleriyle Geri Dnmek

Adrese geri dnen bir ilev asla otomatik mrl yerel bir nesnenin adresiyle geri
dnmemelidir. Otomatik mrl yerel nesnelerin adresleriyle geri dnmek tipik bir
programlama hatasdr.
Klavyeden girilen bir ismin balang adresine geri dnen bir ilev yazlmak istensin:
char *getname()
{
char name_entry[40];

printf("bir isim girin: ");


gets(name_entry);
return name_entry;
/* Yanl!

*/

#include <stdio.h>
int main()
{
char *ptr = get_name();
printf("alnan isim = %s\n", ptr);
}

return 0;

257

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

get_name ilevi iinde yerel bir dizi tanmlanyor. Kullancnn girdii isim yerel diziye
yerletiriliyor, daha sonra yerel dizinin adresiyle geri dnlyor.
Yerel deikenlerin otomatik mrl olduunu, yani ait olduklar bloun yrtlmesi
sonunda bellekten boaltldklarn biliyorsunuz. get_name ilevinin geri dn deeri,
yani yerel name_entry dizisinin balang adresi main ilevi iinde ptr gstericisine
atanyor. Oysa artk yerel dizi bellekten boaltld iin, ptr gsterici deikenine atanan
adresin hibir gvenilirlii yoktur. ptr gstericisinin gsterdii yerden okuma yapmak ya
da buraya yazmak gsterici hatasdr.
Adrese geri dnen bir ilev yerel bir deikenin adresiyle ya da yerel bir dizinin balang
adresiyle geri dnmemelidir. Yukarda yazlan getname ilevinin arlmas alma
zaman hatasna neden olur. C derleyicilerinin ou, bu durumu mantksal bir uyar iletisi
ile belirler.

NULL Adres Deimezi (Null Gsterici)

Bir gsterici deiken, iinde adres bilgisi tutan bir nesnedir, deil mi?
int x = 10;
int *ptr = &x;
Yukardaki deyimleri aadaki cmlelerle ifade edebiliriz:
ptr gstericisi x nesnesinin adresini tutuyor.
ptr gstericisi x nesnesini gsteriyor.
*ptr nesnesi , ptr'nin gsterdii nesnedir.
*ptr , x nesnesinin kendisidir.
yle bir gsterici olsun ki hibir nesneyi gstermesin. Hibir yeri gstermeyen bir
gstericinin deeri yle bir adres olmaldr ki, bu adresin baka hibir amala
kullanlmad gvence altna alnm olsun. te hibir yeri gstermeyen bir adres olarak
kullanlmas amacyla baz balk dosyalarnda standart bir simgesel deimez
tanmlanmtr. Bu simgesel deimez NULL simgesel deimezi olarak bilinir.
NULL bir simgesel deimezdir. Bu simgesel deimez standart balk dosyalarndan
stdio.h, string.h ve stddef.h iinde tanmlanmtr.
NULL adresi herhangi trden bir gstericiye atanabilir. Byle bir atama tamamen
szdizimsel kurallara uygundur, uyar gerektiren bir durum da sz konusu deildir.
int *iptr = NULL;
char *cptr = NULL;
double *dptr = NULL;
NULL adresi hibir yeri gstermeyen bir gstericinin deeridir. Bir gsterici ya bir nesneyi
gsterir (yani bu durumda gstericinin deeri gsterdii nesnenin adresidir) ya da hibir
nesneyi gstermez (bu durumda gstericinin deeri NULL adresidir).
Bir adres bilgisinin doru ya da yanl olarak yorumlanmas sz konusu olduu zaman,
adres bilgisi NULL adresi ise "yanl" olarak yorumlanr. NULL adresi dndaki tm adres
bilgileri "doru" olarak yorumlanr. ptr isimli bir gstericinin deeri NULL adresi deil ise,
yani ptr gstericisi bir nesneyi gsteriyorsa bir ilev arlmak istensin. Byle bir if
deyiminin koul ifadesi iki ayr biimde yazlabilir:
if (ptr != NULL)
foo();
if (ptr)
foo();

258

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Bu kez ptr isimli gsterici deikenin deeri NULL adresi ise, yani ptr gstericisi bir
nesneyi gstermiyorsa, foo ilevi arlmak istensin. if deyiminin koul ifadesi yine iki ayr
biimde yazlabilir:
if (ptr == NULL)
foo();
if (!ptr)
foo();
Bir gsterici deikene herhangi bir trden 0 deeri atandnda, atama ncesi 0 deeri
otomatik olarak NULL adresine dntrlr:
int *ptr = 0;
Yukardaki deyimle ptr gsterici deikenine NULL adresi atanyor.
Peki NULL adresi ne iin kullanlr?
Adrese geri dnen bir ilevin eer baarszl sz konusu ise, ilev baarszlk durumunu
NULL adresine geri dnerek bildirebilir.
int trden bir dizi iinde bulunan ilk asal saynn adresi ile geri dnen bir ilev yazmak
isteyelim:
int *get_first_prime(const int *ptr, int size);
levin birinci parametresi dizinin balang adresi, ikinci parametresi ise dizinin boyutu
olsun. levi aadaki biimde yazdmz dnn:
int is_prime(int val);
int *get_first_prime(const int *ptr, int size)
{
int k;
for (k = 0; k < size; ++k)
if (isprime (ptr[k]))
return ptr + k;
/* ??????? */
}
Yukardaki ilevde, dardan balang adresi alnan dizimizin her elemann asal olup
olmad snanyor, ilk asal say grldnde bu elemann adresiyle geri dnlyor. Peki
ya dizinin iinde hi asal say yoksa, for dng deyiminden kldnda ilev bir p deeri
geri dndrr, deil mi? Peki bu durumda ilev hangi geri dn deerini retebilir?
Madem ki NULL adresi hibir yeri gstermeyen bir adres, o zaman adrese geri dnen bir
ilev baarszlk durumunu NULL adresine geri dnerek bildirebilir, deil mi?

259

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
int is_prime(int val);
int *get_first_prime(const int *ptr, int size)
{
int k;

for (k = 0; k < size; ++k)


if (isprime (ptr[k]))
return ptr + k;
return NULL;

C dilinde, adrese geri dnen bir ilevin baarszlk durumunda NULL adresine geri
dnmesi, ok sk kullanlan bir konvensiyondur.
Parametre deikeni gsterici olan bir ilev, kendisine geilen NULL adresini bir bayrak
deeri olarak kullanabilir. Aadaki gibi bir ilev tasarladmz dnelim:
void func(char *ptr)
{
if (ptr == NULL) {
/***/
}
else {
/***/
}
}
lev kendisine geilen adresin NULL adresi olup olmamasna gre farkl iler yapyor.
Tabi bu durumun ilevi aran kod paras tarafndan bilinmesi gerekir. Standart C
ilevlerinden time ilevi byledir. time ilevinin gsterici parametresine NULL adresi
geildiinde ilev herhangi bir nesneye deer atamaz. Hesaplad deeri yalnzca geri
dn deeri olarak darya iletir. Ancak ileve NULL adresi dnda bir adres
gnderildiinde ilev verilen adresteki nesneye hesaplad deeri yazar.
Birok programc bir gsterici deikene gvenilir bir adres atamadan nce, gstericiye
NULL adresi deerini verir. Bylece kod iinde ilgili gstericinin henz bir nesneyi
gstermedii bilgisi gl bir biimde verilerek, kodun okunabilirlii artrlr.
Bir gstericinin mr henz sona ermeden, gsterdii nesnenin mr sona erebilir. Bu
durumda gstericinin deeri olan adres gvenilir bir adres deildir. Kod iinde bu durumu
vurgulamak iin gstericiye NULL adresi atanabilir.

Gstericilere likin Uyarlar ve Olas Gsterici Hatalar


Bir Gstericiye Farkl Trden Bir Adres Atanmas:

Bir gstericiye farkl trden bir adres atandnda, C derleyicilerin ou durumu pheyle
karlayarak mantksal bir uyar iletisi verir. Ancak derleyici yine de farkl trden adresin
saysal bileenini hedef gstericiye atar. Borland derleyicileri bu durumda aadaki uyar
iletisini verir:
warning : suspicious pointer conversion in function ......
Aadaki kodu inceleyin:

260

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
int main()
{
double d = 1874567812.987;
int *ptr;
ptr = &d;
*ptr = 0;
printf("d = %lf\n", d);
}

return 0;

Yukardaki kodda double trden d deikeninin adresi int trden bir nesneyi gsterecek
ptr deikenine atanyor. Byle bir atamadan sonra ptr double trden d deikenini deil,
int trden bir nesneyi gsterir.
*ptr = 0;
atamasyla d deikeninin ilk 4 byte'na tamsay formatnda 0 deeri atanm olur. Byle
bir atamadan sonra d deikeninin deeri istenilmeyen bir biimde deitirilmi olur, deil
mi?
Eer gstericiye farkl trden adres bilinli bir biimde atanyorsa tr dntrme ileci
kullanlmaldr:
#include <stdio.h>
int main()
{
double d;
unsigned int k;
unsigned char *ptr;
printf("bir gercek sayi girin :");
scanf("%lf", &d);
ptr = (unsigned char *)&d;
for (k = 0; k < sizeof(double); ++k)
printf("%u\n", ptr[k]);
return 0;
}
Yukardaki main ilevinde double trden d deikeninin adresi unsigned char trnden bir
gstericiye atanyor. ptr gsterici deikeni byte byte ilerletilerek d deikeninin her bir
byte'nn deeri tamsay olarak yorumlanarak ekrana yazdrlyor.
ptr = (unsigned char *)&d;
deyiminde atamann bilinli olarak yapldn gstermek iin d deikeninin adresi nce
unsigned char trden bir adres bilgisine dntrlyor, daha sonra atama yaplyor.

Bir Gsterici Deikene Adres Olmayan Bir Deerin Atanmas

Bu da bilinli olarak yaplma olasl ok az olan bir ilemdir. C derleyicileri pheli olan
bu durumu mantksal bir uyar iletisi ile programcya bildirirler. rnein bu uyar iletisi
Borland derleyicilerinde aadaki gibidir:

261

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

"non-portable pointer conversion"


Peki bir gstericiye adres bilgisi olmayan bir deer atanrsa ne olur? C'de bu dorudan bir
szdizim hatas deildir. Yine otomatik tr dnm sz konusudur. Atama ilecinin sa
tarafndaki ifadenin tr, atama ilecinin sol tarafnda bulunan nesne gsteren ifadenin
trne evrilerek atama yaplr. Dolaysyla, atanan deer gsterici deikenin trnden
bir adrese evrilerek gstericiye atanr. rnein:
void func()
{
int x = 1356;
int *ptr;
ptr = x;
/***/
}
Yukardaki rnekte
ptr = x;
atama deyimi ile ptr deikenine x nesnesinin adresi deil, deeri atanyor. x
deikeninin deeri olan 1356, atama ncesi tr dnmyle bir adres bilgisine
dntrlerek ptr deikenine atanr. Artk ptr, x deikenini gstermez, 1356
adresindeki nesneyi gsterir:
*ptr nesnesine erimek artk bir gsterici hatasdr.

Nesnelerin Bellekteki Yerleimleri

Bir byte'tan daha byk olan deikenlerin bellee yerleim biimi kullanlan
mikroilemciye gre deiebilir. Bu nedenle deikenlerin bellekteki grnmleri
tanabilir bir bilgi deildir. Mikroilemciler iki tr yerleim biimi kullanabilir:
i)Dk anlaml byte deerleri bellein dk sayl adresinde bulunacak biimde. Byle
yerleim biimine little endian denir. Intel ilemcileri bu yerleim biimini kullanr. Bu
ilemcilerin kullanld sistemlerde rnein
int x = 0x1234;
biimindeki bir x deikeni bellekte 1A00 adresinden balayarak yerletirilmi olsun:

ekilden de grld gibi x deikeninin dk anlaml byte deeri (34H) dk saysal


adreste (1A00H) olacak biimde yerletirilmitir.
ii) kinci bir yerleim biimi, dk anlaml byte'n yksek saysal adrese
yerletirilmesidir.
Byle yerleim biimine big endian denir. Motorola ilemcileri bu yerleim biimini
kullanr. Bu ilemcilerin kullanld sistemlerde rnein
int x = 0x1234;
biimindeki bir x deikeni bellekte 1A00 adresinden balayarak yerletirilmi olsun:

262

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

1A00
1A01

---0001 0010
0011 0100
----

yksek anlaml byte


yksek anlaml byte

ekilden de grld gibi x deikeninin dk anlaml byte deeri (34H) yksek saysal
adreste (1A00H) olacak biimde yerletirilmitir.
Aadaki kod kullanlan sistemin little endian ya da big endian oldugunu snyor:
#include <stdio.h>
int main()
{
int x = 1;
if (*(char *)&x)
printf("little endian\n");
else
printf("big endian\n");
return 0;
}
Yazlan kodda nce adres ileciyle x deikeninin adresi elde ediliyor. Adres ilecinin
rettii deer int * trndendir. Daha sonra tr dntrme ileciyle, elde edilen adres
bilgisi char * trne dntrlyor. char * trnden adresin de ierik ilecinin terimi
olduunu gryorsunuz. Bu durumda ierik ileci x nesnesinin en dk saysal
adresindeki char trden nesneye eriir, deil mi? Eer bu nesnenin deeri 1 ise sistem
"little-endian" dr.

Yazlarn levlere Gnderilmesi

Yazlar karakter dizilerinin iinde bulunurlar. Bir ilevin bir yaz zerinde ilem
yapabilmesi iin bir yaznn balang adresini almas yeterlidir. Yani ilev yaznn
(karakter dizisinin) balang adresi ile arlr. Yazy iinde tutan char trden dizinin
boyutu bilgisini ileve geirmeye gerek yoktur. nk yazlarn sonunda sonlandrc
karakter vardr. Karakter dizileri zerinde ilem yapan kodlar dizinin sonunu sonlandrc
karakter yardmyla belirler.
Yazlarla ilgili ilem yapan bir ilev char trden bir gsterici deiken ile zerinde ilem
yapaca yaznn balang adresini alr. lev, yaznn sonundaki sonlandrc karakteri
grene kadar bir dng ile yaznn tm karakterlerine eriebilir.
str, char trnden bir gsterici olmak zere yaz zerinde sonlandrc karakteri grene
kadar ilem yapabilecek dngler yle oluturulabilir:
while (*str != '\0') {
/***/
++str;
}
for (i = 0; str[i] != '\0'; ++i) {
/***/
}

puts ve gets levleri

stdio.h iinde bildirilen standart puts ilevinin parametre deikeni char trnden bir
gstericidir:

263

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

int puts(const char *str);


lev, str adresindeki yazy standart k birimine yazar. lev yazma ilemini
tamamladktan sonra ekrana bir de '\n' karakteri yazar. Eer yazma ilevi baarl olursa
ilevin geri dn deeri negatif olmayan bir deerdir. Baarszlk durumunda ilev,
negatif bir deere geri dner. Aada benzer ii gren myputs isimli bir ilev
tanmlanyor:
#include <stdio.h>
void myputs(const char *str)
{
while (*str != '\0')
putchar(*str++);
putchar('\n');
}
int main()
{
char s[] = "NecatiErgin";
int k;
for (k = 0; k < 11; ++k)
myputs(s + k);
return 0;
}
stdio.h iinde bildirilen standart gets ilevi de aslnda gsterici parametreli bir ilevdir:
char *gets(char *ptr);
lev standart giri biriminden ald yazy parametresine aktarlan adrese yerletirir.
Eer giri ilemi baarl olursa ilev ptr adresine geri dner. Baarszlk durumunda
ilevin geri dn deeri NULL adresidir. Aada benzer ii gren mygets isimli bir ilev
tanmlanyor:
#include <stdio.h>
char *mygets(char *ptr)
{
int ch;
int index = 0;
while ((ch = getchar()) != '\n')
ptr[index++] = ch;
ptr[index] = '\0';
}

return ptr;

264

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yazlarla lgili lem Yapan Standart levler


C'nin standart baz ilevleri bir yaznn balang adresini parametre olarak alarak yaz ile
ilgili birtakm faydal ilemler yapar. Bu ilevlere dizge ilevleri denir. Dizge ilevlerinin
bildirimleri string.h dosyas iindedir.

strlen levi

En sk arlan standart C ilevlerinden biridir. levin ismi olan strlen, "string length"
szcklerinden gelir. Bu ilev bir yaznn karakter uzunluunu yani yaznn ka
karakterden olutuu bilgisini elde etmek iin kullanlr.
levin bildirimi:
size_t strlen(const char *str);
biimindedir. levin parametre deikeni, uzunluu hesaplanacak yaznn balang
adresidir. lev sonlandrc karakter grene kadar karakterlerin saysn hesaplar. Geri
dn deeri tr yerine yazlan size_t nin imdilik unsigned int trnn bir baka ismi
olduunu dnebilirsiniz.
#include <stdio.h>
#include <string.h>
int main()
{
char s[100];
printf("bir yaz giriniz : ");
gets(s);
printf("(%s) yazsnn uzunluu = %u\n", s, strlen(s));
}

return 0;

Standart C ilevi olan strlen aadaki biimlerde tanmlanabilir:


unsigned int mystrlen1(const char *str)
{
unsigned int length = 0;

while (*str != '\0') {


++length;
++str;
}
return length;

unsigned int mystrlen2(const char *str)


{
unsigned int len;
for (len = 0; str[len] != '\0'; ++len)
;
return len;
}

265

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

unsigned int mystrlen3(const char *str)


{
const char *ptr = str;

while (*str != '\0')


str++;
return str - ptr;

strchr levi

levin ismi olan strchr ,"string character" szcklerinden gelir. strchr ilevi bir karakter
dizisi iinde belirli bir karakteri aramak iin kullanlan standart bir C ilevidir.
levin string.h dosyas iindeki bildirimi aadaki gibidir:
char *strchr(const char *str, int ch);
Bu ilev ikinci parametresi olan ch karakterini, birinci parametresi olan str adresinden
balayarak sonlandrc karakter grene kadar arar. Aranan karakter sonlandrc
karakterin kendisi de olabilir. levin geri dn deeri, ch karakterinin yaz iinde
bulunabilmesi durumunda bulunduu yerin adresidir. Eer ch karakteri yaz iinde
bulunamazsa, ilev NULL adresine geri dner.
strchr ilevi aadaki gibi tanmlanabilir:
#include <stdio.h>
#include <string.h>
int main()
{
char s[100];
char *p, ch;
printf("bir yaz girin : ");
gets(s);
printf("yaz iinde arayacanz karakteri girin : ");
scanf("%c", &ch);
p = strchr(s, ch);
if (p == NULL)
printf("aranan karakter bulunamad\n");
else
printf("bulundu: (%s)\n", p);
}

return 0;

char *strchr(const char *str, int ch)


{
char c = ch;
while (*str != '\0') {
if (*str == c)
return (char *)str;
++str;
}
if (ch == '\0')
return (char *)str;
return NULL;
}

266

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

strrchr levi

Standart olan bu ilev strchr ilevi gibi bir yaznn iinde bir karakteri arar. Arama yaznn
sonundan balanarak yaplr. Yani "ankara" yazs iinde 'n' karakteri arandnda ilev
yaznn son karakterinin adresini dndrr. levin string.h balk dosyas iindeki
bildirimi aadaki gibidir:
char *strrchr(const char *str, int ch);
lev, str adresindeki yaz iinde bulunabilecek son ch karakterinin adresini dndrr.
Eer yaznn iinde ch karakteri yoksa ilevin geri dn deeri NULL adresidir. lev ile
yaznn sonundaki sonlandrc karakter de aranabilir.
#include <stdio.h>
char *mstrrchr(const char *str, int ch)
{
const char *p = str;
const char *pf = NULL;
while (*p) {
if (*p == ch)
pf = p;
p++;
}
if (ch == '\0')
return (char *)p;
return (char *)pf;
}
int main()
{
char s[100];
char *ptr;
int ch;
printf("bir yazi girin : ");
gets(s);
printf("aranacak karakteri girin: ");
ch = getchar();
ptr = mstrrchr(s, ch);
if (ptr == NULL)
printf("(%s) yazsnda (%c) bulunamad!\n", s, ch);
else
printf("bulundu: (%s)\n", ptr);
return 0;
}

strstr levi

levin ismi string string szcklerinden gelir. Bu ilevle bir yaz iinde baka bir yaz
aranr. levin bildirimi aadaki gibidir:

char *strstr(const char *p1, const char *p2);


Eer p1 adresindeki yaz iinde p2 adresindeki yaz varsa, ilev yaznn bulunduu yerin
adresini dndrr. Eer yoksa ilevin geri dn deeri NULL adresidir. Aadaki
program derleyerek altrn:

267

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
#include <string.h>
#define SIZE

100

int main()
{
char s1[SIZE];
char s2[SIZE];
char *ptr;
printf("iinde arama yaplacak yazy girin: ");
gets(s1);
printf("aranacak yazy girin: ");
gets(s2);
ptr = strstr(s1, s2);
if (!ptr)
printf("(%s) yazisi icinde (%s) yazisi yok!\n", s1, s2);
else
printf("bulundu! (%s)\n", ptr);
}

return 0;

strcspn levi

Bu ilev ile bir yaznn iinde baka bir yazda olan ilk karakterin indisi bulunur. levin
string.h iindeki bildirimi yledir:
size_t strcspn(const char *p1, const char *p2);
Geri dn deeri u ekilde de tanmlanabilir : lev p1 yazs iinde yaznn bandan
balayarak, p2 yazsnn karakterlerinden herhangi birini iermeyen yaznn uzunluu
deerine geri dner:
#include <stdio.h>
#include <string.h>
#define SIZE

100

int main()
{
char s1[SIZE];
char s2[SIZE];
size_t index;
printf("icinde arama yapilacak yaziyi girin: ");
gets(s1);
printf("karakterler: ");
gets(s2);
index = strcspn(s1, s2);
printf("(%s)\n", s1 + index);
s1[index] = '\0';
printf("(%s)\n", s1);
return 0;
}

268

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

strpbrk levi

Standart strpbrk ilevi ile bir yazda baka bir yaznn karakterlerinden herhangi biri
aranr:
char *mstrpbrk(const char *s1, const char *s2)
Eer s1 adresindeki yaznn iinde s2 adresindeki yaznn karakterlerinden herhangi biri
varsa ilev bu karakterin adresini dndrr. Eer s1 yazs iinde s2 yazsnn
karakterlerinin hibiri yoksa ilev NULL adresine geri dner.
Aada strpbrk ilevinin rnek bir tanm ile bir snama kodu yer alyor:
#include <string.h>
#include <stdio.h>
#define

SIZE

100

char *mstrpbrk(const char *s1, const char *s2)


{
const char *p1, *p2;
for (p1 = s1; *p1 != '\0'; ++p1)
for (p2 = s2; *p2 != '\0'; ++p2)
if (*p1 == *p2)
return (char *)p1;
return NULL;
}
int main()
{
char str1[SIZE];
char str2[SIZE];
char *ptr;
printf("birinci yazy girin : ");
gets(str1);
printf("ikinci yazy girin : ");
gets(str2);
ptr = strpbrk(str1, str2);
if (ptr == NULL)
printf("\"%s yazisinda\" (%s) karakterlerinden hic biri yok!\n",
str1, str2);
else
printf("bulundu : (%s)\n", ptr);
return 0;
}

strcpy levi

Standart bir C ilevidir. levin ismi olan strcpy, "string" ve "copy" szcklerinden gelir.
lev ikinci parametresinde tutulan adresten balayarak, sonlandrc karakter grene
kadar, sonlandrc karakter de dahil olmak zere, tm karakterleri birinci parametresinde
tutulan adresten balayarak srayla yazar. levin string.h balk dosyas iindeki bildirimi
aadaki gibidir:
char *strcpy(char *dest, const char *source);
levin geri dn deeri kopyalamann yaplmaya baland adres yani dest adresidir.
strcpy ilevi aadaki gibi tanmlanabilir:

269

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
#include <string.h>
int main()
{
char dest[100] = "C reniyoruz!";
char source[100];
printf("kopyalanacak yazy girin : ");
gets(source);
printf("kopyalama yaplmadan nce yaz :(%s)\n", dest);
strcpy(dest, source);
printf("kopyalama yapildiktan sonra yaz :(%s)\n", dest);
}

return

0;

char *mystrcpy(char *dest, const char *source)


{
int i;

for (i = 0; (dest[i] = source[i]) != '\0'; ++i)


;
return dest;

lev iinde kullanlan for dngsnn ikinci ksmnda nce atama yaplyor, daha sonra
atama ifadesinin deeri yani atama ilecinin sa tarafnda bulunan deer sonlandrc
karakter ile karlatrlyor. Bylece ilgili adrese sonlandrc karakter de kopyalandktan
sonra dngden klyor.
lev aadaki gibi de yazlabilirdi:
/***/
for (i = 0; source[i] != '\0'; ++i)
dest[i] = source[i];
dest[i] = '\0';
/***/
for dng deyiminde keli ayra ileci kullanld iin, birinci parametre deikenine
kopyalanan dest gsterici deikeninin deeri deitirilmiyor. levin sonunda dest adresi
ile geri dnlyor. levin yazmnda while dngs kullanlarak, dest deikeni iindeki
adres srekli artrlabilirdi. Bu durumda ilevin dest gstericisinin ilkdeeriyle geri
dnebilmesini salayabilmek iin, dest gstericisindeki deeri deitirmeden nce, bu
deeri baka bir gsterici deiken iinde saklamak gerekirdi:
char *mystrcpy(char *dest, const char *source)
{
char *temp = dest;

while ((*source++ = *dest++) != '\0')


;
return temp;

strcat levi

Standart bir C ilevidir. levin ismi string ve concatanate szcklerinden gelir


strcat ilevi bir yaznn sonuna baka bir yaznn kopyalanmas amacyla kullanlr. levin
string.h dosyas iindeki bildirimi aadaki gibidir:

270

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

char *strcat(char *s1, const char *s2);


strcat ilevi eklemenin yaplaca ve balang adresi s1 birinci parametre deikeninde
tutulan yaznn sonundaki sonlandrc karakteri ezerek, balang adresi ikinci parametre
deikeninde tutulan yazy birinci yaznn sonuna (sonlandrc karakter de dahil olmak
zere) ekler. Yani ilem sonunda s1 adresindeki yaznn uzunluu s2 adresindeki yaznn
uzunluu kadar artar.
levin geri dn deeri, sonuna eklemenin yapld yaznn balang adresi, yani s1
adresidir.
#include <stdio.h>
#include <string.h>
int main()
{
char s1[100], s2[100];
printf("sonuna ekleme yaplacak yazy girin : ");
gets(s1);
printf("girdiiniz yaznn uzunluu = %d\n", strlen(s1));
printf("eklemek istediiniz yazy girin : ");
gets(s2);
printf("eklenecek yaznn uzunluu = %d\n", strlen(s2));
strcat(s1, s2);
printf("ekleme yapldktan sonra 1. yaz : ");
puts(s1);
printf("ekleme yapldktan sonra yaznn uzunluu : %d\n", strlen(s1))
}

return 0;

strcat ilevi aadaki gibi tanmlanabilir:


char *mystrcat(char *s1, const char *s2)
{
char *temp = s1;
while (*s1 != '\0')
++s1;
while ((*s1++ == *s2++) != '\0')
;
}

/* strcpy(s1, s2); */

return temp;

Bir yaznn sonuna baka bir yazy eklemek, sona eklenecek yazy dier yaznn
sonundaki sonlandrc karakterin bulunduu yere kopyalamak anlamna gelir, deil mi?
Dolaysyla strcat ilevi aadaki biimlerde de tanmlanabilir.
char *mystrcat(char *s1, const char *s2)
{
strcpy(s1 + strlen(s1), S2);
return s1;
}
char *mystrcat(char *s1, const char *s2)
{
strcpy(strchr(s1, '\0'), s2);
return s1;
}

271

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

strcmp ilevi

Standart bir C ilevidir. levin ismi string compare szcklerinden gelir. lev iki karakter
dizisini karlatrmakta kullanlr. Karlatrma, iki karakter dizisi iindeki yaznn,
kullanlan karakter seti tablosu gznnde bulundurularak, ncelik ya da eitlik
durumunun sorgulanmasdr. rnein:
Adana yazs Ankara yazsndan daha kktr. nk eitlii bozan 'n' karakteri ASCII
karakter tablosunda 'd' karakterinden sonra gelir.
ankara yazs ANKARA yazsndan daha byktr. nk kk harfler ASCII tablosunda
byk harflerden sonra gelir.
Kk "masa" byk "MASA" dan daha byktr.
kalem yazs kale yazsndan daha byktr.
strcmp ilevinin string.h balk dosyas iindeki bildirimi aadaki gibidir:
int strcmp(const char *s1, const char *s2);
lev birinci parametre deikeninde balang adresi tutulan yaz ile, ikinci parametre
deikeninde balang adresi tutulan yazlar karlatrr.
levin geri dn deeri,
birinci yaz ikinci yazdan daha bykse pozitif bir deerdir,
birinci yaz ikinci yazdan daha kkse negatif bir deerdir,
birinci yaz ile ikinci yaz birbirine eit ise 0 deeridir.
#include <stdio.h>
#include <string.h>
int main()
{
char s[20];
char password[ ] = "Mavi ay";
printf("parolay girin : ");
gets(s);

if (!strcmp(s, password))
printf("Parola doru!..\n");
else
printf("Parola yanl!..\n");
return 0;

strcmp ilevi aadaki gibi tanmlanabilir:


int mystrcmp(const char *s1, const char *s2)
{
while (*s1 == *s2) {
if (*s1 == '\0')
return 0;
++s1;
++s2;
}
return *(unsigned char *)s1 > *(unsigned char *)s2 ? 1 : -1;
}

272

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

strncpy ilevi

Standart bir C ilevidir. levin ismi string number copy szcklerinden gelir. lev bir
yaznn (karakter dizisinin) ilk n karakterini baka bir yere kopyalamakta kullanlr. levin
string.h iindeki bildirimi aadaki gibidir :
char *strncpy(char *dest, const char *source, size_t n);
lev birinci parametre deikeninde balang adresi tutulan yazya, ikinci parametre
deikeninde adresi tutulan yazdan, nc parametresinde tutulan sayda karakteri
kopyalar.
levin geri dn deeri kopyalamann yaplaca adres yani dest adresidir.
nc parametre olan n says eer kopyalanacak yaznn uzunluundan daha kk ya
da eit ise ilev kopyalama sonunda sonlandrc karakteri birinci dizinin sonuna eklemez.
Yani n <= strlen(source) ise sonlandrc karakter eklenmez.
nc parametre olan n says eer kopyalanacak yaznn uzunluundan daha byk ise
ilev kopyalama sonunda sonlandrc karakteri birinci dizinin sonuna ekler.
Yani n > strlen(source) ise sonlandrc karakter de kopyalanr.
Aada strncpy ilevi tanmlanyor:
#include <string.h>
#include <stdio.h>
#define

SIZE

100

char *mstrncpy(char *s1, const char *s2,


{
char *s = s1;
while (n > 0 && *s2)
*s++ = *s2++;
n--;
}

unsigned int

n)

while (n--)
*s++ = '\0';
}

return s1;

int main()
{
char str1[SIZE];
char str2[SIZE];
int n;
printf("birinci yaziyi girin : ");
gets(str1);
printf("ikinci yaziyi girin : ");
gets(str2);
printf("ikinci yazidan kac karakter kopyalanacak? ");
scanf("%d", &n);
strncpy(str1, str2, n);
printf("(%s)\n", str1);
return 0;
}

273

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

nc parametreye aktarlan deer kopyalanan yaznn uzunluundan kk ya da


eitse kopyalanan yere sizce neden sonlandrc karakter eklenmez?
Bu ilevin yazlar iinde yer deitirme ilemi yapabilmesi istenmitir:
#include <string.h>
#include <stdio.h>
#define

SIZE

100

int main()
{
char str1[SIZE] = "Necati Ergin";
char str2[SIZE] = "Mehmet Aktunc";
strncpy(str1, str2, 6);
printf("(%s)\n", str1);
return 0;
}

strncat levi

Standart bir C ilevidir. levin ismi ingilizce "string number concatanate" szcklerinden
gelir. Bir yaznn sonuna baka bir yazdan belirli bir sayda karakteri kopyalamak
amacyla kullanlr. string.h balk dosyas iinde bulunan bildirimi aadaki gibidir:
char *strncat(char *s1, const char *s2, size_t n);
lev birinci parametre deikeni iinde balang adresi verilen yaznn sonuna, ikinci
parametresinde balang adresi tutulan karakter dizisinden, nc parametresinde
tutulan tamsay adedi kadar karakteri kopyalar.
levin geri dn deeri sonuna ekleme yaplacak yaznn balang adresidir.
levin tanm ve ilevi snayan bir main ilevi rnek olarak aada veriliyor:
char *mstrncat(char *s1, const char *s2, unsigned int n)
{
char *ptr;
for (ptr = s1; *ptr != '\0'; ++ptr)
;
while (n-- && *s2 != '\0')
*ptr++ = *s2++;
*ptr = '\0';
}

return s1;

#include <string.h>
#include <stdio.h>
#define

SIZE

100

int main()
{
char dest[SIZE];
char source[SIZE];

274

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

int n;
printf("birinci yaziyi girin : ");
gets(dest);
printf("ikinci yaziyi girin : ");
gets(source);
printf("1. yazinin sonuna kac karakter kopyalanacak : ");
scanf("%d", &n);
mstrncat(dest, source, n);
printf("eklemeden sonra 1. yazi = (%s)\n", dest);
}

return 0;

strncmp levi

Standart bir C ilevidir. levin ismi string number compare szcklerinden gelir.. strcmp
ilevine benzer, ancak bu ilev iki yaznn tmn deil de, belirli bir sayda karakterlerini
karlatrma amacyla kullanlr.
lev birinci parametre deikeninde balang adresi tutulan yaz ile, ikinci parametre
deikeninde balang adresi tutulan yazlarn, nc parametresinde tutulan saydaki
karakterlerini karlatrr.
lev, birinci yaznn ilk n karakteri ikinci yaznn ilk n karakterinden daha bykse pozitif
bir deere
Birinci yaznn ilk n karakteri ikinci yaznn ilk n karakterinden daha kkse negatif bir
deere
Birinci yaznn ve ikinci yaznn ilk n karakteri birbirine eit ise 0 deerine geri dner.
Aada ilevin tanm ve ilevi snayan bir main ilevi veriliyor:
int strncmp(const char *s1, const char *s2, unsigned int n)
{
while (n--) {
if (*s1 != *s2)
return *(unsigned char *)s1 < *(unsigned char *)s2 ? -1 : 1;
if (*s1 == '\0')
return 0;
s1++;
s2++;
}
return 0;
}
#include <stdio.h>
#define

SIZE

100

int main()
{
char str1[SIZE];
char str2[SIZE];
int n, result;
printf("birinci yaziyi girin : ");
gets(str1);
printf("ikinci yaziyi girin : ");
gets(str2);
printf("iki yazinin kac karakteri karsilastirilacak? ");
scanf("%d", &n);
result = strncmp(str1, str2, n);
if (result == 0)

275

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

printf("(%s) == (%s)\n", str1, str2);


else if (result > 0)
printf("(%s) > (%s)\n", str1, str2);
else
printf("(%s) < (%s)\n", str1, str2);
}

return 0;

strset levi

Standart olmayan bu ilev derleyicilerin ounda bulunur. levin ismi string ve set
szcklerinden gelir. Bir karakter dizisinin belirli bir karakterle doldurulmas amacyla
kullanlr. levin string.h balk dosyas iindeki bildirimi aadaki gibidir:
char *strset(char *str, int ch);
lev birinci parametre deikeninde balang adresi olan yazy sonlandrc karakter
grene kadar ikinci parametre deikeninde tutulan karakterle doldurur. Yaznn
sonundaki sonlandrc karaktere dokunmaz.
levin geri dn deeri yine doldurulan yaznn balang adresidir.
#include <stdio.h>
#include <string.h>
int main()
{
char s[100];
int ch;
printf("bir yaz girin :");
gets(s);
printf("yazy hangi karakterle doldurmak istiyorsunuz : ");
ch = getchar();
printf("\nyaz %c karakteriyle dolduruldu (%s)\n", ch, strset(s, ch));
return 0;
}
strset ilevi aadaki gibi tanmlanabilir:
#include <stdio.h>
char *mystrset(char *str, int ch)
{
int i;
for (i = 0; str[i] != '\0'; ++i)
str[i] = ch;
}

return str;

strrev levi

Standart olmayan bu ilev de derleyicilerin ounda bulunur. levin ismi string reverse
szcklerinden gelir. lev bir yazy ters evirmek amacyla kullanlr. levin string.h
balk dosyas iinde yer alan bildirimi aadaki gibidir:

276

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

char *strrev(char *str);


lev parametre deikeninde balang adresi tutulan yazy ters evirir. levin geri
dn deeri ters evrilen yaznn balang adresidir.
strrev ilevi aadaki gibi tanmlanabilir:
char *mystrrev(char *str)
{
int i, temp;
int length = strlen(str);
for (i = 0; i < length / 2, ++i) {
temp = str[i];
str[i] = str[length - i - 1];
str[length - i - 1] = temp;
}
return str;
}

strupr ve strlwr levleri

Bu ilev standart olmamalarna karn hemen hemen her derleyicide bulunur.


simleri string upper ve string lower szcklerinden gelir. Bu ilevler bir yaznn tm
karakterleri iin byk harf kk harf dntrmesi yapar. levlerin geri dn
deerleri parametresine aktarlan adrestir. Geri dn deerlerine genellikle gereksinim
duyulmaz. Her iki ilev de temel Latin alfabesinde olan harfler iin dnm yapar.
Trke karakterler iin de dnm gerekiyorsa bunun iin bir ilev tanmlanmaldr.
#include <stdio.h>
#include <string.h>
int main()
{
char s[] = "C programcs olmak iin ok almak gerekir!";

strupr(s);
puts(s);
strlwr(s);
puts(s);
return 0;

strupr ilevi aadaki gibi tanmlanabilir:


#include <stdio.h>
#include <ctype.h>
char *mystrupr(char *str)
{
char *temp = str;

while (*str != '\0') {


if (islower(*str))
*str = toupper(*str);
++str;
}
return temp;

277

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Bir Yaznn Balang Adresini Tutan Gstericiyi Yaznn Sonuna


teleme

Birok programda balang adresi tutulan bir yaznn sonunu bulmak gerekir.
Bir yaznn balang adresini tutan bir gsteri deikeni, yaznn sonundaki sonlandrc
karakteri gsterir hale getirmek iin, ayr kalp kullanlabilir:
p bir yaznn balang adresini tutan gsterici olsun. Aadaki deyimlerin hepsi p
gsterici deikeni yaznn sonundaki, sonlandrc karakterin bulunduu yere teler.
p += strlen(p);
p = strchr(p, '\0');
while (*p != '\0')
++ptr;
Aadaki dngden ktktan sonra p gstericisi sonlandrc karakterden bir sonraki
adresi gsterir. Neden?
while (*p++ != '\0')
;

Bo Yaz

Bo yaz (null string) uzunluu 0 olan yazdr. str, char trden bir dizi olmak zere, eer
str[0] sonlandrc karakter ise, str dizisinde bo yaz tutulmaktadr. Bo yaz geerli bir
yazdr.
Yazlarla ilgili ilem yapan ilevler, adresini ald yazlarn bo yaz (null string) olmas
durumunda da doru almaldr. Aadaki dngy inceleyin:
while (*++p != '\0')
;
p bir yaznn balang adresini tutan gsterici deiken olmak zere, yukardaki
dngden kldnda p, yaznn sonundaki sonlandrc karakteri gsterir. Ancak p'nin
gsterdii yaz eer bo ise, yukardaki dng, yazya ait olmayan bellek alan zerinde
ilem yapmaya balar. Bu da phesiz bir programlama hatasdr.
imdi de aadaki if deyimini inceleyin:
int strfunc(const char *ptr)
{
if (!ptr || !*ptr)
return 0;
/***/
}
strfunc ilevi iinde yer alan if deyiminde yer alan
!ptr || !*ptr
ifadesi, ptr gsterici deikeninin deerinin NULL adresi olmas durumunda ya da ptr'nin
gsterdii yaznn bo olmas durumunda dorudur. Bu ifade, " ptr bir yazy
gstermiyorsa ya da ptr'nin gsterdii yaz bosa" anlamna gelir. Bu ifadenin mantksal
tersi olan
ptr && *ptr

278

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

ifadesi ise, ptr bir yazy gsteriyor ve ptr'nin gsterdii yaz bo deil ise anlamna gelir,
deil mi?
Her iki ifade de mantksal ilelerin ksa devre davran zelliinden faydalanlyor.
Mantksal &&, || ilelerinin ksa devre davran olmasayd, ptr'nin deeri NULL
adresiyken, ptr'nin gsterdii nesneye eriilmeye allrd.

rnekler

Aada yazlarla ilgili ilem yapan baz ilevler tanmlanyor. levlerde gsterici
deikenlerin kullanmn inceleyin.
Aada, bir yaznn C'nin kurallarna gre geerli bir isim olup olmad snayan
is_valid_id isimli ilev tanmlanyor. Yaz geerli bir isim ise ilev sfr d deere, deilse
sfr deerine geri dnyor:
#include <ctype.h>
int is_id(const char *ptr)
{
int ch;
//Bos yazi ise gecerli isim degil
if ((ch = *ptr++) == '\0')
return 0;
//lk karakter harf ya da "alt tire" olmal
if (!(isalpha(ch) || ch == '_'))
return 0;
//kalan karakterler harf rakam ya da "alt tire" olmal
while ((ch = *ptr++) != '\0')
if (!(isalnum(ch) || ch == '_'))
return 0;
}

return 1;

279

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Gsterici Hatalar

Gstericileri kullanarak RAM zerinde bir blgeye eriilebilir. Bir programn almas
srasnda bellekte alyor durumda olan baka programlar da olabilir. Gstericileri
kullanarak o anda almakta olan programn bellek alanna veri aktarlrsa oradaki
programn kodu bozulaca iin programn almasnda eitli bozukluklar kabilir. Bu
bozukluk tm sistemi olumsuz ynde etkileyebilir.
Kim tarafndan kullanldn bilmediimiz bellek blgelerine gvenli olmayan blgeler
denir. Gvenli olmayan blgelere eriilmesine ise "gsterici hatalar" denir.
Gsterici hatalar yapldnda sistem kilitlenebilir, programlar yanl alabilir. Gsterici
hatalar sonucundaki olumsuzluklar hemen ortaya kmayabilir.
Gsterici hatalar gvenli olmayan blgelere eriildiinde deil oralara veri aktarldnda
oluur.
Gsterici hatalar derleme srasnda derleyici tarafndan saptanamaz. Bu tr hatalar
programn alma zaman srasnda olumsuzluklara yol aar. Tanmlama yntemiyle elde
edilmi olan bellek blgelerine gvenli blgeler denir. Bir nesne tanmlandnda, o nesne
iin derleyici tarafndan bellekte ayrlan yer, programc iin ayrlm bir alandr ve
gvenlidir.

Gsterici Hatas Oluturan Tipik Durumlar


i)lkdeer Verilmemi Gstericilerin Yol At Hatalar:

Daha nce belirtildii gibi gstericiler de birer nesnedir. Dier nesnelerden farklar
ilerinde adres bilgileri tutmalardr. Gstericiler de nesne olduklarna gre dier nesneler
gibi yerel ya da global olabilirler. Global olarak tanmlanm gstericiler 0 deeriyle
balatlrken, yerel gstericiler p deerleriyle balatlr:
Yerel bir gsterici tanmlandktan sonra, herhangi bir ekilde bu gstericiye bir deer
atamas yaplmaz ise gstericinin iinde rastgele bir deer bulunacandan, bu gsterici *
ileci ile ya da [ ] ileci ile kullanldnda, bellekte rastgele bir yerde bulunan bir
nesneye ulalr. Dolaysyla, elde edilen nesneye bir atama yapld zaman, bellekte,
bilinmeyen rastgele bir yere yazlm olunur. Bu durum tipik bir gsterici hatasdr.
rnekler :
int main()
{
int *p;
*p = 25;
}

/* YANLI */

return 0;

Yukardaki rnekte tanmlanan p gstericisinin iinde bir p deer var.


*p = 25;
deyimiyle rastgele bir yere yani gvenli olmayan bir yere veri aktarlyor. Verinin
aktarld yerde iletim sisteminin, derleyicinin ya da bellekte kalan baka bir programn
(memory resident) kodu bulunabilir. Baz sistemlerde verinin aktarld yerde programn
kendi kodu da bulunabilir.
lkdeer verilmemi global gstericilerin iinde (ya da statik yerel gstericilerin iinde)
sfr deeri bulunur. Sfr says (NULL adresi) gstericilerde snama amacyla kullanlr. Bu
adrese bir veri aktarlmas durumunda, derleyicilerin ounda istee bal olarak bu hata
alma zaman srasnda snanr. rnek:

280

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

char *p;
int main()
{
*p = 'm';
}

/* NULL pointer assignment */

return 0;

Yukardaki kodun altrlmasnda "NULL pointer assignment" eklinde bir alma zaman
hatasyla karlalabilir. Bu snama derleyicinin alabilen program iine yerletirdii
"snama kodu" sayesinde yaplr.
lkdeer verilmemi gstericilerin neden olduu hatalar ilev arlaryla da ortaya
kabilir:
int main()
{
char *ptr;

gets(ptr); /* ????? */
return 0;

Yukardaki kod parasnda standart gets ilevi ile klavyeden alnan karakterler, bellekte
rastgele bir yere yazlr. Standart gets ilevi klavyeden alnan karakterleri kendisine
argman olarak gnderilen adresten balayarak yerletirdiine gre, daha nceki rnekte
verilen hata klavyeden girilen btn karakterler iin sz konusudur.

ii)Gvenli Olmayan lkdeerlerin Neden Olduu Gsterici Hatalar


Bir gstericiye ilkdeer verilmesi , o gstericinin gvenli bir blgeyi gsterdii anlamna
gelmez. rnein :

char *ptr;
/***/
ptr = (char *) 0x1FC5;
*ptr = 'M';
Yukardaki rnekte ptr gstericisine atanan (char *) 0x1FC5 adresinin gvenli olup
olmad konusunda hibir bilgi yoktur. Adrese ilikin blgenin kullanp kullanlmad
bilinemez. her ne kadar bellek alan iinde belli amalar iin kullanlan gvenli blgeler
varsa da 1FC5 byle bir blgeyi gstermez.

iii)Dizi Tamalarndan Doan Gsterici Hatalar

Bilindii gibi bir dizi tanmlamas grdnde derleyici, derleme srasnda dizi iin bellekte
toplam dizi uzunluu kadar yer ayrr. C derleyicileri derleme zamannda bir dizinin
tarlp tarlmadn kontrol etmez.
int main()
{
int a[10], k;

for (k = 0; k <= 10; ++k)


a[k] = 0;
/***/
return 0;

281

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yukardaki rnek bir ok sistemde derlenip altrldnda dng k deikeninin 10


deeri iin de srer. Oysa a[10] eleman iin bir yer ayrlmamtr. Dizinin son eleman
a[9] elemandr. Derleyici a dizisi iin a[0]'dan balayarak a[9] elemanlar iin bellekte
toplam 10 nesnelik yani 40 byte'lk bir yer ayrr. Oysa yeri ayrlmam olan a[10]
blgesinin kim tarafndan ve ne amala kullanld hakknda herhangi bir bilgi yoktur.
Bu konuda bir garanti bulunmamakla birlikte derleyicilerin ou, ardk olarak
tanmlanan elemanlar bellekte bitiik olarak (contiguous) olarak yerletirirler. Ama bu
gvence altna alnm bir zellik deildir. Yani bunun gvence altna alnd dnlerek
kod yazlmas problemlere yol aar. Yukardaki rnekte a[10] blgesi derleyicilerin
ounda a dizisinden hemen sonra tanmlanan ve dng deikeni olarak kullanlan k
deikenine ayrlr. Dolaysyla a[10] elemanna 0 deerini vermekle aslnda k
deikenine 0 deeri aktarlm olabilir ve bu da dngnn sonsuz bir dngye
dnmesine yol aabilir.
Keli ayra ileci de bir gsterici ilecidir, bu ileci kullanarak dizi iin ayrlan alann
dna atama yaplabilir. C dili derleyicileri kaynak kodu bu amala denetlemezler. Ayrca
a dizisi iin a[-1], a[-2].. gibi ifadeler de szdizim asndan geerlidir ve buraya
yaplacak atamalar da gsterici hatalarna yol aar.
Bazen dizi tamalarna ilevler de gizli bir biimde neden olabilir. rnein:
void func()
{
char str[6];

printf("isim girin : ");


gets(str);
/***/

func ilevi iinde tanmlanan str dizisi iin toplam 6 karakterlik yer ayrlyor. Standart gets
ilevi klavyeden alnan karakterleri kendisine gnderilen adresten balayarak bellee
yerletirdikten sonra, sonlandrc karakteri de diziye yazar. O halde yukardaki rnekte
programn almas srasnda 6 ya da daha fazla karakterin girilmesi gsterici hatasna
neden olur. Sonlandrc karakter de ('\0') bellekte bir yer kaplayaca iin program iin
ayrlm bir bellek alan iinde bulunmas gerekir. rnein klavyeden girilen isim
necati
olsun. gets ilevi bu karakterleri aadaki gibi yerletirir :

Sonlandrc karakter, dizi iin ayrlan blgenin dna yerletiriliyor. Bu rnekte girilen
isim daha uzun olsayd, program iin ayrlmam bir blgeye daha fazla karakter
yazlacakt. Bu tr hatalarla karlamamak iin dizi yeteri kadar uzun olmal ya da
standart bir C ilevi olan gets ilevi yerine, dizi uzunluundan daha fazla sayda eleman
yerletirilmesine izin vermeyecek bir ilev kullanlmaldr. Bu amala fgets isimli ilev
arlabilir. Standart fgets ilevini dosyalar konusunda greceksiniz.
Dizgelerle ilgili ilemler yapan standart C ilevlerinden strcpy, strcat, strncpy, strncat
ilevlerinin yanl kullanlmas da benzer hatalar oluturabilir.

282

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

void Trden Gstericiler

Baz ilevler bellek bloklar zerinde genelletirilmi ilemler yapar. Bu ilevler ilem
yaptklar bellek bloklarnda ne olduuyla ilgilenmez. Bir bellek blounun ieriinin
bellekte baka bir yere kopyalandn dnn. lev kaynak adresten hedef adrese byte
byte kopyalama yaparak bu amac gerekletirebilir. Byle bir ilevin parametre
deikenleri hangi trden olmaldr?
void gstericiler herhangi bir trden olmayan gstericilerdir. Bu trden deikenlerin
tanmlarnda void anahtar szc kullanlr:
void *ptr;
void gstericilerin tr bilgisi yoktur. void gstericilerde adreslerin yalnzca saysal
bileenleri saklanr. Bu yzden void gstericilerle dier trden gstericiler (adresler)
arasnda yaplan atamalar geerlidir. void trden bir gstericiye herhangi bir trden bir
adres sorunsuzca atanabilir. Belirli trden bir gsterici deikene void trden bir adres de
ayn ekilde sorunsuzca atanabilir.
char *ptr;
void *vp;
/***/
ptr = vp;
vp = ptr;

/* Geerli*/
/* Geerli */

void gstericiler belirli bir tre ait olmadklar iin, tr bilgisine sahip olan gstericiler
zerinde uygulanan baz ilemler void trden gstericilere uygulanamaz:
i) void trden gstericilerin * ya da [ ] ilelerinin terimi olmas geersizdir. Bu ileler bir
nesneye erimek iin tr bilgisine gereksinim duyar.
void func()
{
double a[50];
void *vptr;
vptr = a; /* Geerli */
*vptr = 3.7;
/* Geersiz! */
vptr[2] = 5.6;
/* Geersiz! */
/****/
}
Yukardaki kod parasnda *vptr ve vptr[2] ifadeleri geersizdir.
ii) void trden bir adres ile bir tamsaynn toplanmas ya da void trden bir adresten bir
tamsaynn kartlmas geersizdir. nk gsterici aritmetiine gre bir gstericinin
deeri n kadar artrldnda, gsterici iindeki adresin saysal bileeni n ile gstericinin
gsterdii nesnenin tr uzunluunun arpm kadar artar. void gstericilerin trleri
olmad iin bu durumda saysal bileenin ne kadar artaca da bilinemez.
void trden gstericiler ++ ve -- ilelerinin terimi olamaz.
++ptr;
ifadesi
ptr = ptr + 1;
ifadesine edeerdir.

283

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

void func()
{
int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
void *vptr = a;
void *p;
p = vptr + 2; /* Geersiz */
++vptr;
/* Geersiz */
--vptr;
/* Geersiz */
vptr += 2;
/* Geersiz */
vptr -= 3;
/* Geersiz */
}
iii) Benzer ekilde, void trden iki adres birbirinden kartlamaz. Dier trden adresler
iin, ayn blok iindeki iki nesneye ilikin iki adresin birbirinden kartlmas tamamen
geerlidir. Byle bir ifadenin deeri iki adres arasndaki nesne saysna denk bir tamsay
oldugunu hatrlayn.
void func()
{
void *p1, *p2;
int k;
/***/
k = p1 - p2;
/* Geersiz */
}
void gsterici deikenleri adreslerin yalnzca saysal bileenlerini saklamak amacyla
kullanlrlar. Dier tr gstericiler arasndaki atama ilemlerinde uyar ya da hata
oluturmadklarndan dolay, trden bamsz adres ilemlerinin yapld ilevlerde
parametre deikeni biiminde de bulunabilirler. rnein:
void func(void *p);
func isimli ilevin parametre deikeni void trden bir gsterici olduundan bu ileve
argman olarak herhangi bir trden bir adres bilgisi gnderilebilir. Yani func ilevi
herhangi bir nesnenin adresi ile arlabilir. Bu durumda derleme zamannda bir hata
olumad gibi, derleyiciden bir uyar iletisi de alnmaz.
func ilevi, ald adresteki nesnenin trne bal bir ilem yapmaz.
C dilinde ilevler void trden adreslere de geri dnebilir. void trden adreslerin herhangi
bir trden gsterici deikene atanmas geerlidir
void *func(void);
int main()
{
int *p;
char *str;
p = func();
/***/
str = func();
}

/* Geerli */
/* Geerli */

return 0;

Parametre Deikeni void Gsterici Olan Standart C levleri

Standart ktphanede ba mem harfleri ile balayan biiminde bir grup ilev vardr. Bu
ilevler trden bamsz olarak bellek bloklaryla ilgili genel ilemler yapar.

284

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

void gstericilerin kullanmn en iyi aklayan rnek, standart string.h balk dosyas
iinde bildirilen memcpy ilevidir.
void *memcpy(void *pdest, const void *psource, size_t nbytes);
memcpy ilevi ikinci parametresiyle belirtilen adresten balayarak (psource), nbytes
sayda byte' birinci parametresiyle belirtilen adresten(pdest) balayarak kopyalar.
levin sonlandrc karakterle ya da yazlarla bir ilikisi yoktur, koulsuz bir kopyalama
yapar. Yani bir blok kopyalamas sz konusudur. lev kopyalad bellek blounda ne
olduu ya da hangi trden bir veri olduuyla ilgilenmeksizin kaynak adresten hedef
adrese belirli sayda byte' kopyalar. zellikle sistem programlarnda ok kullanlan bir
standart ilevdir.
memcpy ileviyle rnein ayn trden herhangi iki dizi birbirine kopyalanabilir:
#include <stdio.h>
#include <string.h>
#define

SIZE

10

int main()
{
int a[SIZE] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int b[SIZE];
int i;
memcpy(b, a, sizeof(int));
for (i = 0; i < SIZE; ++i)
printf("%d\n", b[i]);
}

return 0;

Aadaki ilev arlar da edeerdir:


char s[50] = "Ali";
char d[50];
strcpy(d, s);
memcpy(d, s, strlen(s) + 1);
memcpy ilevinin gsterici olan parametreleri void trdendir. nk hangi trden adres
geirilirse geirilsin, derleyicilerden herhangi bir uyar iletisi alnmaz. Bu ilev aadaki
gibi tanmlanabilir:
void *mymemcpy(void *vp1, const void *vp2, unsigned int n)
{
char *p1 = vp1;
const char *p2 = vp2;
unsigned int k;
for (k = 0; k < n; ++k)
p1[k] = p2[k];
}

return vp1;

lev u biimde de tanmlanabilirdi:

285

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
void *mymemcpy(void *vp1, const void *vp2, size_t n)
{
char *p1 = vp1;
const char *p2 = vp2;
while (n--)
*p1++ = *p2++;
return vp1;
}
int main()
{
int a[5] = {1, 2, 3, 4, 5};
int b[5], i;
mymemcpy(b, a, 10);
for (i = 0; i < 5; ++i)
printf("%d\n", b[i]);
return 0;
}
Ancak memcpy ilevinin akk bloklarn kopyalanmasnda davran gvence altnda
deildir.

memmove ilevi

memove da bir blou bir yerden bir yere kopyalar. levin bildirimi memcpy ilevininki ile
tamamen ayndr.
void *memmove(void *dest, const void *source, unsignt int nbytes);
ki ilev arasndaki tek fark memmove ilevinin akk bloklarn kopyalanmasnda
davrannn gvence altnda olmasdr.
akk olmayan bloklarn kopyalanmasnda memmove ilevi mi tercih edilmelidir? Hayr,
bu iyi bir tavsiye olamaz. nk:
1. memmove ilevinin byle bir gvence vermesinin ek bir yk vardr.
2. memmove ilevin kullanlmas durumunda kodu okuyan kii kopyalamann yapld
blokla kopyalamann yaplaca bloklarn bir ekilde akt konusunda gl bir izlenim
edinir.
Bu durumda, kaynak blokla hedef bloun akmas durumunda ya da akma riskinin
bulunduu durumlarda memmove ilevi, aksi halde yani sz konusu bloklarn akmad
kesinlikle biliniyorsa memcpy ilevi tercih edilmelidir.
Aada memmove ilevi iin yazlan rnek bir kod yer alyor:
void *mymemmove(void *vp1, const void *vp2, unsigned int n)
{
char *p1 = vp1;
const char *p2 = vp2;
if (p1 > p2 && p2 + n > p1) {
p1 += n;
p2 += n;
while (n--)
*--p1 = *--p2;
}

286

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

else
while (n--)
*p1++ = *p2++;
return vp1;
}

memset ilevi

Standart bir C ilevidir. Adresi verilen bir bellek blounu belirli bir karakter ile yani bir
byte deeri ile doldurmak iin kullanlr. levin bildirimi:
void *memset(void *block, int c, unsigned int nbytes);
Bu ilev block adresinden balayarak nbytes byklndeki blou, ikinci parametresiyle
belirtilen byte deeriyle doldurulur.
lev rnein, herhangi bir trden bir diziyi sfrlamak amacyla kullanlabilir:
double d[100];
memset(d, 0, sizeof(d));
lev aadaki gibi tanmlanabilir:
#include <stdio.h>
void *mymemset(void *block, int c, unsigned int n);
int main()
{
int a[10];
int i;
mymemset(a, 0, sizeof(a));
for (i = 0; i < 10; ++i)
printf("%d\n",a[i]);
}

return 0;

void *mymemset(void *block, int c, size_t n)


{
char *p=(char *)block;
while (n--)
*p++ = c;
}

return block;

memchr ilevi
Standart bir C ilevidir. Adresi verilen bir bellek blounda belirli bir byte deerini aramak
iin kullanlr. levin string.h balk dosyas iindeki bildirimi aadaki gibidir:
void *memchr(const void *block, int c, unsigned int nbytes);
lev block adresinden balayan nbytes iinde c deerine sahip bir byte' arar. lev ilk
bulduu c deerine sahip byte'n adresi ile geri dner. levin geri dn deeri void

287

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

trden bir adrestir. Eer aranan byte bulunamaz ise ilev NULL adresine geri dner.
levin baars mutlaka snanmaldr. lev aadaki gibi tanmlanabilir:
void *mymemchr(const void *p_block, int c, unsigned int nbytes)
{
const char *p = p_block;

while (nbytes--) {
if (*p == c)
return (void *)p;
p++;
}
return NULL;

memcmp ilevi
Standart bir C ilevidir. Adresleri verilen iki bellek blounu karlatrmak amacyla
kullanlr. levin string.h balk dosyas iindeki bildirimi aadaki gibidir:
int memcmp(const void *pblock1, const void *pblock1, unsigned int nbytes);
lev block1 ve block2 adreslerinden balayan nbytes byklndeki iki blou
karlatrr. levin geri dn deeri int trdendir. Geri dn deerinin yorumlanmas
standart strcmp ilevine benzer:
ki bellek blou tamamen aynysa, yani iki bloktaki tm byte'lar birbirine eitse, ilev 0
deerine geri dner.
Birinci bellek blou ikinci bellek bloundan daha bykse ilev 0'dan byk bir deere
geri dner. Birinci bellek blou ikinci bellek bloundan daha kkse ilev 0'dan kk bir
deere geri dner. Karlatrma yle yaplr: Bloklar dk saysal adreslerden
balayarak byte byte iaretsiz tamsay olarak karlatrlr. Farkl olan ilk byte ile
karlaldnda, daha byk olan tamsayya sahip blok daha byktr.
lev aadaki gibi tanmlanabilir:
int mymemcmp(const void *vp1, const void *vp2, size_t nbytes)
{
const unsigned char *p1 = vp1;
const unsigned char *p2 = vp2;
unsigned int k;
for (k = 0; k < nbytes; ++k)
if (p1[k] != p2[k])
return p1[k] < p2[k] ? -1 : 1;
}

return 0;

Aada yazlan ilevi snayan bir main ilevi yazlyor:


int main()
{
unsigned char s1[100] = {0};
unsigned char s2[100] = {0};
if (!mymemcmp(s1, s2, 100))
printf("bloklar esit!\n");
s1[90] = 1;

288

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

if (mymemcmp(s1, s2, 100) > 0)


printf("birinci blok buyuk!\n");
return 0;
}

289

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

DZGELER

C dilinde iki trnak iindeki karakterlere dizge ifadesi (string literal) ya da ksaca dizge
(string) denir. rnein:
"Necati Ergin"
"x = %d\n"
"ltfen bir say giriniz : "
ifadelerinin hepsi birer dizgedir.
Dizgelerin tek bir atom olarak ele alndn nceki konularmzdan anmsayacaksnz. C'de
dizgeler, derleyiciler tarafndan aslnda char trden bir dizinin adresi olarak ele alnr. C
derleyicileri, derleme aamasnda bir dizgeyle karlatnda, nce bu dizgeyi oluturan
karakterleri bellein gvenli bir blgesine yerletirir, sonuna sonlandrc karakteri ekler.
Daha sonra dizge yerine, yerletirildii yerin balang adresini koyar. Bu durumda dizge
ifadeleri aslnda, dizgelerin derleyici tarafndan yerletirildii dizinin balang adresidir.
rnein:
char *p;
p = "Necati Ergin";
gibi bir kod parasnn derlenmesi srasnda, derleyici nce "Necati Ergin" dizgesini
bellein gvenli bir blgesine yerletirir. Daha sonra yerletirdii yerin balang adresini
dizge ifadesi ile deitirir.
Dizgeler char trden bir dizinin balang adresi olarak ele alndna gre, dizgelerin char
trden gsterici deikenlere atanmalar geerlidir. Aadaki main ilevini derleyerek
altrn:
#include <stdio.h>
int main()
{
printf("adres = %p\n", "Necati");
printf("adres = %s\n", "Necati");
}

return 0;

main ilevi iinde yaplan ilk printf arsnda "Necati" dizgesi ile %p format karakteri
eleniyor. printf ilevi ile, adres bilgilerinin %p format karakteriyle ekrana
yazdrlabileceini anmsayn. Bu durumda alan kod, "Necati" yazsnn yerletirildii
yerin balang adresini ekrana yazar. kinci printf arsnda ise "Necati" dizgesi %s
format karakteri ile eleniyor. Bu durumda ekrana ilgili adresteki yaz, yani Necati yazs
yazdrlr.
imdi de aadaki arya bakn:
putchar(*"Necati");
"Necati" dizgesinin bu kez ierik ilecinin terimi olduunu gryorsunuz. erik ileci,
terimi olan adresteki nesneye eriimi saladna gre, bu nesnenin deeri 'N'
karakterinin kod numarasdr. arlan putchar ilevinin almasyla ekrana N karakteri
baslr.
Aada tanmlanan get_hex_char ilevi, onaltlk say sisteminde bir basamak deeri
hangi karakter ile gsteriliyorsa, o karakterin kullanlan karakter setindeki kod
numarasn dndryor:
#include <stdio.h>

291

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

int get_hex_char(int val)


{
return "0123456789ABCDEF"[val];
}
int main()
{
int k;
for (k = 0; k < 16; ++k)
putchar(get_hex_char(k));
}

return 0;

levin geri dn deeri


"0123456789ABCDEF"[val]
ifadesinin deeridir. Bu da dizgenin yerletirildii adresten val uzaklktaki nesnenin
deeridir. char trden bu nesnenin deeri de dizgede yer alan karakterlerden herhangi
birinin sra numarasdr. main ilevi iinde 0 15 aralndaki deerlere karlk gelen
karakterler bir dng iinde get_hex_char ilevi ile elde edilerek putchar ilevine
argman olarak gnderiliyor. Programn ekran kts
0123456789ABCDEF
olur.
Dizgelerin bellekte kaplayacaklar yer derleme zamannda belirlenir. Aadaki program
her altrldnda, ekrana hep ayn adres deeri yazlr:
#include <stdio.h>
int main()
{
int k;
for (k = 0; k < 10; ++k)
printf("%p\n", "Necati");
}

return 0;

Dizgelerin levlere Argman Olarak Gnderilmesi

Parametre deikeni char trden bir gsterici olan ilevi, char trden bir adres ile
armak gerektiini biliyorsunuz. nk char trden bir gsterici deikene, doal olarak
char trden bir adres atanmaldr.
Derleyiciler asndan dizgeler de char trden bir adres belirttiklerine gre, parametre
deikeni char trden gsterici olan bir ilevi, bir dizge ile armak son derece doal bir
durumdur:
puts("Necati Ergin");
Burada derleyici "Necati Ergin" dizgesini bellee yerletirip sonuna sonlandrc karakteri
koyduktan sonra artk bu dizgeyi, karakterlerini yerletirdii bellek blounun balang
adresi olarak grr. puts ilevinin parametre deikenine de artk char trden bir adres
kopyalanr. puts ilevi parametre deikeninde tutulan adresten balayarak sonlandrc
karakteri grene kadar tm karakterleri ekrana yazar. Bu durumda ekranda

292

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Necati Ergin
yazs kar.
Aadaki rnekte de "Necati Ergin" dizgesi str adresine kopyalanr. Dizge ifadelerinin
bulunduu yerde, char trden bir dizinin adresi bulunduu dnlmelidir.
#include <stdio.h>
#include <string.h>
int main()
{
char str[20];
strcpy(str, "Necati Ergin");
puts(str);
return 0;
}

Dizgeler Salt Okunur Yazlardr

Dizgeler salt okunur bellek alanlarnda tutulabilir. Bu yzden bir dizgenin ieriinin
kaynak kod iinde deitirilmesi yanltr. Dizgeleri deitiren kodlar tanmsz davran
(undefined behavior) zellii gsterir. Aadaki rnei inceleyin:
#include <stdio.h>
int main()
{
char *ptr = "Durak";
*ptr = 'B'; /* Yanl */
puts(ptr);
}

return 0;

main ilevi iinde tanmlanan ptr isimli gsterici deiken "Durak" dizgesini gsteriyor. ptr
gstericisinin gsterdii nesneye atama yaplmas yanltr. Yukardaki program derleme
zamanna ynelik bir hata iermiyor.

zde Dizgeler

C derleyicileri kaynak kodun eitli yerlerinde tamamen zde dizgelere rastlasa bile
bunlar iin farkl yerler ayrabilir. Ya da derleyici, dizgelerin salt okunur yazlar olmasna
dayanarak, zde dizgelerin yalnzca bir kopyasn bellekte saklayabilir. zde dizgelerin
nasl saklanaca derleyicinin seimine braklmtr. Birok derleyici, zde dizgelerin
bellekte nasl tutulacaklar konusunda programcnn seim yapmasna olanak verir.

Dizgelerin Karlatrlmas

Dizgelerin dorudan karlatrlmas yanl bir ilemdir.

/***/
if ("Ankara" == "Ankara")
printf("dogru!\n");
else
printf("yanlis!\n");
/***/

293

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yukardaki kodun altrlmas durumunda, ekrana "yanl" ya da "doru" yazdrlmas


gvence altnda deildir. Eer derleyici iki "Ankara" dizgesini bellekte ayr ayr yerlere
yerletirmi ise, == karlatrma ileci 0 deeri retir. Ancak bir derleyici, "Ankara"
yazsn tek bir yere yerletirip her iki dizgeyi ayn adres olarak da ele alabilir. Byle bir
durumda == karlatrma ileci 1 deeri retir.
Benzer bir yanllk aadaki kod parasnda da yaplyor:
#include <stdio.h>
int main()
{
char *pstr = "Mavi ay";
char s[20];
printf("parolay giriniz : ");
gets(s);
if (pstr == s)
printf("dogru parola\n");
else
printf("yanl parola\n");
}

return 0;

Yukardaki programda s bir dizinin ismidir. s ismi ileme sokulduunda derleyici


tarafndan otomatik olarak dizinin balang adresine dntrlr. pstr ise char trden
bir gsterici deikendir. pstr gstericisine "Mavi ay" dizgesi atandnda, derleyici nce
"Mavi ay" dizgesini bellekte gvenli bir yere yerletirir. Daha sonra dizgenin yerletirildii
yerin balang adresini pstr gstericisine atar. Kullancnn, parola olarak "Mavi ay" girii
yaptn varsayn. Bu durumda if deyimi iinde yalnzca s adresiyle pstr gstericisinin
deeri olan adresin eit olup olmad snanr. Bu adresler eit olmadklar iin ekrana
"yanl parola" yazlr. ki yaznn birbirine eit olup olmad standart strcmp ilevi ile
snanmalyd:
#include <stdio.h>
#include <string.h>
int main()
{
char *pstr = "Mavi ay";
char s[20];
printf("parolay giriniz : ");
gets(s);
if (!strcmp(pstr, s))
printf("dogru parola\n");
else
printf("yanl parola\n");
return 0;
}
Tabi eitlik ya da eitsizlik karlatrmas gibi, byklk kklk karlatrmas da
doru deildir.
if ("CAN" > "ATA")
printf("doru!\n");
else
printf("yanli!\n");

294

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yukardaki if deyiminde CAN ve ATA isimleri strcmp ilevinin yapt biimde, yani bir yaz
olarak karlatrlmyor. Aslnda karlatrlan yalnzca iki adresin saysal bileenidir.

Dizgelerin mr

Dizgeler statik mrl varlklardr. Dizgeler, tpk global deikenler gibi programn
yklenmesiyle bellekte yer kaplamaya balar, programn sonuna kadar bellekte kalr.
Dolaysyla dizgeler alabilen kodu bytr. Birok sistemde statik verilerin toplam
uzunluunda belli bir snrlama sz konusudur.
Dizgeler derleyici tarafndan .obj modle balayc program tarafndan da .exe dosyasna
yazlr. Programn yklenmesiyle hayat kazanrlar.
altrlabilen bir program ounlukla ana blmden oluur:
kod
data
yn
Kod blmnde, ilevlerin makine kodlar vardr. Data blmnde, statik mrl varlklar
bulunur. Global deikenler ile dizgeler bu blmde bulunur. Yn blm yerel
deikenlerin sakland bellek alandr. Yn blm her sistemde snrl bir alandr.
rnein DOS iletim sisteminde 64K byklnde bir yn alan sz konusudur. Yani
hibir zaman yerel deikenlerin bellekte kaplad alan 64K deerini geemez.
WINDOWS iletim sisteminde varsaylan yn snr deeri 1 MB dr. Ancak bu snr deeri
istenildii kadar bytlebilir.

Bir levin Bir Dizgeyle Geri Dnmesi

Adrese geri dnen bir ilevin, yerel bir deikenin ya da yerel bir dizinin adresi ile geri
dnmesi gsterici hatasdr. lev sonlandnda yerel deikenler bellekten boaltlaca
iin, ilevin geri dndrd adres gvenli bir adres olmaz. Aadaki programda byle
bir hatay yaplyor:
#include <stdio.h>
char *getname()
{
char s[100];
printf("ad ve soyad giriniz : ");
gets(s);
}

return s;

/* Yanl! */

int main()
{
char *ptr;
ptr = getname();
puts(ptr);
}

return 0;

Ancak char trden bir adrese geri dnen bir ilev bir dizge ile geri dnebilir. Bu durumda
bir alma zaman hatas sz konusu olmaz. Dizgeler statik mrl varlklar
olduklarndan programn alma sresi boyunca bellekteki yerlerini korur. rnein
aadaki ilev geerli ve dorudur:

295

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

char *getday(int day)


{
switch (day) {
case 0: return "Sunday";
case 1: return "Monday";
case 2: return "Tuesday";
case 3: return "Wednesday";
case 4: return "Thursday";
case 5: return "Friday";
case 6: return "Saturday";
}

Dizgelerin Birletirilmesi
Dizgeler tek bir atom olarak ele alnr. Bir dizge aadaki gibi paralanamaz:
void func()
{
char *ptr = "Necati Ergin'in C Ders
Notlarn okuyorsunuz";
/* Geersiz */
/***/
}
Ancak dizgelerin uzunluu arttka dizgeleri tek bir satrda yazmak zorlaabilir. Ekrandaki
bir satrlk grntye smayan satrlar kaynak kodun okunabilirliini bozar. Uzun
dizgelerin paralanmasna olanak vermek amacyla, C derleyicileri, aralarnda boluk
karakteri dnda baka bir karakter olmayan dizgeleri birletirerek tek bir dizge olarak
ele alr. rnein:
ptr = "Necati Ergin'in C Ders "
"Notlarn okuyorsunuz";
geerli bir ifadedir. Bu durumda derleyici iki dizgeyi birletirirek kodu aadaki biimde
ele alr:
ptr = "Necati Ergin'in C Ders Notlarn okuyorsunuz";
Derleyicinin iki dizgeyi birletirmesi iin, dizgelerin arasnda boluk karakterlerinin (white
space) dnda hibir karakterin olmamas gerekir:
p = "Necati" "Ergin";
ifadesi ile
p = "NecatiErgin";
ifadesi edeerdir.
Birletirmenin yansra, bir ters bl karakteri ile sonlandrlarak sonraki satra gei
salanabilir. rnein:
ptr = "Necati Ergin'in C Ders \
Notlarn okuyorsunuz";
deyimi ile
ptr = "Necati Ergin'in C Ders Notlarn okuyorsunuz";
deyimi edeerdir. Tersbl karakterinden sonra, dizge aadaki satrn bandan devam
etmelidir. Sz konusu dizge aadaki gibi yazlrsa:

296

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

ptr = "Necati Ergin'in C Dersi \


Notlarn okuyorsunuz";
satr bandaki boluk karakterleri de dizgeye katlr. Sonu aadaki ifadeye edeer
olur:
ptr = "Necati Ergin'in C Dersi

Notlarn okuyorsunuz";

Dizgelerde Ters Bl Karakter Deimezlerinin Kullanlmas

Dizgeler iinde ters bl karakter deimezleri de (escape sequence) kullanlabilir.


Derleyiciler dizgeler iinde bir ters bl karakteri grdnde, onu yanndaki karakter ile
birlikte tek bir karakter olarak ele alr. rnein:

char *p;
p = "Necati\tErgin";
ifadesinde \t tek bir karakterdir (9 numaral ASCII karakteri olan tab karakteri).
Yani
printf("dizgedeki karakter says = %d\n", strlen(p));
ifadesi ile ekrana
dizgedeki karakter says = 12
yazdrlr.
Dizge ifadelerinde dorudan ift trnak ya da ters bl karakterleri kullanlamaz. Bu
karakterlerin zel ilevleri vardr. "ift trnak" karakter deimezinin kendisini ifade
etmek iin, ift trnak karakterinden nce bir ters bl karakteri kullanlr. rnein:
#include <stdio.h>
int main()
{
puts("\"Necati Ergin\"");
return 0;
}
main ilevi iinde yaplan
puts(ptr);
ars ile ekrana
"Necati Ergin"
yazs yazdrlr.
Dizge iinde yer alan ters bl karakter deimezi, onaltlk say sisteminde de ifade
edilebilir. Aadaki program derleyerek altrn:
#include <stdio.h>
int main()
{
puts("\x41\x43\x41\x42\x41");
return 0;
}

297

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Bo Dizge

Bir dizge bo olabilir (null string) yani iinde hibir karakter bulunmayabilir. Bu durum iki
ift trnak karakterinin arasna hibir karakter yazlmamas ile oluturulur.
char *ptr = "";
Yukardaki deyim ile ptr gstericisine bo dizge atanyor. Bo dizgeler de bellekte bir
adres belirtir. Derleyici bo bir dizge grdnde, bellekte gvenilir bir yere yalnzca
sonlandrc karakteri yerletirir.
Bo bir dizge uzunluu 0 olan bir dizgedir. Aadaki program derleyerek altrn:
#include <stdio.h>
#include <string.h>
int main()
{
char *ptr = "";
printf("uzunluk = %d\n", strlen(ptr));
return 0;
}

Dizgelerle Gsterici Deikenlere lkdeer Verilmesi

Dizgeler kullanlarak char trden gsterici deikenlere ilkdeer verilebilir. rnein:

char *p = "stanbul";
char *err = "Bellek yetersiz";
char *s = "Devam etmek iin bir tua basnz";
Dizgeler derleyiciler tarafndan char trden bir dizi adresi olarak ele alndna gre, char
trden gsterici deikenlere dizgelerle ilkdeer verilmesi doal bir durumdur.
Dizilere ift trnak iinde ilkdeer vermek ile, gsterici deikenlere dizgelerle ilkdeer
vermek arasndaki farka dikkat etmek gerekir:
char *p = "Deneme";
char s[10] = "Deneme";
deyimleri tamamen farkldr.
Gsterici deikenlere ilkdeer verildiinde, derleyici bunu bir dizge ifadesi olarak ele alr.
Yani dizge bellee yerletirildikten sonra balang adresi gstericiye atanr. Oysa
dizilerde nce dizi iin yer ayrlr, daha sonra karakterler tek tek dizi elemanlarna
yerletirilir. Dizilere ilkdeer verirken kullanlan ift trnak ifadeleri adres bilgisine
dntrlmez. Dizi elemanlarna tek tek char trden deimezlerle ilkdeer verme ilemi
zahmetli olduu iin, programcnn iini kolaylatrmak amac ile byle bir ilkdeer verme
kural getirilmitir.
char s[10] = "Deneme";
deyimi aslnda
char s[10] = {'D', 'e', 'n', 'e', 'm', 'e', '\0'};
ile ayn anlamdadr.

298

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yaz Tutan char Trden Dizilerle Bir Dizgeyi Gsteren char Trden
Gstericilerin Karlatrlmas
C dilinde bir yaz bilgisi en az iki ayr biimde saklanabilir:
1. Bir yaz char trden bir dizi iinde saklanabilir:
#include <stdio.h>
#include <string.h>
void foo()
{
char s1[100] = "Necati Ergin";
char s2[100];
char s3[100];

printf("bir yaz giriniz: ");


gets(s2);
strcpy(s3, s2);
/***/

Yukardaki foo ilevinde s1 dizisine Necati Ergin yazs ilkdeer olarak yerletiriliyor.
s2 dizisine ise standart gets ilevi arsyla klavyeden bir yaz alnyor.
s2 dizisindeki yaz, standart strcpy ilevine yaplan ar ile s3 dizisine kopyalanyor.
2. Yaz bir dizge olarak saklanarak char trden bir gsterici deikenin bu dizgeyi
gstermesi salanabilir:
char *ptr = "Necati Ergin";
ki yntem, birbirinin tamamen edeeri deildir. Aadaki noktalara dikkat edilmesi
gerekir:
Dizgeler statik mrl varlklar olduklar iin programn sonlanmasna kadar bellekte yer
kaplar. Bir gsterici deikenin bir dizgeyi gsterirken, daha sonra baka bir dizgeyi
gsterir duruma getirilmesi, daha nceki dizgenin bellekten boaltlaca anlamna
gelmez:
char *p = "Bu dizge programn sonuna kadar bellekte kalacak.";
p = "artk yukardaki dizge ile bir balant kalmayacak...";
Yaznn char trden bir dizi iinde tutulmas durumunda bu yazy deitirmek
mmkndr. Dizi elemanlarna yeniden atamalar yaplarak yaz istenildii gibi
deitirilebilir. Ama dizgelerin deitirilmesi tanmlanmam davran zellii gsterir,
yanltr:
#include <stdio.h>
#include <string.h>
void foo()
{
char *ps = "Metin";
char *pstr = "Ankara";

ps[1] = '';
strcpy(pstr, "Bolu");
/***/

/* Yanl! */
/* Yanl! */

299

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

GSTERC DZLER
Gstericiler de birer nesne olduuna gre gsterici dizileri de tanmlanabilir:
Elemanlar gsterici deikenlerden oluan dizilere "gsterici dizileri" (pointer arrays)
denir. rnekler:
char *pstr[10];
int *ap[50];
float *kilo[10];
Gsterici dizilerinin bildirimleri, normal dizi bildirimlerinden farkl olarak '*' atomu ile
yaplr. rnein:
char str[100];
bildiriminde, str 100 elemanl char trden bir dizi iken
char *pstr[100];
bildiriminde ise, pstr 100 elemanl char trden bir gsterici dizisidir. Yani dizinin her bir
eleman char * trnden nesnedir. Dizinin her bir eleman bir gsterici deikendir.
Derleyici, bir gsterici dizisi tanmlamas ile karlanca, dier dizilerde yapt gibi,
bellekte belirtilen sayda gsterici nesnesini tutabilecek kadar, bitiik bir bellek blou
ayrr. rnein:
char *p[10];
bildirimi ile derleyici, p dizisinin 10 elemanl ve her elemann char trden bir gsterici
olduunu anlar. Kullanlan sistemde gstericilerin uzunluunun 4 byte olduu varsaylrsa,
derleyici bu dizi iin 40 byte'lk bir bellek blou ayrr. Bu durumda;
p[0], p[1], p[2], ...p[9]
dizi elemanlarnn her biri char * trndendir. Bu dizinin elemanlarndan her bir nesne,
dierinden bamsz olarak kullanlabilir.

Gsterici Dizilerine lkdeer Verilmesi


Gsterici dizilerine de ilkdeer verilebilir: rnein:
int *p[] = {
(int *)
(int *)
(int *)
(int *)
(int *)
}

0x1FC0,
0x1FC2,
0x1FC4,
0x1FC6,
0x1FC8

Kukusuz, gsterici dizisinin elemanlarna atanan adreslerin bir ama dorultusunda


kullanlabilmesi iin, gvenli blgeleri gstermesi gerekir. Bu nedenle uygulamada char
trden gsterici dizisi dndaki gsterici dizilerine ilkdeer verilmesi durumuna sk
rastlanmaz. Genellikle char trden gsterici dizilerine, dizge ifadeleriyle ilkdeer verilir.

char Trden Gsterici Dizileri

Uygulamalarda en sk grlen, char trden olan gsterici dizileridir.


Dizgelerin, C derleyicisi tarafndan otomatik olarak char trden dizi adreslerine
dntrldn biliyorsunuz. Bu durumda char trden bir gsterici dizisinin
elemanlarna dizgeler ile ilkdeer verilebilir:

301

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

char *aylar[] = {"Ocak", "ubat", "Mart", "Nisan", "Mays", "Haziran",


"Temmuz", "Austos", "Eyll", "Ekim", "Kasm", "Aralk"};
aylar dizisinin her bir eleman char trden bir gstericidir. Bu gsterici dizisine, dizgeler
ile ilkdeer veriliyor. Baka bir deyile, char trden bir gsterici dizisi olan aylar dizisinin
her bir eleman, yln aylarnn ismi olan yazlar gsteriyor.

char Trden Gsterici Dizilerinin Kullanlma Temalar

char trden gsterici dizileri yazlarla ilgili ilemler yapan programlarda ska kullanlr.
Program iinde sk kullanlacak yazlarn, kaynak kod iinde her defasnda bir dizge olarak
yazlmas yerine, bir gsterici dizisinin elemanlarnda saklanmas ok rastlanan bir
temadr. Aadaki rnekte error_messages dizisinin her bir elemannda, hata iletilerine
ilikin yazlar saklanyor.
char *error_messages[] = {"Bellek Yetersiz!", "Hatal ifre", "Dosya
bulunamad", "Belirtilen dosya zaten var", "src hazr deil", "Okunacak
dosya alamyor", "yazlacak dosya alamyor!..", "Belirlenemeyen
hata!"};
Artk programn herhangi bir yerinde yazlardan biri yazdrlmak istendiinde, gsterici
dizisinin herhangi bir elemanna eriilerek ilgili yaznn balang adresi elde edilir.
/*...*/
if (fp == NULL) {
printf("%s\n", err[5]);
return 5;
}
imdi de aadaki program inceleyin:
#include <stdio.h>
int day_of_week(int day, int month, int year);
char *months[] = {"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"};
char *days[] = {"Sunday",
"Friday", "Saturday" };

"Monday",

"Tuesday", "Wednesday", "Thursday",

void display_date(int day, int mon, int year)


{
printf("%02d ", day);
puts(aylar[mon - 1]);
printf(" %d ", year);
printf("%s", days[day_of_week]);
}
Yukardaki programda ismi months ve days olan char trden gsterici dizileri
tanmlanyor. months dizisinin her bir eleman, bir ay ismini ieren yaznn balang
adresini, days dizisinin her bir eleman ise bir gn ismini ieren yaznn balang adresini
tutuyor. Gsterici dizisinin elemanlarna dizgelerle ilkdeer veriliyor. display_date isimli
ilevin, bir tarihe ilikin gn, ay ve yl deerlerini aldn, ilgili tarihi ekrana yazdrrken,
gsterici dizilerinden faydalandn gryorsunuz.
Belirli sayda bir yaz grubu iinde, bir yaznn var olup olmadnn snanmas amacyla da
char trden gsterici dizileri sklkla kullanlr.
Bir yaznn belirli bir yazyla ayn olup olmad standart strcmp ileviyle snanabilir. Peki,
bir yaznn, bir grup yaz iinde var olup olmad nasl saptanabilir?

302

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Aada tanmlanan get_month ilevi, kendisine balang adresi gnderilen bir yaznn,
ngilizce ay isimlerinden biri olup olmadn snyor. Snad yaz geerli bir ay ismi ise,
ilev bu ayn kanc ay olduu bilgisiyle (1 - 12) geri dnyor. lev, kendisine gnderilen
yaz bir ay ismine karlk gelmiyor ise 0 deeriyle geri dnyor.
#include <stdio.h>
#include <string.h>
#define

SIZE

20

int get_month(const char *str)


{
char *months[] = {"Ocak", "Subat", "Mart", "Nisan", "Mayis", "Haziran",
"Temmuz", "Agustos", "Eylul", "Ekim", "Kasim", "Aralik"};
int k;

for (k = 0; k < 12; ++k)


if (!stricmp(months[k], str))
return k + 1;
return 0;

int main()
{
char s[SIZE];
int result;
printf("bir ay ismi giriniz .");
gets(s);
result = get_month(s);
if (result)
printf("%s yilin %d. ayidir\n", s, result);
else
printf("%s gecerli bir ay ismi degildir\n", s);
return 0;
}
Standart olmayan stricmp ilevinin, iki yaznn karlatrmasn byk harf kk harf
duyarll olmadan yapmas dnda, strcmp ilevinden baka bir fark bulunmadn
anmsayn.
Gsterici dizileri tpk dier diziler gibi, yerel ya da global olabilir. Dizinin global olmas
durumunda, dizi hayata baladnda dizinin elemanlarnn hepsinin iinde 0 deerleri
bulunurken, yerel bir gsterici dizisinin iinde rastgele deerler olur. Dizinin her bir
eleman iinde bir adres bilgisi olduuna gre, atama yaplmam global gsterici
dizilerinin her bir eleman iinde 0 adresi (NULL adresi) bulunur. lkdeer verilmemi
yerel gsterici dizilerinin elemanlar iinde ise rastgele adres deerleri bulunur.
Bir gsterici hatasna neden olmamak iin nce gsterici dizisi elemanlarna gvenli
adresler yerletirmek gerekir. Dizgeler statik mrl varlklar olduklar iin, bir gsterici
dizisinin elemanlarna dizgelerle deer vermek bir gsterici hatasna neden olmaz. Zira
dizgeler, daha nce de belirtildii gibi, nce derleyici tarafndan bellekte gvenli bir
blgeye yerletirilir, daha sonra ise yerletirildikleri bloun balang adresi olarak ele
alnr.
Baz durumlarda, bir gsterici dizisinin son elemanna zellikle NULL adresi atanr. Byle
bir gsterici dizisi, dizi boyutu belirtilmeden ilenebilir. Aadaki rnei inceleyin:

303

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
int main()
{
int k;
char *names[] = {"Ali", "Hasan", "Mehmet", "Sebahat", "Fatma",
"Tuncay", "Deniz", "Kerim", "Necati", NULL};
for (k = 0; names[k] != NULL; ++k)
puts(names[k]);
return 0;
}
Aadaki rnekte, char trden bir gsterici dizisinin elemanlar gsterdikleri yazlarn
byklklerine gre sralanyor:
#include <stdio.h>
#include <string.h>
#define

SIZE

10

int main()
{
int i, k;
char *names[SIZE] = {"Ali", "Hasan", "Mehmet", "Sebahat", "Fatma",
"Tuncay", "Kaan", "Taylan", "Aleyna", "Deniz"};
printf("dizi yazdiriliyor!\n");
for (k = 0; k < SIZE; ++k)
puts(names[k]);
for (k = 0; k < SIZE -1; ++k)
for (i = 0; i < SIZE - 1 -k; ++i)
if (strcmp(names[i], names[i + 1]) > 0) {
char *temp = names[i];
names[i] = names[i + 1];
names[i + 1] = temp;
}
printf("siralanmis dizi yazdiriliyor!\n");
for (k = 0; k < SIZE; ++k)
puts(names[k]);
return 0;
}
Sralama amacyla yine "kabarck sralamas" algoritmas kullanlyor. Gsterici dizisinin
ardk iki elemannn deerleri
strcmp(names[i], names[i + 1]) > 0
koulunun doru olmas durumunda takas ediliyor. Bu, "dizinin i indisli eleman olan
gstericinin gsterdii yaz, i + 1 indisli elemannn gsterdii yazdan daha bykse"
anlamna gelir, deil mi? Eer takas ilemi, daha nce dier trden dizileri sralarken
kullanlan
if (names[i] >

names[i + 1] > 0)

kouluyla yaplsayd ne olurdu?


imdi aadaki kod parasn inceleyin:

304

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
int main()
{
char *names[6] = {"Ali", "Hasan", "Mehmet", "Sebahat", "Fatma" "Tunc"};
int k;
for (k = 0; k < 6; ++k)
puts(names[k]);
return 0;
}
Bcei grebildiniz mi?
Aralarnda boluk karakteri dnda baka bir karakter olmayan dizgelerin, derleyici
tarafndan otomatik olarak birletirilerek tek bir dizge olarak deerlendirildiini
biliyorsunuz. Yukardaki kod parasnda names isimli dizinin elemanlarna ilkdeer
verirken kullanlan "Fatma" dizgesiyle "Tuncay" dizgesi arasnda virgl atomu
konulmam. Bu durumda derleyici bu iki dizgeyi birletirerek tek bir dizge olarak yani
"FatmaTuncay" biiminde ele alr. Bu dizge gsterici dizisinin sondan bir nceki elemanna
atanr. Bu durumda dizinin son elemanna NULL adresi atanm olur deil mi? main ilevi
iindeki for dngs de NULL adresine ular. phesiz bu bir gsterici hatasdr.
Aada bir tamsayy bir yazya dntren syaz isimli bir ilev tanmlanyor. lev
tanmlarnda yer alan gsterici dizilerinin kullanmn inceleyiniz:
#include <stdio.h>
void yuzyaz(unsigned int val)
{
static const char *birler[] = {"", "bir", "iki", "uc", "dort", "bes",
"alti", "yedi", "sekiz", "dokuz"};
static const char *onlar[] = {"", "on", "yirmi", "otuz", "kirk",
"elli", "altmis", "yetmis", "seksen", "doksan"};
int y = val / 100;
int o = val % 100 / 10;
int b = val % 10;

if (y > 1)
printf("%s", birler[y]);
if (y > 0)
printf("yuz");
if (o > 0)
printf("%s", onlar[o]);
if (b > 0)
printf("%s", birler[b]);

void syaz(unsigned int val)


{
int milyar, milyon, bin, yuz;
if (val >= 1000000000) {
milyar = val / 1000000000;
yuzyaz(milyar);
printf("milyar");
}
if (val > 1000000) {
milyon = val % 1000000000 / 1000000;

305

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

yuzyaz(milyon);
if (milyon)
printf("milyon");

if (val > 1000) {


bin = val % 1000000 / 1000;
if (bin >= 1)
yuzyaz(bin);
if (bin > 1)
printf("bin");
}
yuz = val % 1000;
yuzyaz(yuz);

int main()
{
unsigned int val;
printf("bir tamsayi giriniz:");
scanf("%u", &val);
syaz(val);
printf("\n");
}

return 0;

306

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

GSTERCY GSTEREN GSTERCLER


Gsterici deikenler ilerinde adres bilgisi tutan nesnelerdir.
int *p;
gibi bir tanmlamayla ismi p olan, bellekte 2 ya da 4 byte yer kaplayacak olan bir nesne
yaratlm olur. Bu nesne int * trndendir.
p bir nesne olduuna gre, p deikeninin de adresinden sz edilebilir.
p deikeni adres ilecinin terimi olabilir:
&p
ifadesinin tr nedir? Bu ifade int * trnden bir nesnenin adresi olabilecek bir trdendir.
Bu tr C dilinde
(int **)
tr olarak gsterilir. O zaman p gibi bir deikenin adresi bir baka nesnede tutulmak
istenirse, p'nin adresini tutacak nesne int ** trnden olmaldr. Aadaki kod parasn
inceleyin:
void func()
{
int x = 10;
int *p = &x;
int **ptr = &p;
/******/
}
Yukardaki programda int ** trnden olan ptr isimli deikene, int * trnden olan p
deikeninin adresi atanyor. Bunun anlam udur: ptr deikeninin deeri, p deikeninin
adresidir. Baka bir deyile, ptr gstericisi p gstericisini gsterir. Bu durumda
*ptr
ifadesi ptr nesnesinin gsterdii nesnedir. Yani *ptr ifadesi p nesnesinin kendisidir.
*ptr ifadesine yaplan atama aslnda p nesnesini deitirir. Aadaki program inceleyin:
#include <stdio.h>
int main()
{
int x = 10;
int y = 20;
int *p;
int **pp;
printf("x = %d\n", x);
printf("y = %d\n", y);
p = &x;
*p = 100;
pp = &p;
*pp = &y;
*p = 200;
printf("x = %d\n", x);
printf("y = %d\n", y);

307

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

**pp = 2000;
printf("x = %d\n", x);
printf("y = %d\n", y);
return 0;
}
Yukardaki main ilevinde, int trden x deikeninin adresi, p isimli gsterici deikene
atandktan sonra
deyimiyle, p gstericisinin gsterdii nesneye yani x deikenine 100 deeri atanyor.
*p = 100;
pp = &x;
deyimiyle ise p nesnesinin adresi pp isimli gstericiye atanyor. Bu atamadan sonra pp
gstericisi p gstericisini gsterir.
*pp = &y;
deyimi ile pp gstericisinin gsterdii nesneye yani p deikenine bu kez y deikeninin
adresi atanyor. Bu atamadan sonra yrtlecek
*p = 200;
atamas ile artk p gstericisinin gsterdii nesneye yani y deikenine 200 deeri atanr.
imdi de aadaki deyimi inceleyin:
**pp = 2000;
erik ilecinin, ile ncelik tablosunun ikinci dzeyinde yer aldn ve sadan sola
ncelik ynne sahip olduunu biliyorsunuz.
Bu durumda nce *pp ifadesi ile pp gstericisinin gsterdii nesneye yani p nesnesine
eriilir. Daha sonra *(*pp) ifadesiyle de pp gstericisinin gsterdii nesnenin gsterdii
nesneye, yani p nesnesinin gsterdii nesneye, yani y deikenine ulalr. Deyimin
yrtlmesiyle y deikenine 2000 deeri atanm olur.
**pp ifadesi, pp'nin gsterdii nesnenin gsterdii nesneye, yani y nesnesine karlk
gelir.

Yerel Bir Gsterici Deikenin Deerini Deitiren levler

Yerel bir nesnenin deerini deitirecek bir ilev, yerel nesnenin adresi ile arlmaldr.
Yerel bir gsterici deikenin deerini deitirecek bir ilev de, yerel gstericinin deerini
deil adresini almaldr. Aadaki rnei inceleyin:
void swap_ptr(int **p1, int **p2)
{
int *temp = *p1;
*p1 = *p2;
*p2 = temp;
}
Yukardaki programda int * trnden iki nesnenin deerini takas etmek amacyla
swap_ptr isimli bir ilev tanmlanyor. levin int ** trnden iki parametresi olduunu
gryorsunuz. Bu ilev phesiz deerlerini takas edecei nesnelerin adresleri ile
arlmaldr:

308

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
int main()
{
int x = 10;
int y = 20;
int *p = &x;
int *q = &y;
printf("*p =
printf("*q =
swap_ptr(&p,
printf("*p =
printf("*q =
}

%d\n",
%d\n",
&q);
%d\n",
%d\n",

*p);
*q);
*p);
*q);

return 0;

main ilevi iinde int trden x ve y isimli deikenler tanmlanyor. Daha sonra
tanmlanan p gsterici deikeni x nesnesini, q gsterici deikeni ise y deikenini
gsteriyor.
Daha sonra arlan swap_ptr ilevine p ve q gstericilerinin adresleri gnderiliyor. leve
yaplan ardan sonra, p gstericisi y deikenini, q gstericisi ise x deikenini gsterir.
imdi de aadaki ilevi inceleyin:
void ppswap(int **p1, int **p2)
{
int temp = **p1;
**p1 = **p2;
**p2 = temp;
}
ppswap ilevi hangi nesnelerin deerlerini takas ediyor?

Bir Gsterici Dizisi zerinde lem Yapan levler

Bir dizi zerinde ilem yapan ilevin dizinin balang adresi ile dizinin boyutunu almas
gerektiini biliyorsunuz.
int trden bir dizi ile ilgili ilem yapan bir ilevin bildirimi aadaki gibi olabilir:
void process_array(int *, int size);
Byle bir ilev dizinin ilk elemannn adresi ve dizinin boyutu ile arlr, deil mi?
int a[10];
gibi bir dizi sz konusu olduunda, dizi ismi olan a, ileme sokulduunda otomatik olarak
bu dizinin adresine dntrlr.
Yani derleyici asndan bakldnda a ifadesi &a[0] ifadesine edeerdir.
Bu ilev
process_array(a, 10);
biiminde arlabilir.
Bu kez elemanlar char * trden olan bir dizi tanmlanm olsun:
char *a[100];

309

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yine a ifadesi bir ileme sokulduunda, bu dizinin ilk eleman olan nesnenin adresine,
yazni dizinin balang adresine dntrlr.
Bu dizinin ilk eleman olan nesne char * trnden olduuna gre, bu nesnenin adresi char
** trndendir. Byle bir dizi zerinde ilem yapacak ilev, bu dizinin balang adresi ile
dizinin boyutunu alacana gre, aadaki gibi bildirilmelidir:
void process_array(char **parray, int size);
Bu ilev
process_array(a, 10);
biiminde arlabilir.
imdi de aadaki program inceleyin:
#include <stdio.h>
#include <string.h>
void swap_ptr(char **p1, char **p2)
{
char *temp = *p1;
*p1 = *p2;
*p2 = temp;
}
void display_str_array(char **p, int size)
{
int k;

for (k = 0; k < size; ++k)


printf("%s ", p[k]);
printf("\n");

void sort_str_array(char **p, int size)


{
int i, k;

for (k = 0; k < size - 1; ++k)


for (i = 0; i < size - 1 - k; ++i)
if (strcmp(p[i], p[i + 1]) > 0)
swap_ptr(p + i, p + i + 1);

int main()
{
char *names[10] = {"Eda", "Abdurrahman", "Berk", "Zarife", "Yusuf",
"Levent", "Sezgi", "Sukufe", "Ufuk", "Cansu"};
display_str_array(names, 10);
sort_str_array(names, 10);
getchar();
display_str_array(names, 10);
return 0;
}

310

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

OK BOYUTLU DZLER
C dilinde iki ya da daha ok boyuta sahip diziler tanmlanabilir:
int a[5][10][20];
Yukardaki bildirimle a dizisi 3 boyutlu bir dizidir.
int m[5][10];
m dizisi 2 boyutlu bir dizidir.
Uygulamalarda daha ok kullanlan 2 boyutlu dizilerdir. 2 boyutlu diziler matris olarak da
isimlendirilir.

Matrisler

C'de iki boyutlu bir dizi aslnda belirli bir boyuttaki tek boyutlu dizilerin dizisi olarak ele
alnr:
int a[5][10];
a dizisi her eleman 10 elemanl int trden bir dizi olan 5 elemanl bir dizidir. Yani a
dizisinin gerekte boyutu 5' tir. kinci keli ayra iinde yer alan 10 ifadesi a dizisinin
elemanlar olan dizilerin boyutudur.
Bu dizi tm dier diziler gibi bellekte bitiik bir blok halinde bulunur. Yani derleyici byle
bir dizi iin bellekte 50 x sizeof(int) byte byklnde bir blok ayarlar.
ok boyutlu bir dizinin elemanlaryla, bu dizinin problem dzlemindeki karl olan
matrisin elemanlarn birbirlerine kartrmak, sk yaplan hatalardandr.
5 x 10 boyutunda bir matrisin 50 eleman vardr. Ancak yukardaki a dizisinin yalnzca 5
eleman vardr.
Yukardaki dizide yer alan toplam 50 tane int trden nesnenin her birine nasl ulalabilir?
Bunun iin keli ayra ileci dizi ismiyle birlikte 2 kez kullanlabilir:
Aadaki program inceleyin. Bu programda bir matriste yer alan tm elemanlara 0-100
aralnda rastgele deerler veriliyor. Daha sonra matriste yer alan tm elemanlarn
deeri ekrana yazdrlyor:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define
#define

ROW
COL

5
10

int main()
{
int a[ROW][COL];
int i, k;
srand(time(0));
for (i = 0; i < ROW; ++i)
for (k = 0; k < COL; ++k)
a[i][k] = rand() % 100;
/********/
311

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

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


for (k = 0; k < COL; ++k)
printf("%2d ", a[i][k]);
printf("\n");
}
}

return 0;

Yukardaki kodu inceleyin. a dizisi 10 elemanl int trden dizilerin oluturduu bir dizidir.
Yani a[0] bu dizilerden ilkine ve a[4] bu dizilerden sonuncusuna karlk gelir.
a[0] bu dizilerden ilkine karlk geldiine gre a dizisinin ilk eleman olan 10 elemanl
dizinin rnein 5 indisli elemanna
a[0][5]
biiminde ulalabilir, deil mi? Keli ayra ilecinin birinci ncelik seviyesinde ve soldan
saa doru ncelik ynne sahip bir ile olduunu anmsayn.
Byle bir iki boyutlu diziye, problem dzlemindeki karl olarak, yani bir matris olarak
bakldnda, bu matriste yer alan ilk eleman
a[0][0]
nesnesidir. Bu nesne matrisin 1. satr ve 1. stununda yer alan nesnedir. Matrisin son
eleman ise
a[4][9]
nesnesidir. Bu nesne matrisin 5. satr ve 10. stununda yer alan nesnedir. Matristeki ilk
nesnenin adresi int trden bir gstericiye atanp bu gsterici srekli artrlrsa, matristeki
tm elemanlarn adresleri elde edilerek son elemann adresine ulalabilir. imdi
yukardaki rnee bir ekleme yapalm:
int main()
{
int a[ROW][COL];
int i, k;
int *ptr;
srand(time(0));
for (i = 0; i < ROW; ++i)
for (k = 0; k < COL; ++k)
a[i][k] = rand() % 100;
/********/
for (i = 0; i < ROW; ++i) {
for (k = 0; k < COL; ++k)
printf("%2d ", a[i][k]);
printf("\n");
}
printf("***********************************************\n");
ptr = &a[0][0];

312

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

i = ROW * COL;
while (i--)
printf("%2d ", *ptr++);
printf("\n");
}

return 0;

Daha nce yazlan main ilevine bir eklemenin yapldn gryorsunuz.


ptr = &a[0][0];
deyimi ile
int * trnden ptr nesnesine matris iinde yer alan ilk int trden nesnenin adresi atanr. i
deikenine ROW * COL ifadesinin deeri, yani matriste yer alan toplam eleman says
atanmtr.
Bu durumda while (i--) dngs matrisin eleman says kadar dner, deil mi? Dngnn
gvdesinde yer alan printf ars ile dngnn her turunda *ptr nesnesinin deeri
yazdrlm ve daha sonra sonek konumunda olan ++ ileciyle gstericinin deeri 1
artrlm yani gstericinin bellekte bir sonraki int trden nesneyi gstermesi salanmtr.
Bylece matris iinde yer alan btn deerler ekrana yazdrlmtr.
Buradan u anlalmaldr: ki boyutlu dizinin elemanlar aslnda bellee ardl olarak
yerletirilen tek boyutlu dizilerdir.

ki Boyutlu Dizilerin levlere Geirilmesi

Aslnda iki boyutlu bir dizinin ileve geirilmesi tek boyutlu dizilerin ileve
geirilmesinden farkl deildir. Bir diziyi ileve geirmek iin dizinin ilk elemannn adresi
ve dizinin boyutu ileve gnderilir, deil mi?
Peki yukardaki rnekte yer alan a gibi bir dizinin ilk eleman nedir? Bu dizinin ilk eleman
a[0]'dr. Ve bu 10 elemanl int trden bir dizidir. imdi bu elemann adresinin alndn
dnelim:
&a[0]
Bu ifadenin tr nedir? C diline yeni balayanlar byle bir ifadenin trnn (int **) tr
olmas gerektiini dnrler. Oysa bu ifadenin tr daha nce karlamadmz bir
trdr:
10 elemanl int trden bir dizinin adresi olabilecek bir tr!
Bu tr biligisi C dilinde yle ifade edilir:
int (*)[10];
Yani a dizisinin ilk eleman bu trden bir gstericiye atanabilir:
int (*ptr)[10] = &a[0];
Bir dizinin ismi bir ifade iinde ileme sokulduunda otomatik olarak dizinin ilk elemann
adresine dntrlr, deil mi? O zaman &a[0] ifadesi yerine dorudan a ifadesi de
yazlabilir:
int (*ptr)[10] = a;
Evet, a ifadesinin tr int ** deil, int (*)[10] trdr.

313

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Bu durum yle de ifade edilebilir: ptr int trden 10 elemanl bir diziyi gsteren
gstericidir. ptr herhangi bir boyuttaki int trden bir diziyi deil, yalnzca 10 elemanl int
trden bir diziyi gsterebilir. ptr gstericisi rnein ++ ileci ile 1 artrlrsa bellekte yer
alan bir sonraki 10 elemanl int trden diziyi gsterir. Yani
ptr + 1
adresinin saysal bileeni ptr adresinin saysal bileeninden sizeof(int) * 10 kadar daha
byktr.
ptr + 1 ifadesi iki boyutlu a dizisinin ikinci eleman olan 10 elemanl int trden dizinin
adresine karlk gelir. Bu durumda
*(ptr + 1)
ifadesi aslnda a[1] dizisidir.
phesiz *(ptr + 1) ifadesi yerine ptr[1] ifadesi de kullanlabilir. Bu durumda bu gsterici
yardmyla iki boyutlu dizinin tm elemanlarna bir dng ile ulalabilir:
for (k = 0; k < ROW; ++k)
ptr[k]
gibi bir dng deyimi ile dngnn her turunda matrisin bir satrna, yani iki boyutlu
dizinin bir eleman olan COL uzunluundaki dizilere ulalr.
Bu durumda 2 boyutlu bir dizi yani bir matris zerinde ilem yapacak bir ilevin
parametre deikeni byle bir gsterici olabilir. levin dier parametresi de dizinin
boyutunu alabilir. Aadaki program inceleyin:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define
#define

ROW
COL

5
10

void fill_matrix(int (*ptr)[COL], int size)


{
int i, k;
for (i = 0; i < size; ++i)
for (k = 0; k < COL; ++k)
ptr[i][k] = rand() % 100;
}
void display_matrix(int (*ptr)[COL], int size)
{
int i, k;

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


for (k = 0; k < COL; ++k)
printf("%2d ", ptr[i][k]);
printf("\n");
}

314

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

int main()
{
int a[ROW][COL];
srand(time(0));
fill_matrix(a, ROW);
display_matrix(a, ROW);
}

return 0;

int (*ptr)[10] gibi bir gsterici bir ilevin parametre deikeni olarak kullanldnda int
ptr[][10] biiminde de yazlabilir. Yani aadaki iki bildirim birbirine edeerdir:
void fill_matrix(int (*ptr)[10], int size);
void fill_matrix(int ptr[][10], int size);
Hatta istenirse ilk keli ayra iine de bir tamsay yazlabilir. Ancak derleyici asndan bu
tamsaynn bir nemi yoktur. Baz programclar yalnzca okunabilirlik asndan dizinin
boyutunu ilk keli ayralarn iine yazarlar. Yukardaki bildirim yle de yaplabilirdi:
void fill_matrix(int ptr[5][10], int size);
Matrisleri ileve geirmenin bir baka yolu da matristeki ilk elemann adresini, matrisin
satr ve stun saysn ileve geirmek olabilir. Yukarda yazdmz ilevleri imdi
deitiriyoruz:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define
#define

ROW
COL

5
10

void fill_matrix(int *ptr, int rowsize, int colsize)


{
int i, k;
for (i = 0; i < rowsize; ++i)
for (k = 0; k < colsize; ++k)
ptr[i + k] = rand() % 100;
}
void display_matrix(int *ptr, int rowsize, int colsize)
{
int i, k;
for (i = 0; i < rowsize; ++i) {
for (k = 0; k < colsize; ++k)
printf("%d ", ptr[i + k]);
printf("\n");
}
}
int main()
{
int a[ROW][COL];
srand(time(0));

315

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

fill_matrix(&a[0][0], ROW, COL);


display_matrix(&a[0][0], ROW, COL);
}

return 0;

Bu kez ilevler matristeki ilk elemann adresini, matrisin satr ve stun saysn alarak
matristeki tm elemanlara, bunlarn bellekte bitiik olarak yer ald bilgisinden hareketle
gsterici aritmetiiyle ulayor.
Tabi bu ilevlere dizi ismi de argman olarak geilebilir. Bu durumda tr dntrme
ileci kullanlmaldr:
void fill_matrix((int *)a, ROW, COL);
void display_matrix((int *)a, ROW, COL);

Matris Eleman Olan Dizilerin lk Elemanlarnn Adresi

Dizi isimlerinin derleyici tarafndan otomatik olarak dizilerin ilk elemannn adresine
dntrldn biliyorsunuz. Benzer biimde iki boyutlu bir dizinin eleman olan tek
boyutlu bir diziye keli ayra ileci ile ulaldnda, bu ifade otomatik olarak bu tek
boyutlu dizinin ilk elemannn adresine dntrlr. Aadaki rnei inceleyin:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define
#define

ROW
COL

5
10

void fill_array(int *ptr, int size)


{
int k;
for (k = 0; k < size; ++k)
ptr[k] = rand() % 100;
}
void display_array(const int *ptr, int size)
{
int k;
for (k = 0; k < size; ++k)
printf("%2d ", ptr[k]);
printf("\n");
}
Bu kez rnekte yer alan display_array isimli ilev, balang adresini ve boyutunu ald
int trden bir dizinin elemanlarnn deerlerini ekrana yazdrrken, fill_array ilevi ise
balang adresini ve boyutunun ald dizinin elemanlarna rastgele deerler atyor.
int main()
{
int a[ROW][COL];
int i;
srand(time(0));
for (i = 0; i < ROW; ++i)
fill_array(a[i], COL);

316

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

/******/
for (i = 0; i < ROW; ++i)
display_array(a[i], COL);
}

return 0;

main ilevi iinde yer alan for dng deyimini inceleyelim:


for (i = 0; i < ROW; ++i)
fill_array(a[i], COL);
a[i] ifadesi dngnn her turunda a dizisinin eleman olan COL boyutundaki tek boyutlu
dizilere karlk gelir deil mi? Bu ifade ileme sokulduunda derleyici tarafndan otomatik
olarak bu dizinin ilk elemannn adresine dntrlr.
a[0] ifadesi otomatik olarak &a[0][0] ifadesine dntrlr. fill_array isimli ileve ikinci
argman olarak da COL ifadesi gnderilir. nk COL ifadesi adresi a[i] olan dizinin
boyutunu gsterir.
Bir dizinin tanm srasnda dizi boyutunu gsteren ifadelerin deimez ifadesi (constant
expresion) olmas gerektiini biliyorsunuz. Ayn koul ok boyutlu diziler iin de geerlidir.
Eer bir matrisin boyutlar derleme zamannda deil de programn alma zamannda
belli oluyorsa dinamik bellek ynetimi kullanlmaldr. Bu konudaki rnekler "Dinamik
Belek Ynetimi" blmnde ele alnmaktadr.

ki Boyutlu Dizilere lkdeer Verilmesi

ki boyutlu dizilere de ilkdeer verilebilir. Verilen ilkdeerler srasyla iki boyutlu dizinin
eleman olan tek boyutlu dizilerin elemanlarna atanr.
#include <stdio.h>
int main()
{
int a[3][5] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
int i, k;

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


for (k = 0; k < 5; ++k)
printf("%2d ", a[i][k]);
printf("\n");
}
return 0;

stenirse ilkdeerleri ieren bloun iinde isel bloklar kullanlarak, eleman olan dizilerin
belirli sayda elemanna ilkdeer verilebilir. lk deer verilmeyen elemanlara otomatik
olarak 0 deeri atanr. Aadaki rnei de derleyerek altrn:
#include <stdio.h>
int main()
{
int a[3][5] = { {1, 2}, {3, 4, 5}, {6, 7, 8, 9}};
int i, k;
for (i = 0; i < 3; ++i) {
for (k = 0; k < 5; ++k)

317

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

printf("%2d ", a[i][k]);


printf("\n");
}

}
return 0;

char Trden ki Boyutlu Diziler

Nasl bir yaz char trden bir dizinin iinde tutulabiliyor ise, mantksal bir iliki iindeki n
tane yaz iki boyutlu bir dizi iinde tutulabilir:
char words[10][50];
Yukarda tanmlanan words isimli dizinin 10 eleman vardr. words isimli dizinin her bir
eleman char trden 50 elemanl dizidir. words dizisinin iinde uzunluu 49 karakteri
gemeyen, 10 tane yaz tutulabilir.
words[3]
Bu yazlardan drdncsnn adresi
words[6][2]
Bu yazlardan yedincisinin nc karakteridir.
Aadaki program inceleyin:
#include <stdio.h>
#include <string.h>
#define

ARRAY_SIZE

10

char *name_array[ARRAY_SIZE] = {"Ali", "Veli", "Hasan", "Necati", "Deniz",


"Kaan", "Selami","Salah", "Nejla", "Figen"};
int main()
{
char names[ARRAY_SIZE][20];
int k;
for (k = 0; k < ARRAY_SIZE; ++k)
strcpy(names[k], name_array[k]);
for (k = 0; k < ARRAY_SIZE; ++k)
printf("(%s) ", names[k]);
printf("\n");
for (k = 0; k < ARRAY_SIZE; ++k)
strrev(names[k]);
for (k = 0; k < ARRAY_SIZE; ++k)
printf("(%s) ", names[k]);
printf("\n");
}

return 0;

main ilevi iinde iki boyutlu names isimli bir dizi tanmlanyor.
char names[ARRAY_SIZE][20];

318

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Bu dizi iinde uzunluu en fazla 19 karakter olabilecek ARRAY_SIZE sayda isim


tutulabilir, deil mi?
for (k = 0; k < ARRAY_SIZE; ++k)
strcpy(names[k], name_array[k]);
dng deyimiyle name_array isimli bir gsterici dizisinin elemanlarnn gsterdii isimler,
iki boyutlu names dizisinin eleman olan char trden dizilere standart strcpy ileviyle
kopyalanyor. Aadaki dng deyimiyle her bir isim ekrana yazdrlyor:
for (k = 0; k < ARRAY_SIZE; ++k)
printf("(%s) ", names[k]);
Aadaki dng deyimi ile standart olmayan strrev isimli ileve yaplan arlarla, iki
boyutlu dizi iinde tutulan isimlerin hepsi ters evriliyor:
for (k = 0; k < ARRAY_SIZE; ++k)
strrev(names[k]);

char Trden ki Boyutlu Dizilere lkdeer Verilmesi

char trden bir diziye ift trnak iinde yer alan karakterlerle ilkdeer verilebileceine
gre iki boyutlu bir dizinin elemanlar olan char trden tek boyutlu dizinin elemanlarna
da benzer ekilde ilkdeer verilebilir:
char names[5][10] = {"Ali", "Veli", "Hasan", "Tuncay", "Deniz"};
Yukarda, names isimli iki boyutlu dizinin eleman olan 10 elemanl char trden dizilere,
ift trnak iinde yer alan yazlarla ilkdeer veriliyor.
imdi de iki boyutlu char trden bir dizi zerinde ilem yapacak baz ilevler
tanmlayalm:
#include <stdio.h>
#include <string.h>
#define

ARRAY_SIZE

20

void swap_str(char *p1, char *p2)


{
char temp[20];
strcpy(temp, p1);
strcpy(p1, p2);
strcpy(p2, temp);
}
void sort_names(char ptr[][20], int size)
{
int i, k;
for (i = 0; i < size - 1; ++i)
for (k = 0; k < size - 1 - i; ++k)
if (strcmp(ptr[k], ptr[k + 1]) > 0)
swap_str(ptr[k], ptr[k + 1]);
}
void display_names(const char ptr[][20], int size)
{
int i;
for (i = 0; i < size; ++i)

319

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

printf("(%s) ", ptr[i]);


printf("\n");
}
int main()
{
char names[ARRAY_SIZE][20] = {"Ali", "Veli", "Hasan", "Necati",
"Deniz", "Kaan", "Selami","Salah", "Nejla", "Huseyin", "Derya", "Funda",
"Kemal", "Burak", "Burcu", "Ozlem", "Nuri", "Metin", "Guray", "Anil"};
display_names(names, ARRAY_SIZE);
sort_names(names, ARRAY_SIZE);
printf("***********************************\n");
display_names(names, ARRAY_SIZE);
}

return 0;

Yukarda tanmlanan ilevlerden swap_str ilevi adreslerini ald iki yazy takas ediyor.
display_names isimli ilev ise balang adresini ve boyutunu ald iki boyutlu dizide yer
alan isimleri ekrana yazdryor.
sort_names isimli ilev ise balang adresini ve boyutunu ald iki boyutlu dizi iinde
tutulan isimleri kkten bye doru sralyor.

char * Trden Diziyle char Trden ki Boyutlu Dizi Arasndaki


Farklar

Mantksal iliki iinde n tane yaz, bir gsterici dizisi yardmyla tutulabilecei gibi iki
boyutlu bir dizi iinde de tutulabilir:
char *pnames[10] = {"Ali", "Veli", "Hasan", "Deniz", "Ferda", "Murat",
"Ayca", "Erdem", "Kaan", "Gurbuz"};
char names[10][20] = {"Ali", "Veli", "Hasan", "Deniz", "Ferda", "Murat",
"Ayca", "Erdem", "Kaan", "Gurbuz"};
Elemanlar dizgeleri gsteren bir gsterici dizisinin elemanlar, yalnzca okuma amacyla
kullanlabilecek yazlarn balang adreslerini tutar. Dizgelerin yalnzca okuma amacyla
kullanlabilecek yazlar olduunu anmsamalsnz.
Yukardaki rnekte, pnames dizisinin eleman olan gstericilerin gsterdii yazlar
zerinde deiiklik yapmak, doru deildir. Ancak names dizisi iinde yer alan isimler
istenirse deitirilebilir. Aadaki main ilevini inceleyin:
#include <string.h>
int main()
{
int k;
for (k = 0; k < 10; ++k) {
strrev(pnames[k]);
strrev(names[k]);
}
}

/* Yanl */
/* Yanl deil*/

return 0;

320

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

exit, abort atexit levleri

Bir C programnn almas main ilevinden balar, main ilevinin sonunda, ya da bu


ilevin geri dn deeri retmesiyle, sonlanr. Program, eer bir baka ilevin
altrlmas srasnda sonlandrlmak istenirse, standart exit ya da abort ilevleri
arlabilir.

exit levi

Standart bu ilev stdlib.h balk dosyas iinde bildirilmitir:


void exit(int status);
lev, altrlmakta olan program sonlandrmadan nce aadaki temizlik ilerini yapar:
i) atexit ileviyle daha nce kayt edilmi ilevleri kayt edilmelerine gre ters sra iinde
arr.
ii) Yazma amal alm tm dosyalarn tampon alanlarn (buffer) boaltr (flush). Ak
durumda olan tm dosyalar kapatr.
iii) tmpfile ileviyle alm olan dosyalar siler.
iv) Kontrolu, programn altrld sisteme, baar durumunu ileten bir bilgiyle geri verir.
leve gnderilen deer 0 ya da EXIT_SUCCESS simgesel deimezi ise, ilev, sisteme
programn baar nedeniyle sonladrld bilgisini iletir. leve gnderilen argman 1 ya
da EXIT_FAILURE simgesel deimezi ise, ilev, sisteme programn baarszlk nedeniyle
sonlandrld bilgisini iletir.

abort levi

Standart bu ilev stdlib.h balk dosyas iinde bildirilmitir:


void abort(void);
lev bir C programn olaand biimde sonlandrmak amacyla arlr. Bir C program
abort ilevine yaplan ar ile sonlandrldnda, atexit ileviyle daha nce kayt edilmi
ilevler arlmaz. abort ars ile programn sonlanmasndan nce baz temizlik
ilemlerinin yaplp yaplmayaca derleyicinin seimindedir.
Standart assert makrosu iinde de bu ilev arlr.
atexit levi
Standart bu ilevin bildirimi yine stdlib.h balk dosyas iindedir.
int atexit (void (*func)(void));
atexit ilevi ile, program sonlandnda ya da exit ilevi arldnda, arlmas istenen
bir ilev kaydedilir. Program normal d yollarla, rnein abort ya da raise ileviyle
sonlandrldnda, kaydedilen ilevler arlmaz.
atexit ileviyle en az 32 ilev kaydedilebilir.
levin parametresi, kaydedilecek ilevin adresidir. levin geri dn deeri ilemin
baar durumunu iletir. 0 geri dn deeri, ilemin baarsn, 0 d bir deer ilemin
baarszln gsterir.
Kaydedilen bir ilevi kayttan karmann bir yolu yoktur.
Kaydedilen ilevler kaydedildikleri sra ile ters srada arlrlar. Bir ilev birden fazla kez
kaydedilebilir. Bu durumda birden fazla kez altrlr.

321

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

DNAMK BELLEK YNETM


Dinamik Bellek Ynetimi Nedir

altrlabilen bir program bir bellek alann kullanr. Nesneler programn kulland bellek
alanndaki bloklardr. Bir ya da birden fazla nesnenin programn alma zamannda
kaplayaca yer iki ayr biimde elde edilebilir:
1. Nesne(ler) iin derleyici derleme zamannda bellekte bir yer ayarlar.
2. Nesne(ler) iin yer programn alma zamannda elde edilir.
Programn alma zaman srasnda belli bir byklkte bitiik (contigous) bir bellek
alannn alan program tarafndan ayrlmasna , byle bir alann istenildii zaman
sisteme geri verilmesine olanak salayan yntemlere "dinamik bellek ynetimi" (dynamic
memory management) denir.
C dilinde bir deiken ya da bir dizi tanmland zaman, bu deiken ya da dizinin
programn alma zamannda kaplayaca yer, derleme zamannda derleyici tarafndan
ayrlr:
int a[100];
Derleme srasnda yukardaki gibi bir dizi tanm ile karlaan derleyici bellekte -eer
kullanlan sistemde int tr uzunluunun 2 byte olduu varsaylrsa- toplam 200 byte yer
ayrr. Programn almas srasnda bir dizinin uzunluunu deitirmek mmkn deildir.
Eer bu dizi yerel ise otomatik mrldr. Yani iinde tanmlanm olduu bloun
kodunun yrtlmesi sresince hayatn srdrr. Dizi global ise statik mrldr. Yani
dizi, programn alma sresi boyunca bellekteki yerini korur.
Dinamik bellek ynetimi aralar kullanlarak bir ya da birden fazla nesnenin programn
alma zamannda kaplayaca yerin elde edilmesi derleme zamanndan, alma
zamanna geciktirilebilir.
Kullanlacak bellek blounun elde edilmesi neden derleme zamanndan alma zamanna
kaydrlsn? Bunun nemli baz nedenleri vardr. lerleyen sayfalarda bu nedenlerin
ouna deinilecek.
Bellek alannn programn alma zamannda elde edilmesinin en nemli nedenlerinden
biri gereksinim duyulan bellek blounun byklnn programn alma zamannda
belli olmasdr.
Dizi tanmlamalarnda dizi boyutunu gsteren ifade yani keli ayracn iindeki ifade,
deimez ifadesi olmaldr. Bu ifade deiken ieremez. nk derleyicinin dizi iin
bellekte yer ayrabilmesi iin, dizi boyutunu derleme zamannda bilmesi gerekir. Oysa
birok uygulamada kullanlmas gereken dizinin boyutu programn alma zamannda
belirlenir. Bir dizindeki dosyalarn isimlerinin kkten bye doru sralanmak amacyla
geici olarak bir dizide saklanmas gerektiini dnn. Bu amala kullanlacak dizinin
boyutu ne olmaldr? Bu balangta belli deildir. nk dizin iinde ka dosya olduu
belli deildir. Bu tip durumlara zellikle veri taban uygulamalarnda sk rastlanr. Baz
uygulamalarda dizilerin gerek uzunluu programn almas srasnda, ancak birtakm
olaylar sonucunda kesin olarak belirlenebilir. Bu durumda dizilerle alan programc
herhangi bir gsterici hatasyla karlamamak iin dizileri en kt olasl gz nnde
bulundurarak mmkn olduunca byk tanmlamak zorundadr. Bu da bellein verimsiz
kullanlmas anlamna gelir. stelik tanmlanan diziler yerel ise tanmlandklar bloun
sonuna kadar, tanmlanan diziler global ise programn almasnn sonuna kadar bellekte
tutulur. Oysa dizi ile ilgili ilem biter bitmez, dizi iin ayrlan bellek blgesinin boaltlmas
verimli bellek kullanm iin gereklidir.
Bellein kontrolu iletim sistemindedir. letim sistemlerinin baka bir amala
kullanlmayan bir bellek alann kullanma sunmasna yarayan sistem ilevleri vardr.
phesiz bu ilevler dorudan arlabilir. Ancak uygulamalarda ounlukla standart C

323

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

ilevleri kullanlr.Yazlan kaynak kodun tanabilirlii asndan standart C ilevleri tercih


edilmelidir.
Aada dinamik bellek ynetiminde kullanlan standart C ilevlerini tek tek ayrntl olarak
inceleniyor:

malloc ilevi
malloc ilevi programn alma zaman srasnda bellekten dinamik bir blok elde etmek
iin kullanlr. levin stdlib.h balk dosyas iindeki bildirimi aadaki gibidir:
void *malloc(size_t nbyte);
size_t trnn, unsigned int ya da unsigned long trlerinden birinin typedef ismi
olduunu biliyorsunuz.
lev, elde edilmek istenen bloun byte olarak uzunluunu alr. Ayrlan alann bitiik
(contiguous) olmas gvence altna alnmtr. malloc ilevinin geri dn deeri elde
edilen bellek blounun balang adresidir. Bu adres void trden olduu iin, herhangi bir
trden gstericiye sorunsuz bir ekilde atanabilir. Bu adres herhangi bir trden
gstericiye atand zaman artk elde edilen blok, balang adresini tutan gsterici
yardmyla bir nesne ya da bir dizi gibi kullanlabilir. malloc ilevinin istenilen blou
ayrmas gvence altnda deildir. malloc ilevi birok nedenden dolay baarsz olabilir.
Bellekte elde edilmek istenen alan kadar bo bellek alannn bulunmamas sk grlen bir
baarszlk nedenidir.
malloc ilevi baarsz olduunda NULL adresine geri dner. lev arsnn baars
mutlaka snanmaldr. malloc ilevi ile bellekte bir blok elde edilmesine ilikin aada bir
rnek veriliyor:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *pd;
int k, n;
srand(time(0));
n = rand() % 100 + 10;
pd = (int *) malloc(n * sizeof(int));
if (pd == NULL) {
printf("cannot allocate memory\n");
exit(EXIT_FAILURE);
}
printf("rastgele %d sayi\n", n);
for (k = 0; k < n; ++k) {
pd[k] = rand() % 100;
printf("%d ", pd[k]);
}
/***/
}
Yukardaki main ilevinde, n deikeninin deeri programn alma zamannda elde
standart rand ilevine yaplan ar ile rastgele olarak elde ediliyor. Daha sonra standart
malloc ileviyle n tane int trden nesnenin sabilecei kadar byklkte bir bellek blou
elde ediliyor.

324

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

malloc ilevinin baars bir if deyimiyle snanyor. Baarszlk durumunda, yani malloc
ilevinin geri dn deerinin NULL adresi olmas durumunda standart exit ilevi
arlarak program sonlandrlyor.
Daha sonra elde edilen dinamik blok int trden bir dizi olarak kullanlyor. Dinamik dizinin
elemanlarna 0 - 100 aralnda rastgele deerler atanyor.
Kaynak kodun tanabilirlii asndan kullanlacak bellek blounun bykl sizeof
ileciyle elde edilmelidir.
phesiz, malloc ilevi baarsz olduunda program sonlandrmak zorunlu deildir.
Atama ile snama bir defada da yaplabilir.
if ((pd = (int *) malloc(n * sizeof(int)) ==
printf("cannot allocate memory\n");
exit(EXIT_FAILURE);
}

NULL) {

malloc ilevinin baars mutlaka snanmaldr. levin baarsz olmas durumunda, geri
dn deeri olan adresten okuma ya da yazma yaplmas, NULL adresinin ieriinin
alnmasna neden olur. Bu da bir gsterici hatasdr.
Programclar ou kez, kk miktarlarda ok sayda bloun ayrlmas durumunda,
snamay gereksiz bulma eilimindedir. Oysa snama ileminden vazgemek yerine daha
kolaylatrc yntemler denenmelidir. rnein p1, p2, p3, p4, p5 gibi 5 ayr gsterici
deikenin her biri iin n byte dinamik alan elde edilmek istensin. Bu durumda snama
mantksal ileler ile tek bir if deyimi ile yaplabilir.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *p1, *p2, *p3, *p4, *p5;
p1
p2
p3
p4
p5

=
=
=
=
=

(char
(char
(char
(char
(char

*)malloc(n);
*)malloc(n);
*)malloc(n);
*)malloc(n);
*)malloc(n);

if (!(p1 && p2 && p3 && p4 && p5)) {


printf("cannot allocate memory!..\n");
exit(EXIT_FAILURE);
}
/*....*/

malloc arlarndan herhangi biri baarsz olursa


!(p1 && p2 && p3 && p4 && p5)
ifadesi "doru" olarak yorumlanacandan if deyiminin doru ksm yaplr.
Bazen de malloc ilevi programc tarafndan tanmlanan baka bir ilev ile sarmalanr:
#include <stdio.h>
#include <stdlib.h>
void *cmalloc(size_t n)
{
void *pd = malloc(n);

325

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

if (!pd) {
printf("cannot allocate memory!..\n");
exit(EXIT_FAILURE);
}
return pd;
}
Yukarda tanmlanan cmalloc isimli ilevin parametrik yaps malloc ileviyle ayn
olduunu gryorsunuz. lev malloc ilevinden farkl olarak, baarszlk durumunda
program sonlandryor. malloc ile yaplacak bir dinamik blok elde etme giriiminin
baarsz olmas durmunda program bir hata iletisi verilerek sonlandrlacaksa, kaynak
kodun srekli yinelenmesi yerine, cmalloc ilevi arlabilir.
malloc ilevinin geri dn deeri void trden bir adres olduu iin, bu adres sorunsuzca
herhangi bir trden bir gsterici deikene atanabilir. Ancak okunabilirlik asndan malloc
ilevinin geri dn deeri olan adresin, tr dntrme ileci yardmyla, kullanlacak
gsterici deikenin trne dntrlmesi nerilir. Bylece malloc ilevi ile elde edilen
bloun hangi trden nesne ya da nesnelermi gibi kullanlaca bilgisi kodu okuyana
verilmi olur.
C dilinin standartlatrlmasndan nceki dnemde yani klasik C dneminde, void trden
gstericiler olmad iin, malloc ilevinin geri dn deeri char trden bir adresti. Bu
durumda, geri dn deeri olan adresin, char tr dnda bir gstericiye atanmas
durumunda tr dnm bir zorunluluktu.
malloc ilevi birden fazla kez arlarak birden fazla dinamik alan elde edilebilir. malloc
ilevine yaplan farkl arlarla elde edilen bloklarn bellekte bitiik olmas gvence
altnda deildir. Bu yzden, her bir ilev arsnn geri dn deeri olan adres mutlaka
bir gsterici deikende saklanmaldr. Aadaki kod paras ardk malloc arlarnn
bitiik bellek bloklar elde edeceini varsayd iin yanltr:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *pd;
int i;
pd = (int *)malloc(sizeof(int) * 10);
if (!pd) {
printf("cannot allocate memory!\n");
exit(EXIT_FAILURE);
}
if (malloc(sizeof(int) * 10) == NULL) {
printf("cannot allocate memory!\n");
exit(EXIT_FAILURE);
}
/* Yeni blok eski bloun hemen altnda olmak zorunda deildir */
for (i = 0; i < 20; ++i)
pd[i] = i;
/*...*/
return 0;
}
malloc ilevi ile elde edilen bloun iinde p deerler vardr. Aadaki kod paras ile bu
durumu snaynz:

326

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
#include <stdlib.h>
int main()
{
int *pd;
int i;
pd = (int *) malloc(10 * sizeof(int));
if (!pd) {
printf("yetersiz bellek!..\n");
exit(EXIT_FAILURE);
}
for (i = 0; i < 10; ++i)
printf("pd[%d] = %d\n", i, pd[i]);
return 0;
}
Dinamik bellek ilevlerinin kullanmna sunulan bellek blgesi ngilizce'de heap olarak
isimlendirilir. C++ dilinde bu alan free store olarak isimlendirilir. heap alannn bykl
sistemden sisteme deiebilir ancak alabilir bir program sz konusu olduunda,
altrlacak programn bellee yklenmesiyle, belirli byklkte bir heap alan programn
kullanmna ayrlr.
Sistemlerin ounda malloc ilevinin parametre deikeni unsigned int (size_t) trnden
olduuna gre, malloc ilevi ile DOS altnda en fazla 65535 byte yani 64KB byklnde
bir blok elde edilebilir. Oysa UNIX, WINDOWS gibi 32 bitlik sistemlerde unsigned int tr
4 byte uzunluunda olduuna gre, bu sistemlerde teorik olarak, malloc ilevi ile
4294967295 byte (4 MB) uzunluunda bitiik bir blok elde edilebilir. Tabi bu durum,
dinamik yer ayrma ileminin gvence altnda olduu anlamna gelmez.
Heap alan da snrldr. Srekli malloc ilevinin arlmas durumunda, belirli bir noktadan
sonra ilevler baarsz olarak NULL adresine geri dner.
Aada, kullanlan heap alannn bykl bir kod ile elde edilmeye allyor:
#include <stdio.h>
#include <stdlib.h>
#define BLOCK_SIZE

2048

int main()
{
long total = 0L;
void *pd;
for (;;) {
pd = malloc(BLOCK_SIZE);
if (!pd)
break;
total += BLOCK_SIZE;
}
printf("toplam heap alan = %ld byte\n", total);
system("pause");
return 0;
}
Yukardaki program DOS iletim sistemi iin nce BLOCK_SIZE simgesel deimezinin
2048 deeri ile derleyerek altrn. Daha sonra program BLOCK_SIZE deimezinin
deerini 1 yaparak yeniden derleyin ve altrn. Toplam deerin ok daha kldn
greceksiniz.

327

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

malloc ilevi dinamik blok elde etme ilemini programn alma zamannda yerine getirir.
Dinamik bellek ilevleriyle elde edilen bloklarn kontrol edilebilmesi iin heap alannda
uygun bir veri yaps ile bir tablo tutulur. Tutulan tabloda elde edilmi her bir dinamik
bloun balang adresi ve boyutu vardr. Bu tablonun kendisi de heap alanndadr. Bir
program altrldnda heap alan iki ayr biimde tketilir:
i) malloc/calloc/ realloc ilevleri tarafndan elde edilen bloklarn kullanma sunulmasyla
ii) her bir yer ayrma ilemi iin ilgili tabloya bir bilginin daha eklenmesi ile.

Elde Edilen Dinamik Bloun Geri Verilmesi

Dinamik bellek ilevlerine yaplan ardan elde edilen bir blok standart ilevlerinden free
ilevine yaplan ar ile sisteme geri verilebilir. free ilevinin bildirimi de stdlib.h balk
dosyas iindedir:
void free(void *block);
free ilevine daha nce malloc, calloc ya da realloc ilevleriyle elde edilmi olan bir bellek
blounun balang adresi geilmelidir. free ilevi arsyla bu blok heap alanna geri
verilmi olur. heap alanna geri verilen blok malloc, calloc ya da realloc ilevleri
tarafndan yeniden elde edilme potansiyeline girer.
Grld gibi free ilevi geri verilecek bellek blounun yalnzca balang adresini alr,
daha nce ayrlm bellek blounun boyutunu istemez. alma zamannda heap alannda
tutulan tablolarda, zaten elde edilmi bellek bloklarnn boyutu deeri tutulmaktadr.
free ilevine argman olarak daha nce dinamik bellek ilevleriyle elde edilmi bir bellek
blounun balang adresi yerine baka bir adres gnderilmesi tanmsz davrantr,
yaplmamaldr.
#include <stdlib.h>
int main()
{
char *p1, *ptr;
char s[100];
ptr = (char *)malloc(20);
free(ptr);
free(p1);
free(s);
}

/* Geerli ve doru*/
/* Yanl */
/* Yanl */

return 0;

Yukardaki rnekte
free(p1)
ars bir alma zaman hatasna neden olur. nk p1 adresinde dinamik bellek
ilevleri ile elde edilmi bir alan yoktur.
free(s)
ars da bir alma zaman hatasna neden olur. nk s dizisi iin yer, dinamik bellek
alanndan ayrlmamtr.
Daha nce dinamik olarak elde edilmi bir blok free ilevi ile heap alanna geri verilir,
ama bu bloun balang adresini tutan gsterici herhangi bir ekilde deitirilmez.
Bloun balang adresini tutan, free ilevine argman olarak gnderilen gsterici, free
ilevine yaplan ardan sonra artk gvenli olmayan bir adresi gsterir. Geri verilen bir

328

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

bellek blouna ulamak sk yaplan bir gsterici hatasdr. Aadaki kodu derleyerek
altrn:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define

ARRAY_SIZE

100

int main()
{
char name_entry[ARRAY_SIZE];
char *pd;
printf("bir isim giriniz: ");
gets(name_entry);
pd = (char *)malloc(strlen(name_entry + 1));
if (pd == NULL) {
printf("dinamik bir blok elde edilemiyor!\n");
exit(EXIT_FAILURE);
}
strcpy(pd, name_entry);
printf("yazi = %s\n", pd);
free(pd);
printf("yazi = %s\n", pd);
}

/* Yanl! */

return 0;

Yukardaki main ilevi iinde nce klavyeden alnan bir isim name_entry isimli yerel diziye
yerletiriliyor. Daha sonra arlan malloc ilevi ile klavyeden alnan ismin uzunluundan
1 byte daha byk bir bellek blou elde ediliyor. Elde edilen bellek blouna yerel dizideki
isim kopyalanyor. Daha sonra dinamik bloktaki isim ekrana yazdrlyor. Yaplan
free(pd)
arsyla dinamik blok heap alanna geri veriliyor. Ancak geri verme ileminden sonra
yaplan printf arsyla geri verilen bloa ulalyor. Bu bir gsterici hatasdr.
Dinamik bellek ilevleri dinamik yer ayrma ve dinamik blou geri verme ilemlerini
programn alma zamannda gerekletirirler.
free ilevine ilikin tipik bir hata da daha nce elde edilen bir dinamik bloun, free
ileviyle kltlmeye allmasdr. Aadaki kodu inceleyelin:
#include <stdlib.h>
int main()
{
char *pd;
pd = (char *)malloc(1000);
/****/
free(pd + 500); /* Yanlis */
/****/
free(pd);
return 0;
}

329

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yukardaki main ilevinde nce malloc ilevi ile 1000 byte'lk bir blok elde edilerek bloun
balang adresi pd gsterici deikenine atanyor. Daha sonra arlan free ilevine pd +
500 adresinin argman olarak gnderildiini gryorsunuz. Byle bir ar ile free
ilevinin daha nce ayrlan 1000 byte'lk alann 500 byte'n geri vermesi sz konusu
deildir.
pd + 500 adresi bir dinamik alann balang adresi deildir. Bu yzden ilev ars
tanmsz davran zellii gsterir. Bir malloc ars ile elde edilen dinamik alan free
ilevine yaplan bir aryla kltlemez.
free ilevine dinamik bir bloun balang adresi dnda baka bir adresin geilmesi
tanmsz davrantr. Bu durumun tek istisnas free ilevine NULL adresinin geilmesidir.
leve NULL adresinin geilmesi tanmsz davrana neden olmaz, yalnzca bir ileme
neden olmayan (no operation) ardr:
if (ptr)
free(ptr);
ptr bir gsterici deiken olmak zere yukardaki if deyiminde ptr deikeninin deeri
NULL adresi deilse free ilevi arlyor.
Bu if deyimi yerine free ilevi dorudan arlsa da kodun anlamnda fazlaca bir deiiklik
olmazd.

Dinamik Bir Dizinin Kullanlmas

malloc ilevi ile elde edilen bir bellek blou boyutu programn alma zamannda elde
edilen bir dizi olarak kullanlabilir. Aadaki program derleyerek altrn:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void set_array(int *ptr, int size)
{
int k;
for (k = 0; k < size; ++k)
ptr[k] = rand() % 100;
}
void display_array(const int *ptr, int size)
{
int k;
for (k = 0; k < size; ++k)
printf("%2d ", ptr[k]);
printf("\n");
}
int main()
{
int n;
int *pd;
printf("kac tane tamsayi : ");
scanf("%d", &n);
pd = (int *)malloc(sizeof(int) * n);
if (pd == NULL) {
printf("cannot allocate memory!\n");
exit(EXIT_FAILURE);
}
srand(time(0));

330

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

set_array(pd, n);
display_array(pd, n);
free(pd);
return 0;
}
Yukardaki programda programn alma zamannda ka nesnenin istendii bilgisi
kullancdan standart scanf ileviyle n deikenine alnyor. Daha sonra malloc ileviyle n
tane int trden nesnenin saca kadar byklkte bir dinamik bellek blou elde ediliyor.
Elde edilen dinamik bellek blounun balang adresinin pd isimli gstericiye atandn
gryorsunuz. Artk balang adresi pd ve boyutu n olan bir dizi sz konusudur, deil
mi? set_array ve display_array ilevleri bu dizinin balang adresi ve boyutu ile
arlyor.

calloc levi

calloc ilevi malloc ilevine ok benzer. stdlib.h balk dosyas iindeki bildirimi aadaki
gibidir.
void *calloc(size_t nblock, size_t block_size);
calloc ilevi heap alanndan birinci parametresi ile ikinci parametresi arpm kadar
byte'lk bir bellek blounu elde etmek iin kullanlr. levin geri dn deeri, yer ayrma
ileminin baarl olmas durumunda, elde edilen bellek blounun balang adresidir. Yer
ayrma ilemi baarl olmazsa calloc ilevi de malloc ilevi gibi NULL adresine geri dner.
Elemanlar int trden olan 100 elemanl bir dizi iin dinamik yer ayrma ilem calloc ilevi
ile aadaki gibi yaplabilir:
void func()
{
int *pd;
/***/
pd = (int*) calloc(100, sizeof(int));
if (pd == NULL) {
printf("cannot allocate memory\n");
exit(EXIT_FAILURE);
}
/***/
}
phesiz yukardaki kod parasnda calloc ilevi u ekilde de arlabilirdi:
pd = (int*) calloc(sizeof(int), 100);
calloc ilevinin malloc ilevinden baka bir fark da elde ettii bellek blounu
sfrlamasdr. calloc ilevi tarafndan elde edilen blounun tm byte'larnda sfr deerleri
vardr. malloc ilevi calloc ilevine gre ok daha sk kullanlr. Ayrlan blok sfrlanacaksa
malloc ilevi yerine calloc ilevi tercih edilebilir.
Yeri heap alanndan elde edilen n elemanl int trden bir dizinin elemanlar sfrlanmak
istensin. Bu ilem malloc ilevi ile yaplrsa, dizinin elemanlar ayr bir dng deyimi ile
sfrlanmaldr:
int main()
{
int *pd;
int i;
int n = rand() % 100 + 10;
pd = (int *) malloc(sizeof(int) * n);

331

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

/***/
for (i = 0; i < n; ++i)
ptr[i] = 0;
/***/

Oysa calloc ilevi zaten sfrlama ilemini kendi iinde yapar:


pd = calloc(sizeof(int) , n);
Derleyicilerin ounda calloc ilevi, bellekte yer ayrma ilemini yapmas iin, kendi iinde
malloc ilevini arr.

Bellekte Sznt

Dinamik bellek ilevleriyle heap alanndan elde edilen bir blok free ilevi arsna kadar
tutulur. Dinamik bloun balang adresi kaybedilirse, artk programn sonuna kadar bu
blou kullanma ans olmad gibi blok heap alanna geri de verilemez. Bu durum
bellekte sznt (memory leak) olarak isimlendirilir. Bir ilev iinde dinamik bir bloun elde
edildiini ancak ilev iinde bu bloun heap alanna geri verilmediini dnn:
void process()
{
char *pd = (char *)malloc(1000);
if (pd == NULL) {
printf("dinamik bir blok elde edilemiyor!\n");
exit(EXIT_FAILURE);
}
/***/
}
process isimli ilev her arldnda 1000 byte'lk bir alan elde ediliyor. Ancak ilev iinde
elde edilen dinamik alan heap alanna geri verilmiyor. Bu durumda process ilevine
yaplan her ar ile heap alanndan 1000 byte'lk bir alan bloke edilmi olur. process
ilevin ana program iinde ok sk arlan bir ilev olduu dnlrse, belirli bir ar
saysndan sonra heap alan tmyle tketilebilir. Yani belirli bir sre sonra artk malloc
ilevi yeni bir blou elde edemeyecek duruma gelir.

realloc ilevi
realloc ilevi daha nce malloc ya da calloc ilevleriyle elde edilmi bir bellek blounu
bytmek ya da kltmek iin arlr. levin bildirimi stdlib.h balk dosyas iindedir.
void *realloc(void *block, size_t newsize);
realloc ilevine gnderilen birinci argman, daha nce elde edilen bir bellek blounun
balang adresi, ikinci argman ise yeni bloun toplam uzunluudur.
realloc ilevi ile dinamik bir blok bytlmek istendiinde, ilev, blou daha yksek
saysal adrese doru bytmek zorunda deildir. realloc ilevi, daha nce elde edilmi
bloun bittii yerde, istenilen uzunlukta bir blok bulamazsa ya da dinamik alan bu ynde
bytmek istemezse, bu kez bloun tamam iin bellekte kullanlmayan baka bir yer
aratrr. Eer istenilen toplam uzunlukta ardl bir blok bulunursa buray ayrr, eski
bellek bloundaki deerleri yeni yere tar ve eski bellek blounu sisteme geri verir.
stenen uzunlukta srekli bir alan bulunamazsa ilev NULL adresiyle geri dner.
Aadaki programda yaplan dinamik bellek ilemlerini inceleyin:

332

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
#include <stdlib.h>
int main()
{
int *pd;
int k;
int n, nplus;
printf("kac tamsay : ");
scanf("%d", &n);
pd = (int *) malloc(sizeof(int) * n);
if (!pd) {
printf("bellek yetersiz!..\n");
exit(EXIT_FAILURE);
}
for (k = 0; k < n; ++k)
pd[k] = k;
printf("kac tamsay eklenecek: ");
scanf("%d", &nplus);
pd = (int *) realloc(pd, sizeof(int) * (n + nplus));
if (pd == NULL) {
printf("bellek yetersiz!..\n");
exit(EXIT_FAILURE);
}
for (; k < n + nplus; ++k)
pd[k] = k;
for (k = 0; k < n + nplus; ++k)
printf("%d ", pd[k]);
printf("\n");
free(pd);
return 0;
}
malloc ilevi ile int trden n tane nesnenin saca kadar byklkte bir dinamik alan
elde ediliyor. malloc ilevi baarl olamazsa standart exit ileviyle program
sonlandrlyor.
Elde edilen dinamik alandaki n tane nesneye bir dng yardmyla atamalar yaplyor.
Daha sonra arlan realloc ileviyle elde edilen dinamik alan nplus tane nesneyi daha
iine alabilecek biimde geniletiliyor. Eer realloc ilevi baarsz olursa program
sonlandrlyor. Ardndan realloc ilevinin geri dn deeri olan adresindeki n + nplus
adet nesneye sahip dizi yine bir dng deyimiyle yazdrlyor.
realloc ilevi baarl olmusa iki olaslk sz konusudur:
1. realloc ilevi daha nce elde edilen dinamik alann hemen altnda yani daha yksek
saysal adreste, ilk blou bytecek biimde bo alan bularak ek bellek alann buradan
salamtr. Bu sistemlerin ounda pek karlalan bir durum deildir. Bu durumda
realloc ilevinin geri dn deeri olan adres ilevin birinci parametresine gnderilen
adrestir.

333

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

2. realloc ilevi daha nce ayrlan bloun altnda bo yer bulamam ya da bu ynde bir
bytme ilemini tercih etmemi olabilir. Ve heap alannda toplam
(n + nplus) * sizeof(int)
kadar byte'lk baka bir bo blok ayarlam olabilir. Bu durumda realloc ilevi daha nce
elde edilmi alandaki deerleri de bu alana kopyalayarak eski blou sisteme geri
vermitir.
realloc ilevinin bu davranndan dolay geri dn deeri bir gsterici deikene mutlaka
atanmaldr. Aada sk yaplan tipik bir hata grlyor:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *p;
p = malloc(10);
if (p == NULL) {
printf("can not allocate memory!..\n");
exit(EXIT_FAILURE);
}
/***/
if (realloc (p, 20) == NULL) {
printf("can not allocate memory!..\n");
exit(EXIT_FAILURE);
}
gets(p);
}

return 0;

realloc ilevinin baarl olmas daha nce elde edilen bloun altna yani daha byk
saysal adrese doru ek blok salad anlamna gelmez. realloc ilevi daha nce elde
edilmi dinamik alan baka bir yere tayarak yeni bloun balang adresiyle geri
dnm olabilir. Bu durumda eski blok serbest braklr, artk bu adresin bir gvenilirlii
yoktur.
Yukardaki rnekte realloc ilevinin, daha nce elde edilen blou bulunduu yerde
bytt varsaylyor. Eer realloc ilevi bellek blounu baka bir yere tayarak
bytmse, yukardaki kodda bir gsterici hatas yaplm olur, nk artk p
gstericisinin gsterdii adres gvenilir bir adres deildir.
Bu yzden uygulamalarda genellikle realloc ilevinin geri dn deeri, realloc ilevine
deeri gnderilen gstericiye atanr:
ptr = realloc(ptr, 100);
Ancak bu bir zorunluluk deildir. Eer realloc ilevi ile yaplan yer ayrma ileminin
baarl olmamas durumunda program sonlandrlmayacaksa ve daha nce dinamik
olarak elde edilen blgedeki deerler bir dosyaya yazlacak ise, artk realloc ilevinin
baarsz olmas durumunda, ptr gstericisine NULL adresi atanaca iin ptr gstericisinin
daha nce elde edilen blok ile ilikisi kesilmi olur.
Byle bir durumda geici bir gsterici kullanmak uygun olur:
temp = realloc(ptr, 100);
if (temp == NULL)
printf("cannot allocate memory!..\n);

334

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Bu durumda ptr gstericisi halen daha nce elde edilen bloun balang adresini
gsteriyor.
C standartlar realloc ilevi ile ilgili olarak aadaki kurallar getirmitir:
i) Daha nce elde edilen bir bellek blounu bytmesi durumunda, realloc ilevi bloa
eklenen ksma herhangi bir ekilde deer vermez. Yani eski bloa eklenen yeni blok
iinde p deerler (garbage values) bulunur.
realloc ilevi eer daha nce elde edilmi bellek blounu bytemez ise NULL adresi ile
geri dner ancak daha nce elde edilmi olan ve bytlemeyen bellek bloundaki
deerler korunur.
ii) Eer realloc ilevine gnderilen birinci argman NULL adresi olursa, realloc ilevi
tamamen malloc ilevi gibi davranr. Yani:
realloc(NULL, 100);
ile
malloc(100);
arlar tamamen ayn anlamdadr. Her ikisi de 100 byte'lk bir dinamik alan elde etmeye
alr.
Buna neden gerek grlmtr? Yani neden malloc(100) gibi bir ar yapmak yerine
realloc(NULL, 100) eklinde bir ar tercih edilebilir?
Aadaki program inceleyin:
#include
#include
#include
#include

<stdio.h>
<ctype.h>
<stdlib.h>
<conio.h>

void display_array(const int *ptr, int size);


int get_max(const int *ptr, int size);
int get_min(const int *ptr, int size);
double get_ave(const int *ptr, int size);
double get_stddev(const int *ptr, int size);
int main()
{
int *ptr = NULL;
int ch, grade;
int counter = 0;
for (;;) {
printf("not girmek istiyor msunuz? [e] [h]\n");
while ((ch = toupper(getch())) != 'E' && ch != 'H')
;
if (ch == 'H')
break;
printf("notu giriniz : ");
scanf("%d", &grade);
counter++;
ptr = (int *) realloc(ptr, sizeof(int) * counter);
if (ptr == NULL) {
printf("cannot allocate memory!..\n");
exit(EXIT_FAILURE);
}

335

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

ptr[counter - 1] = grade;

if (counter == 0) {
printf("hibir not girii yapmadnz!..\n");
return 0;
}
printf("toplam %d tane not girdiniz\n", counter);
printf("girdiiniz notlar aada listeleniyor :\n");
display_array(ptr, counter);
printf("\nen buyuk not : %d\n", get_max(ptr, counter));
printf("en kk not : %d\n", get_min(ptr, counter));
printf("notlarn ortalamas : %lf\n", get_ave(ptr, counter));
printf("notlarn standart sapmas . %lf\n", get_stddev(ptr, counter));
free(ptr);
return 0;
}
Yukardaki programda:
ptr = (int *) realloc(ptr, sizeof(int) * counter);
deyiminde, dngnn ilk turunda ptr gstericisinin deeri NULL olduu iin realloc ilevi
malloc gibi davranacak ve int trden 1 adet nesnelik yer ayrr. Ancak dngnn daha
sonraki turlarnda realloc ilevine gnderilen adres NULL adresi olmayacandan, daha
nce elde edilen blok dng iinde srekli olarak bytlm olur.
Eer realloc ilevine gnderilen ikinci argman 0 olursa, realloc ilevi tamamen free ilevi
gibi davranr:
realloc(ptr, 0);
ile
free(ptr);
tamamen ayn anlamdadr. Buna neden gerek grlmtr? Yani neden
free(ptr)
gibi bir ar yapmak yerine
realloc(ptr, 0)
eklinde bir tercih edilsin?

Dinamik Olarak Elde Edilen Alann Balang Adresine Geri Dnen


levler

Dinamik olarak ayrlan bir blok, free ileviyle serbest braklarak sisteme geri verilene
kadar gvenli olarak kullanlabileceine gre, bir ilev byle bir bloun balang adresine
geri dnebilir.
Aadaki ilevi inceleyin:

336

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *getname()
{
char s[30];
char *ptr;
printf("ismi giriniz : ");
gets(s);
ptr = (char *) malloc(strlen(s) + 1);
if (ptr == NULL) {
printf("cannot allocate memory!..\n");
exit(EXIT_FAILURE);
}
return strcpy(ptr, s);
}
getname ilevinde nce klavyeden bir isim yerel bir diziye alnyor. Daha sonra strlen
ilevi kullanlarak yerel diziye alnan ismin uzunluu bulunuyor. malloc ilevi ile bu ismi ve
sonuna gelecek sonlandrc karakteri iine alacak byklkte bir alan dinamik olarak elde
ediliyor. Daha sonra da strcpy ilevi kullanlarak, isim dinamik olarak elde edilen alana
kopyalanyor ve bu bloun balang adresine geri dnlyor.
Dinamik bir yer ayrma ilemi yapan ilevin arlmas sonucunda ayrlan bloun geri
verilmesi, ilevi arann kodun sorumluluunda olur:
int main()
{
char *p =
/*****/
free(p)
/*****/
return 0;
}

getname();

Bir ilev iinde dinamik olarak bir bellek blou ayrmak ve daha sonra bu bloun
balang adresine geri dnmek C dilinde ok kullanlan bir tekniktir.
Aada kaynak kodu verilen strcon ilevi birinci parametresinde balang adresi tutulan
yaznn sonuna ikinci parametresinde balang adresi tutulan yazy kopyalyor; fakat her
iki adresteki yazlar da bozmadan, birletirilmi yaznn balang adresi olan bir adrese
geri dnyor:
#include <string.h>
#include <stdlib.h>
char *strcon(const char *s1, const char*s2)
{
char *ptr = malloc (strlen(s1) + strlen(s2) + 1);
/* Basari sinamasi */
strcpy(ptr, s1);
strcat(ptr, s2);
}

return ptr;

337

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

levimiz, adresleri gnderilen yazlar dinamik bir alana kopyalayarak, dinamik alann
balang adresiyle geri dnyor. strcpy ve strcat ilevleri, birinci paramatrelerinin
deerleriyle geri dndnden
strcpy(ptr, s1);
strcat(ptr, s2);
return ptr;
deyimleri tek bir deyim olarak yazlabilirdi, deil mi?
return strcat(strcpy(ptr, s1), s2);

Birden Fazla Dinamik Alann Bir Gsterici Dizisiyle Denetimi

Dinamik bellek ilevleriyle elde edilen farkl bloklarn balang adreslerinin bir gsterici
dizisinin elemanlarnda tutulmas ok karlalan bir temadr. Aadaki program
inceleyin:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *get_name()
{
char name_entry[40];
char *pd;
printf("ismi giriniz : ");
gets(name_entry);
pd = (char *) malloc(strlen(name_entry) + 1);
if (pd == NULL) {
printf("bellek yetersiz!..\n");
exit(EXIT_FAILURE);
}
return strcpy(pd, name_entry);
}
int main()
{
char *p[10];
int k;
int len_sum = 0;
for (k = 0; k < 10; ++k)
p[k] = get_name();
printf("isimler : \n");
for (k = 0; k < 10; ++k) {
printf("(%s) ", p[k]);
len_sum += strlen(p[k]);
}
printf("\n");
printf("girilen isimlerin ortalama uzunlugu = %lf\n", (double)len_sum /
10);
for (k = 0; k < 10; ++k)
free(p[k]);
return 0;
}

338

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Baz durumlarda gsterici dizisinin kendisi de dinamik olarak yaratlr. Aadaki


programda satr ve stn says klavyeden girilen bir matrisin elemanlarna nce 0 - 100
arasnda rastgele deerler veriliyor sonra matris ekrana yazdrlyor:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
int no_of_rows, no_of_cols;
int **prows;
int i, k;
srand(time(0));
printf("satir sayisi : ");
scanf("%d", &no_of_rows);
printf("sutun sayisi : ");
scanf("%d", &no_of_cols);
prows = (int **)malloc(sizeof(int *) * no_of_rows);
if (prows == NULL) {
printf("dinamik bellek elde edilemiyor!\n");
exit(EXIT_FAILURE);
}
for (k = 0; k < no_of_rows; ++k) {
prows[k] = (int *) malloc(sizeof(int) * no_of_cols);
if (prows[k] == NULL) {
printf("dinamik bellek elde edilemiyor!\n");
exit(EXIT_FAILURE);
}
}
/****/
for (i = 0; i < no_of_rows; ++i)
for (k = 0; k < no_of_cols; ++k)
prows[i][k] = rand() % 100;
/****/
for (i = 0; i < no_of_rows; ++i) {
for (k = 0; k < no_of_cols; ++k)
printf("%2d ", prows[i][k]);
printf("\n");
}
/****/
for (i = 0; i < no_of_rows; ++i)
free(prows[i]);
free(prows);
}

return 0;

imdi program inceleyin. Matrisin satr ve stun saysnn kullanc tarafndan klavyeden
girilmesi salanyor. Matrisin satr says nrows stun says ncols'dur. Matris nrows tane
ncols uzunluunda int trden dinamik diziden oluur. Yani matrisin her bir satr bir
dinamik dizidir. Bu dinamik dizilerin balang adresleri yine dinamik bir gsterici
dizisinde tutulur. nce nrows tane int * trnden nesne iin dinamik bir alann ayrldn
gryorsunuz:
prows = (int **)malloc(sizeof(int *) * no_of_rows);

339

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Aadaki dng ile bu dinamik dizinin her bir elemannn int trden ncols uzunluunda
dinamik bir dizinin balang adresini tutulmas salanyor.
for (k = 0; k < no_of_rows; ++k) {
prows[k] = (int *) malloc(sizeof(int) * no_of_cols);
Yer ayrma ilemleri tamamlandktan sonra
prows[i][k]
ifadesiyle matrisin i ve k indisli elemanna ulalabilir. nk prows[i] (int *) trnden bir
nesnedir. Bu nesnenin deeri dinamik bir dizinin balang adresidir. Keli ayra ilecinin
ile ncelik tablosunun birinci dzeyinde olduunu, bu ncelik dzeyinin soldan saa
ncelik ynne sahip olduunu hatrlayn. Bu durumda nce daha soldaki keli ayra
ileci bir deer retir. Soldaki keli ayra ilecinin rettii (int *) trnden deer bu kez
ikinci keli ayra ilecine terim olur. Bu ile de satrlardan herhangi birini oluturan int
trden dinamik dizinin bir elemanna ulatrr. Bu durumda ulalan int trden nesne,
matrisin [i][k] indisli eleman olur.
Ayrlan dinamik alanlarn geri verilmesinde dikkatli olunmaldr. nce matrisin satrlarn
oluturan dinamik diziler heap alanna geri verilmeli, daha sonra ise dinamik dizilerin
balang adreslerini tutan gsterici dizisinin geri verilme ilemi gerekletirilmelidir:
for (i = 0; i < no_of_rows; ++i)
free(prows[i]);
free(prows);

340

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

BELRLEYCLER ve NTELEYCLER
Belirleyiciler (storage class specifiers), bildirimler yaplrken kullanlan ve nesnelerin
zellikleri hakknda derleyicilere bilgi veren anahtar szcklerdir.
C'de kullanlan belirleyiciler unlardr:
auto, register, static, extern ve typedef.
Tr niteleyicileri ise nesnelerin iindeki deerlerin deitirilip deitirilmeyeceine ilikin
bilgi verir.
Tr belirleyicileri unlardr:
const, volatile.
Yer belirleyici ve tr niteleyiciler C'nin anahtar szckleridir.

Yer Belirleyicilerle Bildirim lemi

Yer belirleyici, tr belirleyici ya da tr ifade eden anahtar szcklerin dizilimi herhangi bir
biimde olabilir:
auto const unsigned long int
const auto unsigned long int
unsigned long int auto const
int const long auto unsigned

a;
a;
a;
a;

Yukardaki bildirimlerin hepsi geerlidir. Ancak okunabilirlik asndan yer belirleyici


szcn daha nce yazlmas nerilir.
Eer bir bildirimde belirleyicisi ya da tr niteleyicisi bir tr bilgisi olmadan kullanlrsa,
nceden seilmi (default) olan int tr bildirimin yapld kabul edilir.
register int a;
Yukardaki bildirim ile
register a;
bildirimi edeerdir.
Ancak okunabilirlik asndan byle bir bildirim nerilmez.

auto Belirleyicisi
auto yalnzca yerel deikenler iin kullanlabilecek bir yer belirleyicisidir. auto
belirleyicisinin global deikenlerin ya da ilevlerin parametre deikenlerininin
bildiriminde kullanlmas geersizdir.
Bu anahtar szck, nesnenin bilinirlik alan bittikten sonra kaybolacan, bellekte
kaplad yerin geerlilii kalmayacan gsterir. Yerel deikenler otomatik mrldr.
Yani bulunduklar bloa ilikin kod almaya balandnda yaratlr, sz konusu bloun
yrtlmesi bittikten sonra yok olurlar. te auto belirleyicisi bu durumu vurgulamak iin
kullanlr. Zaten bir yerel deiken, baka bir yer belirleyici anahtar szck kullanlmad
srece (default olarak) auto biiminde ele alnr. Bu durumda auto yer belirleyicisinin
kullanm gereksizdir:
{
}

auto int a;
float b;

341

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

auto yer belirleyicisi global deikenlerle ya da parametre deikenleriyle birlikte


kullanlmaz. rnein :
auto int a;
function(auto int x)
{
/***/
}

/* Geersiz! */
/* Geersiz! */

auto anahtar szc baz mikroilemcilerde uyumu korumak iin dnlmtr.


Modern sistemlerde anlaml bir kullanm yoktur.

register Belirleyicisi
register belirleyicisi, deikenin "bellekte deil de CPU yazmalarnn iinde" tutulmas
isteini derleyiciye ileten bir anahtar szcktr. Deikenlerin bellek yerine dorudan
yazmalarda tutulmas programn almasn hzlandrr.
Yazma (register) nedir? Yazmalar CPU (central processing unit) iinde bulunan tampon
bellek blgeleridir. CPU iindeki aritmetik ve mantksal ilemleri yapan birimin yazmalar
ve belleklerle ilikisi vardr. Genel olarak CPU tarafndan yaplan aritmetik ve mantksal
ilemlerin her iki terimi de bellee ilikin olamaz. rnein bellekte bulunan sayi1 ve sayi2
isimli iki deiken toplanarak elde edilen deer sayi3 isimli baka bir bellek blgesine
yazlmak istensin. Bu C'deki
sayi3 = sayi1 + sayi2;
ilemine karlk gelir. CPU bu ilemi ancak 3 admda gerekletirebilir:
1. adm : nce sayi1 bellekten CPU yazmalarndan birine ekilir.
MOV reg, sayi1
2. adm : Yazma ile sayi2 toplanr.
ADD reg, sayi2
3. adm: Toplam sayi3 ile belirtilen bellek alanna yazlr.
MOV sayi3, reg
Bellee yazma ve bellekten okuma ilemleri yazmalara yazma ve yazmalardan okuma
ilemlerine gre daha yavatr. nk bellee eriim iin bir makine zaman gerekir.
register belirleyicisi derleyiciye yalnzca bir istei iletir. Yani register belirleyicisi ile
bildirilen deikenin yazmata tutulacann bir gvencesi yoktur. Derleyiciler byle bir
istei yerine getirmeyebilir. CPU yazmalar hangi sistem sz konusu olursa olsun snrl
saydadr. Bu nedenle birka deikenden fazlas register belirleyicisi ile tanmlanm olsa
bile yazmalarda saklanmayabilir. C derleyicileri yazmalarda saklayamayacaklar
deikenler iin genel olarak hata veya uyar iletileri vermez. Yani derleyiciler,
tutabilecekleri yazma saysndan fazla register belirleyicisine sahip deikenlerle
karlatklarnda bunlara ilikin register belirleyicilerini dikkate almaz.
register belirleyicileri ancak yerel ya da parametre deikenleri ile kullanlabilir. Global
deikenler ile kullanlamazlar. rnekler:
register int g;

/* Geersiz! */

int func (register int y)


/* Geerli */
{
register int x;
/* Geerli */
}

342

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

En fazla ka tane deikenin yazmalarda saklanabilecei bilgisayar donanmlarna ve


derleyicilere baldr. Ayrca, uzunluu tamsay (int) trnden byk olan trler genellikle
yazmalarda saklanamaz. Bu durumlarda da derleyicilerden hata veya uyar iletisi
beklenmemelidir.
Sonu olarak register belirleyicisi hzn nemli olduu ok zel ve ksa kodlarda ancak
birka deiken iin kullanlmaldr. Modern derleyicilerin ou seime bal olarak kod
zerinde eniyileme (optimizasyon) yaparak baz deikenleri yazmalarda saklar. Bu
durum da ou zaman register anahtar szcnn kullanlmasn gereksiz klar.

static Belirleyicisi
static belirleyicisi ancak yerel ya da global deikenlerin bildiriminde kullanlabilir. Bu
belirleyici, parametre deikenlerinin bildiriminde kullanlamaz.
static anahtar szcnn global ve yerel deikenlerin bildiriminde kullanlmas farkl
anlamlara gelir.

static Anahtar Szcnn Yerel Deikenlerin Bildiriminde


Kullanlmas

static yer belirleyicisi ile tanmlanm yerel deikenler ya da yerel diziler programn
almas boyunca bellekte kalr. Baka bir deyile, static anahtar szc yerel
deikenlerin mrn otomatik mrden statik mre ykseltir. Statik yerel deikenler
tpk global deikenler gibi programn almaya balamasyla yaratlr ve programn
yrtlmesi bitene kadar da bellekte tutulur.
Statik yerel deikenler programc tarafndan ilkdeer verildikten sonra kullanlr.
lkdeer verme ilemi programn almas srasnda deil, derleme zamannda derleyici
tarafndan yaplr. Derleyici bellekten yer ayrlmasna yol aacak makine kodunu
oluturur. Statik yerel deiken iin bellekte yer programn yklenmesi srasnda ayrlr.
Derleme zamannda gerekte bellekte yer ayrlmaz. Bellekte yer ayrma iini yapacak
makine kodu retilir. Statik yerel deikenler ilkdeerleriyle birlikte bellee yklenir.
Aadaki program derleyerek altrn:
#include<stdio.h>
void func1()
{
int x = 5;
printf("x = %d\n", x);
x++;
}
void func2()
{
static int y = 5;
printf("y = %d\n", y);
y++;
}
int main()
{
int k;
printf("func1 ilevi 5 kez arlyor!\n");
for (k = 0; k < 5; ++k)
func1();
printf("\nfunc2 ilevi 5 kez arlyor!\n");
for (k = 0; k < 5; ++k)
func2();
return 0;
}

343

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yukardaki program iinde tanmlanan func1 ilevi her arldnda x deikeni yaratlr
ve ilevin almas sonlandnda x deikeni bellekten boaltlr. Her ne kadar ilevin
sonlanmasndan nce x deikeninin deeri 1 artrlsa da, bunun bir sonraki arya hibir
etkisi olmaz. func1 ilevinin bir sonraki arsnda x deikeni yine 5 deeri ile balatlr.
Oysa func2 ilevi iin durum deiiktir. func2 ilevi iindeki y isimli yerel deiken blok
bilinirlik alanna ait fakat statik mrldr. y deikenine ilkdeer verme deyimi derleyici
tarafndan retilen kodun bir parasdr. y deikeni programn banda 5 deeri ile
balatlr ve programn sonuna kadar bellekteki yerini korur. lev ka kez arlrsa
arlsn, bellekteki yeri deimeyen ayn y deikeni kullanlr. Bu durumda ilevin ana
blounun sonunda y deikeninin deeri 1 artrld iin bir sonraki arda artk y
deikeninin deeri 6 olur. Programa ilikin ekran ktsn aada veriyoruz.
func1 ilevi 5 kez arlyor!
x = 5
x = 5
x = 5
x = 5
x = 5
func2 ilevi 5 kez arlyor!
y = 5
y = 6
y = 7
y = 8
y = 9

statik Yerel Nesnelerin Kullanlmasna likin Ana Temalar

Statik yerel nesnelerin kullanlmasna ilikin ana temelarda, bu nesnelerin mrlerinin


statik olmasndan faydalanlr. Bu temalarda global deikenler de pekala kullanlabilir.
Ancak global deikenler statik mrl olmalaryla birlikte dosya bilinirlik alanna aittir.
Oysa statik yerel deikenler blok bilinirlik alanna aittir. Global deikenlerin dosya
bilinirlik alanna sahip olmalarndan kaynaklanan dezavantajlardan etkilenmemek iin bir
ok durumda ilevlerin statik mrl nesne gereksinimi statik yerel deikenlerle
karlanr.

levlerin Statik Yerel Nesnelerin Adresleriyle Geri Dnmeleri

Bir adres deerine geri dnen ilevlerin, yerel deikenlerin adreslerine geri dnmemeleri
gerektiini biliyorsunuz. nk yerel deikenler otomatik mrldr ve ilevin almas
sonunda bellekten boaltlr. Ancak static anahtar szc ile tanmlanm yerel
deikenler, programn sonlanmasna kadar bellekteki yerlerini koruyacandan, ilevin
statik bir yerel deikenin adresine geri dnmesinde bir saknca yoktur:
#include <stdio.h>
char *get_name()
{
static char entry[100];
printf("bir isim giriniz : ");
gets(entry);
return entry;
}
Ancak statik bir yerel dizinin adresiyle geri dnmek, dinamik bir dizinin yani malloc
ileviyle yeri elde edilmi bir dizinin adresiyle geri dnmekten farkldr. lev her
arldnda ayn adresi dndrr. Aadaki main ilevini inceleyin:

344

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
int main()
{
char *p[10];
int k;
for (k = 0; k < 10; ++k)
p[k] = get_name();
/*...*/
for (k = 0; k < 10; ++k)
printf("isim = (%s)\n", p[k]);
}

return 0;

Yukardaki main ilevinde programc 10 elemanl bir gsterici dizisi tanmlanyor. Gsterici
dizisinin her bir elemanna get_name ilevinin arlarndan elde edilen geri dn
deerleri olan adresler atanyor. Ancak get_name ilevi her defasnda ayn statik yerel
dizinin adresiyle geri dnyor. Kullanc tarafndan yaplan isim girii her defasnda bir
nceki giriin zerine yazlr. main ilevinin sonunda gsterici dizisinin tm elemanlar
ayn yazy gsterir, deil mi?
Baz standart C ilevleri de statik yerel dizilerin adreslerine geri dner. rnein time.h
balk dosyas iinde bildirimi yaplan ctime ve asctime ilevleri statik bir dizi iinde
tutulan yaznn balang adresiyle geri dner.

Statik Yerel Dizilerin Kullanlmasyla Salanan Verim Art


Diziler de static anahtar szcyle tanmlanabilirler.

void func()
{
static char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
/**/
}
Yukardaki rnekte, func ilevi iinde alphabet dizisi static anahtar szcyle
tanmland iin, bir kez ilkdeer verildikten sonra her arldnda bu deerleri korur ve
varln programn sonuna kadar srdrr. Oysa static anahtar szc kullanlmasayd,
bu dizi func ilevine yaplan her arda yeniden yaratlacak ve dizinin elemanlarna
yaplan ilkdeer atamalar her defasnda yeniden yaplacakt. Bu da ileve yaplan her
ar iin ek bir makine zamannn harcanmasna neden olacakt.

levlerin Daha nceki arlaryla Mantksal Ba kurmas

Baz ilevler daha nceki arlaryla mantksal bir ba oluturarak ilerini


gerekletirirler. rnein LIMIT pozitif bir tamsay olmak zere 0 LIMIT aralnda
rastgele say retecek bir ilev tanmlamak istediimizi dnelim. lev daha nce
retmi olduu bir sayy bir daha retmesin. lev bir saynn daha nce retilip
retilmemi olduu bilgisini statik bir yerel bayrak dizisinde saklayabilir. Aadaki
program derleyerek altrn:
#include
#include
#include
#include

<stdio.h>
<string.h>
<stdlib.h>
<time.h>

#define

LIMIT

20

345

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

int urand()
{
static char flags[LIMIT] = {0};
int ret_val;
if (!memchr(flags, 0, sizeof(flags)))
return -1;
while (flags[ret_val = rand() % LIMIT])
;
flags[ret_val]++;
}

return ret_val;

int main()
{
int k;
srand(time(0));
for (k = 0; k < LIMIT; ++k)
printf("%d ", urand());
printf("\n");
printf("%d\n", urand());
}

return 0;

urand ilevi iinde flags isimli statik bir yerel dizinin elemanlar 0 deeriyle balatlyor.
Dizinin her bir eleman ilgili deerin daha nce retilip retilmediini gsteren bir bayrak
olarak kullanlyor. rnein ilev arldnda 12 deerinin daha nce retilip retilmedii
flags dizisinin 12 indisli elemannn deerinden anlalyor. Bu elemann deeri 0 ise 12
deeri retilmemi, 1 ise 12 deeri retilmi demektir.
lev nce standart memchr ileviyle dizinin iinde 0 deerinin olup olmadna bakyor.
Dizinin hibir elemannn deeri 0 deilse, tm deerler retilmi demektir. lev -1
deerine geri dnerek bu durum hakknda bilgi iletiyor.
Bayrak dizisinde en az bir 0 deeri var ise, bir dng iinde srekli rastgele deer
retiliyor. retilen deer, ismi ret_val olan bir deikene atanyor. Bayrak dizisinin
ret_val indisli elemannn deeri 1 olduka dng devam ediyor. Dngden klmas iin
daha nce retilmemi bir deerin retilmesi gerekiyor. Dngden kldktan sonra
ret_val deikeninin deer, geri dndrlecek deerdir. Ancak bu deer geri
dndrlmeden nce bayrak dizisinin ret_val indisli elemannn deeri 1 yaplyor.
Bylece bir sonraki arda artk bu deeri yeniden retilmesi engelleniyor.

Statik Yerel Deikenler ile Global Deikenlerin Karlatrlmas

Statik yerel deikenler mr asndan global deikenler ile ayn zellikleri gsterirler.
Yani programn almaya balamas ile yaratlrlar ve programn almas bitince
mrleri sona erer. Ama bilinirlik alan (scope) asndan farkllk gsterirler. Global
deikenler dosya bilinirlik alanna uyarken statik yerel deikenler blok bilinirlik alanna
uyar. Statik yerel deikenlerin blok bilinirlik alanna sahip olmas verilerin gizlenmesini
(data hiding) kolaylatrr ve kodun yeniden kullanlabilirliini (reusability) artrr. nk
global deikenlere bal olan ilevler bir projeden bir baka projeye kolayca
tanamazlar.

Modl Kavram ve Nesnelerin Balant zellii

Bir proje birbirinden bamsz olarak derlenebilen birden fazla kaynak dosyadan
oluabilir. Projelerin bamsz olarak derlenebilen her bir kaynak dosyasna "modl" denir.

346

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Bir projeyi oluturan farkl kaynak dosyalar birbirinden bamsz olarak derlendikten
sonra, hepsi birlikte balayc (linker) ile birletirilerek tek bir altrlabilir dosyay
olutururlar.

Byk Projelerin Modllere Ayrlmasnn Faydalar

Eer btn modller tek bir kaynak kod iinde birletirilirse en ufak bir deiiklikte tm
proje tekrar derlenmek zorundadr. Oysa modllere ayrlm projelerde, yalnz deiikliin
yapld modln derlenmesi yeterlidir. nk dier modller zaten derlenmitir ve onlar
yalnzca balama aamasnda ilem grrler. Programlar modller halinde yazmann bir
dier avantaj da grup almas yaparken ortaya kar. Bu durumda projelerin bamsz
paralar (modlleri) ayr kiiler tarafndan hazrlanabilir.
Dier taraftan modller de ilevler gibi yeniden kullanlabilen yaplardr. Bir modl birden
fazla projede kullanlabilir.

Balant Kavram

Projeyi oluturan kaynak dosyalarn birinde tanmlanan bir isme, projeyi oluturan baka
bir kaynak dosya iinde ulalabilir mi? Bu kaynak dosyalar en sonunda tek bir alr
dosyay oluturacaklarna gre, baz durumlarda bir modlde tanmlanan bir nesneye
baka bir modlde ulamak istenmesi son derece doaldr.
Bir modlde tanmlanm bir deikenin baka bir modlde kullanlp kullanlmayacan
gsteren zellie o nesnenin balant zellii (linkage) denir. Balant zellii bilinirlik
alanndan farkldr. Bilinirlik alan derleyiciyi ilgilendiren yani derleme zamanna ilikin bir
kavramdr. Bir nesne bilinirlik alan dnda kullanlrsa derleme zamannda hata oluur.
Ancak balant, balayc program ilgilendiren yani balama zamanna ilikin bir
kavramdr. Bir nesne, balantsnn olmad bir modlde kullanlrsa balama zamannda
hata oluur.
C standartlarna gre nesneler balant zellikleri asndan 3 ana gruba ayrlr.
1. D balantya sahip nesneler (external linkage)
Eer bir nesne tanmlandktan sonra, bu nesneye hem kendi modlnn iinde her yerde
hem de dier modllerde ulam mmknse "nesnenin d balants vardr" denir.
2. balantya sahip nesneler (internal linkage)
Eer bir nesne tanmlandktan sonra bu nesneye kendi modlnn iinde her yerde
ulalabiliyorsa, ancak projeyi oluturan dier modllerde bu nesneye ulalamyorsa,
"nesnenin i balants vardr" denir.
3. Balantsz Nesneler (no linkage)
Kendi modlnde ancak belirli bir blok iinde bilinen nesnelerdir.
Bir ilevin parametre deikenleri ve bir ilev iinde tanmlanan yerel nesneler balantsz
nesnelerdir. Bu nesnelere projeyi oluturan dier modllerde ulamak mmkn deildir.
Global deikenler normal olarak d balantya sahiptir. Yani bir global deikene baka
bir modl iinde ulalabilir. Peki projeye ait bir kaynak dosya iinde global bir deiken
tanmland zaman baka bir kaynak dosya iinde bu deiken nasl kullanlabilir?

347

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

extern Belirleyicisi

extern belirleyicisi ile bir bildirim yaplr. Bir deikenin extern belirleyicisi ile bildirilmesi
derleyiciye nesnenin baka bir modlde tanmlandn anlatr.
Bir proje mod1.c ve mod2.c isimli iki kaynak dosyadan olumu olsun :
MOD1.C
int a;
float func1()
{
/***/
a = 100;
/***/
}

MOD2.C
int func2()
{
...
a = 300;
/* HATA */
}

mod1.c dosyasnda tanmlanm olan a deikeni global bir deikendir ve d balantya


sahip olduu iin normal olarak proje iindeki dier kaynak dosyalarda da kullanlabilir.
mod2.c dosyasnda da bu deikene ulalabilir. Fakat iki modln ayr ayr derlendii
yukardaki rnekte problemli bir durum sz konusudur. nk mod2.c dosyasnn
derlenmesi srasnda derleyici a deikeninin mod1.c kaynak dosyas iinde global olarak
tanmlandn bilemez. mod2.c kaynak dosyasn derlerken a deikeni hakknda bilgi
bulamayan derleyici bu durumu hata olarak belirler. C dilinde bir deiken ancak nceden
bildirilmise kullanlabilir, deil mi? extern belirleyicisi derleyiciye, ilgili global
deikeninin kendi modl iinde deil de bir baka modl iinde tanml olduunu
bildirme amacyla kullanlr.
mod2.c modlnde a deikeninin extern anahtar szc ile bildirilmesi durumunda sz
konusu sorun ortadan kalkar.
mod2.c
extern int a;
/*extern bildirimiyle a deikeninin baka bir modlde tanmlanm olduu
belirtiliyor*/
int func2()
{
a = 300;
/***/
}
extern bildirimini gren derleyici, deikenin projeye ait baka bir modlde tanmlandn
varsayarak hata durumunu ortadan kaldrr. Ancak derleyici makine kodu retirken
extern anahtar szc ile bildirilmi bir deikenin bellekteki yerini
saptayamayacandan, bu ilemi btn modlleri gzden geirecek olan balayc
programa brakr. Bylece deikenin tanmland modl bulup extern olarak bildirilmi
olanlarla ilikilendirme ilemi balayc program (linker) tarafndan yaplr. Yani extern
belirleyicisi ile programc derleyiciye, derleyici ise balaycya bildirimde bulunur.
extern belirleyicisini gren derleyici bellekte bir yer ayrmaz. extern bildirimi bir
tanmlama deildir, bildirimdir.
Aslnda yalnz deikenler iin deil ilevler iin de extern belirleyicisinin kullanlmas sz
konusudur. C derleyicileri kendi modlleri iinde tanmlanmadklar halde arlan standart C ilevleri gibi- ilevleri otomatik olarak extern kabul ederler. Bu nedenle ilev
bildirimlerinde ayrca extern belirleyicisini yazmaya gerek yoktur. nk derleyici
tarafndan yazlm varsaylr.

348

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

rnein yukarda verilen rnekte mod2c modlnde bulunan y1 ilevi iinde bulunan x1
ilevi arlyor olsun:
/****mod1.c
int a;

*****/

float x1()
{
a = 100;
}
mod2.c
extern int a;
extern float x1(void);
int y1()
{
float f;
f = x1();
a = 300;
/***/
}
mod2.c modlnde x1 ilevi iin yazlm olan prototip ifadesini inceleyin:
extern float x1(void);
Bu rnekte x1 ilevi baka bir modlde tanml olduu iin bildiriminde extern anahtar
szc kullanlyor . Ancak extern belirteci eklenmeseydi derleyici zaten extern
varsayacakt.
Bir global deiken hibir modlde tanmlanmadan, btn modllerde extern olarak
bildirilirse, tm modller hatasz bir ekilde derlenebilir. Hata balama aamasnda,
balaycnn extern olarak bildirilen nesneyi hibir modlde bulamamas biiminde ortaya
kar.
extern belirleyicisinin tek bir modl sz konusu olduunda "ama d" bir kullanm
vardr. Aadaki rnekte main ilevi iindeki global x deikeni, tanmlamadan nce
kullanldndan hataya neden olur.
int main()
{
/***/
x = 100;
/***/
}
int x;
/* x global bir deiken ama tanmndan daha nce kullanlm */
int func()
{
x = 200;
/***/
}

Yukardaki kod derlendiinde, main ilevinin iindeki x deikeninin bildiriminin


bulunamadn ifade eden bir hata iletisiyle karlalr. Bu durumda, eer bir global
deiken tanmlamadan kullanlyorsa, hata olumamas iin daha nce extern
bildiriminde bulunulmaldr.

349

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

extern int x;
int main()
{
/**/
x = 100;
/**/
}
int x;
int func()
{
x = 200;
/***/
}
extern bildirimini bu ekilde kullanmak yerine, global deikeni programn en banda
tanmlamak daha iyi bir tekniktir.

static Anahtar Szcnn Global Deikenler le Kullanlmas


static belirleyicisi global bir deiken ile birlikte kullanlrsa, bu deikeni i balantya
sahip yapar. Yani static anahtar szcyle tanmlanm bir global deiken i balantya
sahiptir. Byle bir deiken extern bildirimiyle projeyi oluturan dier modllerde
kullanlmaz, yalnzca kendi modlnde kullanlabilir.
Global deikenler iin static tanmlamasnn yalnzca balant zerinde etkili olduuna,
mr zerinde etkili olmadna dikkat ediniz.
Bir de u soru zerinde dnelim? Neden i balantya sahip bir global deiken
kullanmak isteyelim? Bir global deikeni kendi modlyle snrlamak ne gibi faydalar
salayabilir?

sim Kirlenmesi

Bir projeyi oluturan dosyalar iinde d balantya sahip iki varln ismi ayn olamaz.
Eer iki global varlk ayn ismi paylayorsa balama aamasnda hata oluur.
Bu da zellikle byk projeler sz konusu olduunda tehlikeli bir durumdur. Zira byk
projelerin ounda hem ok sayda programc kod yazar, hem de baka firmalar
tarafndan yazlm dosyalar da projede kullanlr. Bu durumda farkl kaynak dosyalar
global varlklara ayn isimler verilemez. Ayn isimlerin seilmesi durumunda balama
zamannda hata oluur.

Baka Modller Tarafndan Deitirilmesi stenmeyen Global


Deikenler

Bir global deiken yalnzca bir modl ilgilendiriyorsa, bu modln hizmet verdii
modlleri ilgilendirmiyorsa, programn alma zamannda dier modller tarafndan
yanllkla deitirilebilir. Baka modldeki global deikenlerle isim akmasna yol
aabilir yani isim kirlenmesine neden olabilir. Doal olan byle bir global deikenin i
balantya sahip olmasdr. Byle global deikenler static anahtar szc ile
tanmlanmaldr.

Modllerin Oluturulmas

Modl darya baz hizmetler verecek kodlarn oluturduu birimdir. C dilinde geleneksel
olarak bir modle ilikin iki ayr dosya oluturulur. Bu dosyalardan biri modln balk
dosyasdr. Bir balk dosyas bir modln arayzdr (interface). Bir modln arayz, o
modl kullanacak dosyalarn derlenmesi srasnda, derleyicinin bilmesi gereken bilgileri
salayan bildirimleri ierir. Modller daryla olan ilikilerini arayzleri ile kurar. Bir
modle ilikin dary ilgilendiren bildirimler geleneksel olarak uzants ".h" olarak

350

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

seilmi text dosyalarnda toplanrlar. "h" uzants "header" szcnn ba harfinden


gelir.
Bir modlden faydalanan bir kaynak dosya o modln balk dosyasn #include nilemci
komutuyla eklerler. Bylece tm bildirimleri derleyici grm olur.
O modle ilikin tanmlamalar ise .c uzantl ayr bir dosya iinde yer alr. Bu tanmlamalar
global deikenlerin tanmlamalar ve ilevlerin tanmlamalardr. Teknik olarak bu
dosyaya "kod dosyas" (implementation file) denir. Projede alan bir programc modln
ara yzn deitirmeden, modln kodunu yani kaynak dosyay deitirirse, projede bu
modl kullanan programclarn, kendi kodlarnda bir deiiklik yapmalar gerekmez.
Bylece nce modller ilikin arayzler belirlenir ve bu arayzlere bal olarak kaynak
dosyalar yazlrsa, kaynak dosyada bir deiim olsa da, bu kaynak dosyadaki ilevleri
aran modllerde bir deiiklik yaplmas gerekmez.

Static Anahtar Szcnn lev Bildirimlerinde ya da


Tanmlarnda Kullanlmas

levler da global varlklardr. Bir modldeki baz ilevler darya hizmet vermek iin
tanmlanr. Bu ilevler modln arayznde yani balk dosyasnda bildirilmelidir. Ancak
modlde yer alan modln kendi i ileyiinde grev yapan ilevler, darya dorudan
hizmet vermez. Bu ilevler, kodlama dosyasnda static anahtar szc ile bildirilir ve
tanmlanrl. Bu durumda static anahtar szc, ilevin geri dn deerinin trnden
nce yazlr:

static int func(int);

Tr Niteleyicileri
C de const ve volatile olmak zere iki tr niteleyicisi vardr.
[C99 standartlaryla restrict anahtar szcyle yeni bir tr niteleyicisi eklenmitir.]

const Belirleyicisi

const belirleyicisi, ilkdeer atandktan sonra nesnenin ieriinin deitirilemeyeceini


anlatr. const belirleyicisi yerel, global deikenlerle ve ilevlerin parametre
deikenleriyle birlikte kullanlabilir. const anahtar szc ile tanmlanan bir nesneye
atama ileci ile atama yaplmas geersizdir:
const double PI = 3.14159265

/* Geerli. lkdeer verme. */

int main()
{
const int i = 10;
i = 100;

/* Geersiz */

return 0;
}
Yerel bir deiken const belirleyicisi ile tanmlanacaksa ilkdeer verilmelidir, ilkdeer
verilmezse const belirleyicisi kullanmann bir anlam kalmaz. Aadaki rnei inceleyin:
void func ()
{
const int a;
/**/
}

/* anlamsz */

Bu rnekte a yerel bir deiken olduundan bir p deere sahiptir. Deikenin deeri bir
daha deitirilemeyeceine gre byle bir tanmlamann da bir anlam olamaz.

351

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

const belirleyicisinin kullanm amac nedir? Kullanld yere gre const belirleyicisi
aadaki faydalar salayabilir:
1. Programn okunabilirliini artrr. Bu ynyle kodu okuyana yardmc olur.
Program okuyanlar const anahtar szcn grdklerinde nesnenin deerinin
deitirilmeyecei bilgisini alrlar.
2. Yanllkla nesnenin deerinin deitirilmesi engellenir. Bu ynyle kodu yazana
yardmc olur. const bir nesnenin deeri atama yoluyla deitirlmesi durumunda derleme
zamannda hata oluur. Bylece deeri deitirilmemesi gereken bir nesnenin deerinin
yanllkla atama yoluyla deitirilmesi de engellenmi olur.
3. const anahtar szc ile tanmlanan nesneler, derleyici tarafndan salt okunan
bellekte saklanabilirler. Derleyici const nesnenin deerinin deitirilmeyeceini
bilmediinden, bu nesnelerin kullanld ifadeler iin ek eniyileme(optimizasyon)
ilemleri uygulayabilir. const anahtar szc bu ynyle derleyiciye yardmc olur.

const Nesnelerle Simgesel Deimezlerin Karlatrlmas

const nesneler deeri deimeyecek deimezler gibi kullanldklarna gre, bunlarn


yerine ou zaman #define nilemci komutuyla oluturulmu simgesel deimezler de
kullanlabilir.
Ancak const nesneler ile simgesel deimezler arasnda baz farkllklar vardr. kisi
arasnda tercih yaplmas durumunda bu farkllklar rol oynar:
1. Simgesel deimezler nesne deildir. Bu yzden programn alma zamannda
bellekte bir yer kaplamazlar. Nesne olmadklar iin bilinirlik alanlar, mrleri ve balant
zelliklerinden sz edilemez. Derleme aamasna gelindiinde derleyici simgesel
deimezlerin yerine, nilemci tarafndan yerletirilen atomlar grr.
2. Derleyiciler const nesneler iin daha iyi "debugging" destei verirler.
3. Derleyiciler derleme zamannda bir hata olumas durumunda hatann yerini iaretleme
konusunda const nesneler iin daha iyi destek verirler.
4. Bir dizi const anahtar szc ile tanmlanabilir. Bu durumda dizinin keli ayra ileci
ile ulalan herhangi bir elemanna atama yaplamaz. Byle bir durumu nilemci #define
komutuyla kolaylkla gerekletirmek mmkn deildir:
void foo
{
const char alphabet[] = "abcdefghijklmnopqrstuvwxyz";
alphabet[2] = 'X';
/* GEERSZ*/
}
5. C'de const nesneler d balantya sahiptir. Bir const nesne, extern bildirimi yaplarak
baka modllerde kullanlabilir.
6. C dilinde const nesneler deimez ifadesi olarak kullanlamazlar. Aadaki rnei
inceleyin:
#define

SIZE

100

int main()
{
const int size = 100;
int legal_array[SIZE];
int illegal_array[size];
/***/
}

/* GEERSZ size deimez ifadesi deil */

352

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

const Anahtar Szcnn Gsterici Tanmlamalarnda


Kullanlmas:

const anahtar szc sklkla gsterici nesnelerinin tanmlamalarnda kullanlr.


const anahtar szcnn gstericilerle birlikte ayr kullanlma biimi vardr.
Kullanlan her biimde tanmlanan gstericinin zellii deiir.
1. const anahtar szcnn '*' atomundan nce kullanlmas:
Byle gstericilere gsterdii yer const olan gstericiler (pointer to const objects) denir.
Byle bir gstericinin gsterdii nesne, gstericinin ierii alnarak elde edilen nesneye
atama yaplmas yoluyla deitirilemez. Ancak gstericinin kendisine atama yaplabilir.
Yani gstericinin bir baka nesneyi gstermesi salanabilir. Aadaki rnei inceleyin:
int main()
{
int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
double d1 = 2.5, d2 = 3.5;
char str[] = "Necati";
int x = 20;
const int *iptr = a;
double const *dptr = &d1;
const char *cptr = str;
/*
*iptr = 100;
Geersiz!
*dptr = 1.23;
Geersiz!
cptr[1] = 'x'; Geersiz!
*/
iptr = &x;
dptr = &d2;
cptr = "Selami";
}

return 0;

Yukardaki main ilevinde tanmlanm, gsterdii yer const olan gstericiler iin yaplan
*iptr = 100;
*dptr = 1.23;
cptr[1] = 'x';
atamalar derleme zamannda hata oluumuna neden olur. Ancak gstericilerin
kendilerine yaplan
iptr = &x;
dptr = &d2;
cptr = "Selami";
atamalarnn tamamen kurallara uygun olduunu gryorsunuz.
const anahtar szcnn gstericilerle birlikte kullanlmasnda en sk grlen biim
budur ve zellikle ilevlerin parametre deikenleri olan gstericilerle bu biim kullanlr:
void func(const char *str)
{
/***/
}
Yukarda func isimli ilevinin parametre deikeni olan str gstericisi deerini ilevin
arsyla alr. lev ar ifadesindeki argman ilevin arlmasyla s gstericisine

353

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

kopyalanr. Ancak ilev iinde *s nesnesine ya da s[x] nesnesine bir atama yaplamaz.
Yani s gstericisinin gsterdii yerdeki nesne (ileve adresi gnderilen nesne)
deitirilemez. Yukardaki rnekte const anahtar szcnn kullanlmas hereyden nce
okunabilirlik ile ilgilidir. Yukardaki kodu okuyan bir C programcs func ilevinin dardan
adresi alnan nesnenin yalnzca deerinden faydalanlacan, yani bu nesnenin deerini
deitirmeyeceini anlar. Geleneksel olarak, const anahtar szcnn, parametre
deikeni olan gstericilerin tanmlanmasnda kullanlmamas okunabilirlik asndan bir
ileti olarak kabul edilir:
void func(char *s)
{
/***/
}
Yukardaki kodu okuyan bir C programcs func ilevinin (aslnda sentaks asndan bir
zorunluluk bulunmasa da) kendisine adresi gnderilen nesneyi deitireceini anlar. Kodu
okuyan kii yle dnr: Eer func ilevi adresi gnderilen nesneyi deitirmeyecek
olsayd, s gstericisi const anahtar szc ile tanmlanrd.
2. const anahtar szcnn '*' atomundan sonra kullanlmas:
Bu ekilde tanmlanm gstericilere kendisi const gsterici (const pointer) denir. Bu
gstericilere ilkdeer olarak verilen adres atama yoluyla deitirilemez. Yani gsterici
mr boyunca ayn nesneyi gsterir. Ancak gstericinin gsterdii nesneyi, gstericinin
ieriini alarak deitirmek mmkndr. const anahtar szcnn bu kullanm biiminde
gsterici tanmlanrken ilkdeer verilmelidir, yoksa const anahtar szcnn
kullanlmasnn bir anlam kalmaz. Aadaki rnei inceleyin:
int main()
{
int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
double d1 = 2.5, d2 = 3.5;
char str[] = "Necati";
int x = 20;
int *const iptr = a;
double *const dptr = &d1;
char *const cptr = str;
*iptr = 100;
*dptr = 1.23;
cptr[1] = 'x';
/*
iptr = &x;
dptr = &d2;
cptr = "Selami";
*/
}

Geersiz!
Geersiz!
Geersiz!

return 0;

3. const anahtar szcnn hem '*' atomundan nce hem de '*' atomundan sonra
kullanlmas:
Bu durumda hem kendisi const hem de gsterdii yer const olan bir gsterici tanmlanm
olur. Atama ileciyle ne gstericiye ne de gstericinin ierii alnarak elde edilen nesneye
atama yaplabilir. const szcnn bu biimde kullanlmas yine daha ok parametre
deikenlerinin tanmlanmasnda grlr ise de bu uygulamalarda seyrek olan bir
durumdur. Aaadaki rnei inceleyin:

354

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

int main()
{
int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
double d1 = 2.5, d2 = 3.5;
char str[] = "Necati";
int x = 20;
const int *const iptr = a;
const double *const dptr = &d1;
const char *const cptr = str;
/*
*iptr = 100;
Geersiz!
*dptr = 1.23;
Geersiz!
cptr[1] = 'x';
Geersiz!
iptr = &x;
dptr = &d2;
cptr = "Selami";
}

Geersiz!
Geersiz!
Geersiz!

return 0;

Gstericiyi gsteren bir gstericinin const anahtar szc ile bildirilmesinde const
anahtar szcnn kullanlmas farkl olanaklar yaratr:
const char **ptr;
ptr nin gsterdii gstericinin gsterdii nesneye atama yaplamaz. const olan **ptr
nesnesidir. ptr nesnesine ve *ptr nesnelerine atama yaplabilir. (pointer to pointer to
const object)
char *const *ptr;
*ptr nin gsterdii gstericiye atama yaplamaz. const olan *ptr nesnesidir. ptr nesnesine
ve **ptr nesnelerine atama yaplabilir.
char ** const ptr;
ptr ye atama yaplamaz. const olan ptr nesnesidir. **ptr nesnesine ve *ptr nesnelerine
atama yaplabilir.
const char *const *ptr;
yalnzca ptr nesnesine atama yaplabilir.
char *const * const ptr;
yalnzca **ptr nesnesine atama yaplabilir.
const char ** const ptr;
yalnzca *ptr nesnesine atama yaplabilir.

Bir ilevin Geri Dn Deerinin const Adres Olmas

Adrese geri dnen bir ilevin geri dn deeri const bir adres olabilir:
const char *get_name(void);
Yukarda bildirimi yaplan get_name ilevinin geri dn deeri const bir adrestir. Peki bu
ne anlama gelir? Bir ilevin geri dn deeri trnn aslnda, geri dn deerini iinde
tutacak geici nesnenin tr olduunu biliyorsunuz. get_name ilevinin geri dn
deerini tutacak geici nesnenin tr const char * trdr. Yani geici nesne gsterdii
yer const olan bir gstericidir. lev ars, ilevin geri dn deerini, yani geici
nesnenin deerini gsterdiine gre, byle bir ileve yaplan ar ierik ilecine ya da

355

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

keli ayra ilecine terim olduunda, ulalan nesneye atama yaplamaz. Aadaki
rnei inceleyin:
char *get_name();
const char *get_fname();
int main()
{
*get_name() = 'a';
get_name()[2] = 'x';
*get_fname() = 'a';
get_fname()[2] = 'x';
}

/* Geersiz
/* Geersiz

*/
*/

return 0;

Yukarda main ilevi iinde arlan get_name() ilevinin geri dndrd adresteki
nesneye 'a' deeri atanyor. Yine get_name()[2] ifadesi ile ilevin dndrd adresteki
nesneden iki sonraki nesneye ulalarak bu nesneye de 'x' deeri atanyor. Atamalar
geerlidir. Ancak geri dn deeri const char * trden olan get_fname ilevi iin benzer
atamalar geersizdir, derleme zamannda hata oluturur.

volatile Belirleyicisi
Derleyiciler eniyileme amacyla nesneleri geici olarak yazmalarda tutabilir.
Yazmalardaki bu eit geici barnmalar register belirleyicisi kullanlmasa da derleyiciler
tarafndan yaplabilir. rnein:
int kare (int a)
{
int b;
b = a * a;
return b;
}
Yukardaki ilevde b geici bir deikendir, dolaysyla derleyici b deikenini bellekte bir
yerde saklayacana, geici olarak yazmalarndan birinde saklasa da ilevsel bir farkllk
ortaya kmaz. Bu eit uygulamalarda derleyicinin deikenleri geici olarak yazmalarda
saklamas ilemleri hzlandrr. Aadaki kodu inceleyin:
int a;
int b;
/***/
a = b;
if (a == b) {
/***/
}
Bu rnekte doal olarak ilk admda b deikeni a deikenine aktarlmak zere
yazmalardan birine ekilir. Ancak derleyici if ayrac iindeki ifadede a == b
karlatrmasn yapmak iin bellekteki b yerine yazmataki b'yi kullanabilir. Verdiimiz
iki rnekte de derleyici bir takm eniyileme ilemleriyle program ilevi deimeyecek
biimde daha hzl alr hale getirmek istemitir. Ancak kimi uygulamalarda derleyicinin
bu biimde davranmas hatalara neden olabilir. kinci rnekte :

356

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

a = b;
/* Bir kesme gelerek b'yi deitirebilir!
if (a == b) {
/***/
}

*/

Bir donanm kesmesi (rnein 8h gibi) b'yi deitiriyorsa, bu durum if deyimi tarafndan
farkedilmeyebilir. te bu tr durumlarda deikenlerin eniyileme amacyla geici olarak
yazmalarda tutulmas arzu edilmeyen sonularn olumasna yol aabilir. volatile "
Deikenleri eniyileme amacyla yazmalarda bekletme, onlar bellekteki gerek
yerlerinde kullan!" anlamna gelen bir tr belirleyicisidir. Bu anlamyla volatile
belirleyicisini register belirleyicisi ile zt anlaml olarak dnebiliriz. Yukardaki rnekte b
deikenini volatile olarak bildirerek anlattmz gibi bir problemin kmas engellenebilir.
int a;
volatile int b;
volatile ok zel uygulamalarda kullanlabilen bir belirleyicidir.
Yerel, parametre ya da global deikenlerle birlikte kullanlabilen volatile belirleyicisi
ancak ok zel uygulamalarda nemli olabilir. Bu belirleyicinin bilinsizce kullanlmasnn
performans kt ynde etkileyebileceini unutmaynz.

357

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

YAPILAR
Yap nedir

Yaplar (structures) programcnn birden fazla nesne yaratmasna izin veren bir aratr.
Yaplarn kullanlmasyla bellekte birbirini izleyecek ekilde yer alan birden fazla nesne
yaratlabilir. Bellekte bitiik olarak yer alan nesnelerin dizi tanmlamalaryla da
yaratlabileceini biliyorsunuz. Ancak yaplarn dizilerden baz farkllklar vardr: Diziler
ayn trden nesneleri iinde tutabilirken, yaplar farkl trlerden nesneleri tutabilir.
Yaplarn kullanlmasnn ana nedeni budur. ou zaman, trleri farkl bir takm nesneler,
mantksal olarak bir btn oluturabilir. sim, ya, cinsiyet, departman, cret, renim
durumu gibi bilgileri farkl trden nesneler iinde saklanabilir. Bunlarn tamam bir
iyerinde alan bir kiiye ait bilgiler olabilir. Aralarnda mantksal iliki olan farkl trden
veriler yaplar iinde saklanabilir.
int trden 10 elemanl bir dizi tanmlandn dnelim:
int a[10];
Kullanlan sistemde int trnn 4 byte yer kapladn dnrsek bu dizi iin bellekte 40
byte'lk bir blok ayrlr deil mi? Programc bu dizinin elemanlarna keli ayra ileci ile
ulaarak, eleman olan nesneler zerinde dorudan ilemler yapabilir. Ancak dizinin
tamam bir nesne olarak kullanlamaz. Yani C dili bir dizinin tamamn bir nesne olarak
grmez. Dizi isimlerinin, C'de dizinin ilk eleman olan nesnenenin adreslerine
dntrldklerini hatrlayalm. Yaplarda durum biraz daha farkldr. Yap kullanlmasyla
da birden fazla nesne iin ardl bir blok ayrlr. Ancak bu kez bloun tamam da bir
nesne olarak kullanlabilir. Yapnn eleman olan nesneler zerinde ilemler
yapabileceimiz gibi, bu nesnelerin oluturduu bloun tamam zerinde de dorudan
baz ilemler yapabiliriz.

Programcnn Tanmlad Bir Tr Olarak Yap

Yaplarn kullanlmasyla programc yeni bir tr yaratabilir. C'nin var olan doal veri
trlerinin yannda, mantksal bir anlam soyutlayan yeni trler yaratlabilir. rnein deeri
bir tarih bilgisi olan bir tr ya da deeri bir kompleks say olan bir tr oluturulabilir.
Bylece programlama ile bir zm oluturmak istediimiz problem dzlemi daha iyi
modellenebilir. Yaplarn iyi bir ekilde renilmesi, ileride nesne bazl(object based) ve
nesneye ynelimli (object oriented) programlama tekniklerinin iyi bir biimde
anlalabilmesine yardmc olur.

Yap Bildirimi

Yap ile programcnn yeni bir tr yaratmasna olanak verilir. Yaplarn kullanlabilmesi iin
yaplmas gereken ilk ilem bu yeni tr derleyiciye tantmaktr. Tantma ilemi yap
bildirimi ile olur. Yap bildirimini gren derleyici, bu yeni tr hakknda bilgi edinmi olur.
Bu bildirimle derleyiciye aadaki bilgiler verilir:
- trn ismi
- trn bellekte ne kadar yer kaplad
- elemanlarn isimleri
Derleyici bir yap bildirimini grdkten sonra, bu trden bir nesne tanmlandnda nesne
iin bellekte ne kadar yer ayracan rendii gibi, bu nesnenin programc tarafndan
kullanmna ilikin ifadelere ilikin derleme zamannda baz snamalar yapabilir.
Yap bildiriminin belirli bir sentaks vardr.

359

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yap Bildiriminin Genel ekli


<struct >
<tr>
<tr>
<tr>
...
};

[yap etiketi] {
<eleman ismi>;
<eleman ismi>;
<eleman ismi>;

struct bir anahtar szcktr. Bildirimde mutlaka yer almas gerekir. struct anahtar
szcn bir yap etiketi (structure tag) izleyebilir. Yap etiketi C dilinin isimlendirme
kurallarna uygun olarak seilmi bir isimdir. Yap etiketinden sonra bir blok yer alr. Bu
blok bildirime ak bir blge belirler. Bu blok iinde yap elemanlarnn bildirimleri yaplr.
rnek verelim:
struct Date {
int day, month, year;
};
struct Point {
int x, y;
};
struct Complex {
double real;
double imag;
};
Yap etiketleri (structure tags) isimlendirme kurallarna uymaldr. Ancak programclarn
ou yap etiketlerinin ilk harflerini byk, dier harflerini kk seerler.
Yap bildiriminin yaplmas bellekte derleyici tarafndan bir yer ayrlmasna neden olmaz.
Yani bir tanmlama (definition) sz konusu deildir. Bu bildirimle programcnn yaratt
yeni bir veri tr hakknda derleyiciye bilgi verilir. Derleyici bu bilgiyi, bu trden
yaratlacak nesneler iin ablon olarak kullanr.
Yukardaki bildirimlerle yaratlm olan trlerin ismi srasyla, struct Sample, struct Date,
struct Point ve struct Complex'dir. Yani tr ismi struct anahtar szc ve yap etiketinin
birletirilmesiyle elde edilir. Yap etiketi tek bana bir tr bilgisi belirtmez. Ancak struct
anahtar szc olmadan da bir tr ismi yaratlmasn salayan aralar da ileride
greceimizi imdiden belirtelim.

Yap Bildirimlerinin Yeri

Tm bildirimler gibi yap bildirimleri de yerel ya da global dzeyde yaplabilir. Tm


bildirimler gibi yap bildirimlerinin de bilinirlik alan vardr. Bildirim bir blok iinde
yaplrsa, bildirilen yap yalnzca bildirimin yapld blok iinde bilinir.
Yap bildirimleri ancak ok zel durumlarda bir blok iinde yaplr. Kaynak dosya iindeki
tm ilevlerin yeni yaratlan tr kullanabilmeleri iin, bildirim hemen her zaman global
dzeyde yaplr. Tanmlanan ilevleri aracak dier kaynak dosyalar da, ou zaman
ayn yapy kullanmak zorunda olduundan, yap bildirimleri genellkle modllerin balk
dosyalarna yerletirilir. Bylece ilgili balk dosyasn ekleyen bir kaynak dosya iinde de
ayn bildirim yaplm olur.

Yap Trnden Deiken Tanmlamas

Doal trlerden nesneler nasl tanmlanyorsa yap trnden bir deikenin tanmlanmas
da ayn szdizimle olur. Yani nce tr belirten szckler daha sonra da yap deikeninin
ismi yazlr:

360

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

struct Date bdate;


struct Point p1, p1;
Yukardaki tanmlamalarn ilgili yap bildirimlerinin grlr olduu bir noktada yapld
kabul ediliyor. Yap bildiriminin grlmedii bir kaynak kod noktasnda yap deikeni
tanmlanmas geersizdir.
struct Date mydate;
tanmlamasyla ismi mydate olan tr struct Date olan bir deiken tanmlanyor.
struct Point p1, p2, p3;
tanmlamasyla trleri struct Point olan p1, p2 ve p3 isminde ayr deiken
tanmlanyor.
Nesnelerin temel zellikleri nesnelerin trne bal deildir. phesiz yap nesnelerinin de
bilinirlik alanlarndan, mrlerinden, balant zelliklerinden sz edilebilir. Bu zellikler
doal veri trleri iin ne anlam tayorlarsa yap nesneleri iin de ayn anlam tar.
Global isim alannda tanmlanan bir yap nesnesi
i) Dosya bilinirlik alanna aittir. Nesnenin tanmndan sonra yer alan tm ilevler bu yap
nesnesine ulaabilirler.
ii) Statik mrldr. Programn alma zamannn balangcndan, programn
sonlanmasna kadar bellekte yer kaplar.
iii) Statik mrl olduu iin ilkdeer atamas yaplmad zaman, bellekte kaplad
btn byte lar 0 bitleriyle doldurulur. Pratik olarak bunun anlam yapnn tm
elemanlarnn deerinin 0 olmasdr.
Yerel alanda tanmlanan bir yap nesnesi
i) Blok bilinirlik alanna aittir. Yalnzca tanmlamasnn yapld blok iinde bu nesneye
ulalabilir.
ii) Otomatik mrldr. Programn ak, nesnenin tanmland bloa girdiinde nesne
yaratlr. Programn ak nesnenin tanmlad blou terk ettiinde nesne bellekten
boaltlr.
iii) Otomatik mrl olduu iin ilkdeer atamas yaplmad zaman, bellekte kaplad
alanda p deerleri vardr. Pratik olarak bunun anlam yapnn tm elemanlarnn p
deerleriyle balatlmasdr.
Yap nesnelerinin bildirim ve tanmlamalarnda belirleyiciler kullanlabilir.
rnein yerel ya da global bir yap nesnesi static ya da const belirleyicisi ile
tanmlanabilir. Bu belirleyicilerin bildirim ya da tanmlamalara katt anlamlar yap
nesneleri iin bir farkllk tamazlar.
Yap deikenleri bileik nesnelerdir. Yani paralardan, alt nesnelerden oluurlar. Zaten
yap bildirimi ile yaplan bir ilem de bu paralarn isimleri ve trleri hakknda derleyiciye
bilgi verilmesidir. Bir yap deikeni (nesnesi) iin, yap bildiriminde belirtilen elemanlarn
toplam uzunluu kadar (byte olarak) yer ayrlr. Aadaki rnei inceleyin:

361

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
struct Sample {
int i;
long l;
double d;
};
int main()
{
struct Sample sam;
printf("%d\n", sizeof(sam));
}

return 0;

Yukardaki program UNIX altnda altnda ekrana 16 deerini yazdrr. nk struct


Sample trnden bir nesne olan sam nesnesinin bellekte kaplad yer elemannn
kaplad uzunluun toplamdr. Bu aadaki ekilde de ifade edilebilir:
sizeof(sam) == sizeof(int) + sizeof(long) + sizeof(double)
Hizalama (alignment) konusunda yeniden bu noktaya deininilecek.

Yap Bildirimi le Deiken Tanmlamasnn Birlikte Yaplmas

Bir yap bildirimi sonlandrc atom ile sonlandrlmadan, yap bildiriminin kapanan kme
ayracndan hemen sonra bir deiken listesi yazlrsa yap bildirimi ile deiken
tanmlamas bir arada yaplm olur.
struct Date {
int day, month, year;
}bdate, edate;
Yukardaki deyim ile struct Date tr bildirilirken bu yap trnden bdate ve edate
deikenleri de tanmlanyor. Bu durumda yap deikenlerinin bilinirlik alanlar yap
bildiriminin yerletirildii yere bal olarak belirlenir. Yani sz konusu yap deikenleri
yerel ya da global olabilir.
Yap nesnelerinin hemen yap bildiriminden sonra tanmlanmas durumunda yap ismi
kullanma zorunluluu da bulunmaz. rnein yukardaki bildirim aadaki ekilde de
yaplabilir.
struct {
int day, month, year;
} bdate, edate;
Burada bdate ve edate yukarda bildirilen ama isimlendirilmeyen yap trnden
deikenlerdir. Bu yntemin dezavantaj artk ayn trden baka bir yap deikeninin
tanmlanmasnn mmkn olmaydr. rnein yukardaki kod parasndan sonra ayn
yap trnden bir yap nesnesi daha tanmlamak istediimizi dnelim. Bu tanmlama
struct {
int day, month, year;
}cdate;
biiminde yaplsa bile artk derleyici, bildirimleri edeer olan bu iki yap trn ayr yap
trleri olarak ele alr. Dolaysyla
cdate = bdate;

362

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

gibi bir atama yap trlerinin farkl olmas nedeniyle geerli deildir.
Byle bir tanmlamann baka bir dezavantaj da, bu yap tryle ilgili bir ilev
yazlamaydr. nk yap trnn bir ismi yoktur. Bir ilevin parametre deikeni tr
bilgisi olmadan tanmlanamaz.

Yaplar ve sim Alanlar

Yap isimleri ve yap elemanlarnn isimleri ayr isim alanlarnda deerlendirilir:


Aadaki kod geerlidir:
void func()
{
struct x {int x;}x;
}

Yap Elemanlarna Eriim

Yaplarn dizilerden nemli bir fark da elemanlara eriim konusundadr. Dizi elemanlarna
eriim, dizi ismi ve keli ayra ileci [ ] (index operator - subscript operator) yoluyla
yaplrken, yap elemanlarna eriim iin nokta ileci kullanlr.
Nokta ilecine (dot operator) ilikin atom '.' dr. Nokta ileci, iki terimli araek
konumunda (binary infix) bir iletir. Bu ilecin sol terimi bir yap trnden nesne
olmaldr. lecin sa terimi ise nesnenin ait olduu ilgili yap trnnn elemanlarndan
biri olmak zorundadr. Nokta ileci ile ncelik tablosunun en yksek ncelikli dzeyinde
bulunur.
Bir yap nesnesi tanmlanarak, bu yap nesnesinin elemanlarna nokta ileci ile
eriildiinde artk bu elemanlarn her biri ayr bir nesne olarak ele alnr. Bu nesnelerin,
yap dnda tanmlanan nesnelerden herhangi bir fark yoktur. Aadaki kodu derleyerek
altrn:
#include <stdio.h>
struct Sample{
int i;
long l;
double d;
};
int main()
{
struct Sample sam;
sam.i = 10;
sam.l = 200000L;
sam.d = 1.25;
printf("sam.i = %d\nsam.l = %ld\nsam.d = %lf\n", sam.i, sam.l, sam.d);
return 0;
}
Yukardaki rnekte grld gibi sam.i, sam.l ve sam.d yap elemanlar ayr birer nesne
zellii gsterir. Bu elemanlara ayr ayr ulaabilir, ayr ayr atamalar yaplabilir. Bu
nesneler ++ ve -- ilelerinin ya da adres ilecinin terimi olabilir.

Yap Elemanlarnn Bellekteki Yerleimi

Yap elemanlar bellee, bildirimde ilk yazlan eleman kk saysal adreste olacak
biimde, bitiik olarak yerletirilir. Aadaki program derleyerek altrn:

363

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

struct Sample{
int i;
long l;
double d;
};

#include <stdio.h>
int main()
{
struct Sample sam;
printf("sam.i'nin adresi = %p\n", &sam.i);
printf("sam.l'nin adresi = %p\n", &sam.l);
printf("sam.d'nin adresi = %p\n", &sam.d);
}

return 0;

Yap Nesneleri zerinde Yaplabilecek lemler

Yap nesnelerinin elemanlar deil de kendileri sz konusu olduunda, yani bir yap
nesnesi bir btn olarak ele alndnda ancak drt ilecin terimi olabilir: nokta ileci,
sizeof ileci, adres ileci, atama ileci. Bir yap nesnesinin bunlarn dnda bir ilecin
terimi olmas geersizdir.

sizeof leci ve Yaplar

Bir yap nesnesi sizeof ilecinin terimi olabilir. Bu durumda sizeof ilecinin rettii deer,
nesnenin ait olduu trn bellekte kaplad byte saysdr. Tabi sizeof ilecinin teriminin
bir tr ismi de olabileceini biliyorsunuz. Aadaki rnei inceleyin:
struct Point {
int x, y;
};
int main()
{
struct Point p;
printf("sizeof(struct Point) = %u\n", sizeof(struct Point));
printf("sizeof(p) = %u\n ", sizeof(p));
}

return 0;

Yukardaki main ilevini iinde yaplan printf arsnda sizeof ilecinin terimi bir tr ismi
(struct Point) iken, ikinci printf arsnda ise sizeof ilecinin terimi struct Point trnden
bir nesne olan p dir.

Adres leci ve Yap Nesneleri

Bir yap nesnesi adres ilecinin terimi olabilir. Bu durumda adres ilecinin rettii deer
ilgili yap trnden bir adres bilgisidir:
struct Date isimli bir yapnn bildiriminin yaplmasndan sonra aadaki gibi bir nesne
tanmlandn dnelim:

364

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

struct Date {
int d, m, y;
};
struct Date mydate = {4, 3, 1964};
&mydate
ifadesi geerli bir ifadedir. Bu ifade (struct Date *) trndendir.
Peki &mydate ile &mydate.day ayn adresler midir? Bu adreslerin saysal bileenleri ayn
olmakla birlikte tr bileenleri farkldr. ki ifade, saysal bileenleri ayn olan farkl trden
iki adres bilgisidir.
&mydate ifadesinin tr (struct Date *) iken &mydate.day ifadesinin tr (int *) trdr.

Atama leci ve Yap Nesneleri

Bir yap nesnesi atama ilecinin sol ya da sa terimi olabilir.


Bir yap nesnesine atama ileci ile ancak ayn trden baka bir yap nesnesi atanabilir.
Atama ilecinin sandaki ve solundaki trlerin farkl yap trlerinden olmas geersizdir.
Ayn trden iki yap nesnesinin birbirine atanmasnda yap elemanlar karlkl olarak
birbirlerine atanr. Yani bir blok kopyalanmas sz konusudur. Atama ilemi iin kesinlikle
iki yap deikeninin de ayn trden olmas gerekir. ki yap deikeni de ayn trden
deilse bu durum geersizdir. ki yapnn ayn trden olmalar iin ayn yap ismi ile
tanmlanm olmalar gerekir. Aadaki iki yap, elemanlarnn trleri ve isimleri ayn
olduu halde farkl iki tr belirtirler ve bu trlerden nesneler birbirlerine atanamaz.
struct POINT_1 {
int x, y;
};
struct POINT_2{
int x, y;
};
void func()
{
struct POINT_1 a;
struct POINT_2 b;
b.x = 10;
b.y = 20;
a = b; /* Geersiz */
}
ki yap nesnesinin birbirine atanmas, nesnelerin tm elemanlarnn karlkl olarak
birbirlerine atanmas sonucunu dourur. Yani bir blok kopyalamas sz konusudur.
zellikle byk yaplar sz konusu olduunda atama ileci ile yap nesnelerini birbirine
atanmasnn maliyetinin yksek olduu unutulmamaldr. lgili yap trnn sizeof deeri
byklnde bir bellek blou, adeta memcpy benzeri bir ilevle kopyalanr.
Aadaki program derleyerek altrn:
#include <stdio.h>
#include <string.h>
struct Data{
int i;
long l;
double d;
};

365

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

int main()
{
struct Data d1, d2, d3, d4;
d1.i = 10;
d1.l = 200000L;
d1.d = 1.25;
d2 = d1;
d3.i = d2.i;
d3.l = d2.l;
d3.d = d2.d;
memcpy(&d4, &d3, sizeof(struct Data));
printf("d1.i
printf("d2.i
printf("d3.i
printf("d4.i

=
=
=
=

%d\nd1.l
%d\nd2.l
%d\nd3.l
%d\nd4.l

=
=
=
=

%ld\nd1.d =
%ld\nd2.d =
%ld\nd3.d =
%ld\nsam4.d

%lf\n\n", d1.i, d1.l, d1.d);


%lf\n\n", d2.i, d2.l, d2.d);
%lf\n\n", d3.i, d3.l, d3.d);
= %lf\n\n", d4.i, d4.l, d4.d);

return 0;
}
Yukardaki main ilevinde struct Sample trnden d1, d2, d3, d4 isimli 4 deikenin
tanmlandn gryorsunuz. d2 deikenine atama ileci kullanlarak d1 deikeninin
deeri atanyor. d4 deikenine de standart memcpy ilevi kullanlarak d3 nesnesinden
kopyalama yaplyor.

Tr Dntrme leci ve Yap Nesneleri

Bir yap nesnesi tr dntrme ilecinin terimi olamaz. Yani aadaki gibi bir kod da
geersizdir:
struct S1 {
int a, b;
};
struct S2 {
int a, b;
};
void func()
{
struct S1 s1;
struct S2 s2;

s1.a = 10;
s1.b = 20;
s2 = (struct S2)s1;

/* Geersiz! */

Yap Elemanlarnn Bellekteki Yerleimi

Yap elemanlar bellee, bildirimde ilk yazlan eleman kk adreste olacak biimde,
bitiik olarak yerletirilir. Aadaki program derleyerek altrn:

366

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
struct Date {
int day, mon, year;
};
int main()
{
struct Date date;
printf("date.day'in adresi = %p\n", &date.day);
printf("date.mon'un adresi = %p\n", &date.mon);
printf("date.year'in adresi = %p\n", &date.year);
return 0;
}

Yap Eleman Olarak Dizilerin Kullanlmas

Yapnn bir eleman herhangi trden bir dizi olabilir. Bu durumda da yapnn dizi
elemannn ismi bir nesne belirtmez, bir adres bilgisidir. nce aadaki rnei inceleyin:
#include <stdio.h>
#define

NAME_LEN

20

struct Person {
char name[NAME_LEN];
int no;
};
int main()
{
struct Person per;
gets(per.name);
puts(per.name);
putchar(per.name[3]);
per.name++
return 0;

/* Geersiz. Dizi ismi nesne deildir. */

}
Bildirilen struct Person yapsnn bir eleman char trden 20 elemanl bir dizidir. Bu
durumda kaynak kodumuz Unix iletim sisteminde derlendiinde, sizeof(struct Person)
24 olur. Tanmlanan her struct Person trnden nesnenin iinde 20 elemanl char trden
bir dizi yer alr.
main ilevi iinde kullanlan per.name ifadesi, per yap nesnesinin iinde yer alan char
trden dizinin balang adresidir. Bu ifade ileme sokulduunda, derleyici tarafndan
otomatik olarak char * trne dntrlr.
gets(per.name);
arsyla gets ilevine, per nesnesi iindeki char trden name dizisinin balang adresi
geiliyor. Bylece klavyeden alnan yaz nesnenin iindeki diziye yerletiriliyor.
puts(per.name);
arsyla da benzer biimde bu dizinin iindeki yaz ekrana yazdrlyor.

367

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Ancak istenirse, nesnenin iindeki dizinin herhangi bir elemanna keli ayra ileci ya da
ierik ileci ile ulalabilir:
per.name[3]
*(per.name + 3)
ifadelerinin tr char trdr. Bu ifadeler per nesnesinin iindeki name dizisinin 3 indisli
eleman olan char trden nesneye karlk gelir.
struct Person trnden bir dizinin iinde tutulan yaznn uzunluu ne olursa olsun, struct
Person trnn sizeof deeri deimez. Baz durumlarda, yap nesneleri iinde yer alan
diziler, yap nesnesinin boyutunu gereksiz bir biimde artrd iin tercih edilmez.
Bir yapnn eleman neden bir dizi olur? Bu yolla bir yap nesnesi iinde ayn trden belirli
sayda deer tutulabilir. Bir renciye ilikin bilgilerin, bir yap tr ile modellendiini
dnn. Byle bir yapnn iinde, rencinin notlarn iinde tutacak int trden bir dizi
yer alabilir. Ancak uygulamalarda en ok grlen durum, yaz bilgilerinin yap iinde yer
alan char trden diziler iinde tutulmasdr.
Ayn trden belirli sayda deerin bir yap nesnesine bal olarak tutulmas iin, bir baka
yol da yapnn bir elemannn bir gsterici olmasdr.

Yap Eleman Olarak Gsterici Deikenlerin Kullanlmas

Yapnn bir eleman herhangi trden bir gsterici olabilir. Aadaki rnei inceleyin:
#include <stdio.h>
struct Person {
char *name_ptr;
int no;
};
int main()
{
struct Person per;
per.name_ptr = "Necati Ergin";
per.no = 125;
printf("%s %d\n", per.name_ptr, per.no);
}

return 0;

Yukardaki kod parasnda bu kez struct Person trnn bir eleman char trden bir
gsterici olarak seiliyor. Bir gsterici kullanlan sistemde 2 ya da 4 byte yer
kaplayacana gre yukardaki struct Person yapsnn sizeof deeri UNIX altnda 8 byte
olur.
per.name_ptr = "Necati Ergin";
fadesi ile per nesnesinin name_ptr isimli elemanna "Necati Ergin" dizgesi atanyor.
Dizgelerin birer adres bilgisi olduunu, derleyici tarafndan char * trnden ifadeler
olarak deerlendirildiklerini biliyorsunuz.
per.name_ptr
char * trden nesne gsteren bir ifadedir. Bu ifade per nesnesi iinde yer alan char
trden gsterici deikene karlk gelir.
Bu gstericinin gsterdii yere yani

368

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

*per.name_ptr
per.name_ptr[n]
ifadelerine gsterici hatas oluturmadan atama yapabilmek iin, nce eleman olan
gstericinin gvenilir bir yeri gstermesi gerekir.
Bir yapnn elemannn bir gsterici olmas ou zaman, yap nesnesinin dinamik olarak
elde edilen bir bellek alann kullanmas amacyla istenir. Aadaki kod parasn
inceleyin:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define

ARRAY_SIZE

100

struct Person {
char *name_ptr;
int no;
};
int main()
{
struct Person per;
char name_entry[ARRAY_SIZE];
printf("ismi giriniz : ");
gets(name_entry);
per.name_ptr = (char *)malloc(strlen(name_entry) + 1);
if (per.name_ptr == NULL) {
printf("bellek tahsis edilemiyor!\n");
exit(EXIT_FAILURE);
}
strcpy(per.name_ptr, name_entry);
printf("numarayi giriniz : ");
scanf("%d", &per.no);
printf("isim = %s\nNo : %d\n", per.name_ptr, per.no);
/*...*/
free(per.name_ptr);
}

return 0;

main ilevi iinde yaplanlar srasyla inceleyelim: nce struct Person trnden per isimli
bir deikenin tanmlandn gryorsunuz. Klavyeden girilen isim, nce standart gets
ileviyle yerel name_entry dizisine alnyor. Yerel diziye alnm ismin uzunluunun 1
fazlas kadar byte'lk bir alan malloc ileviyle dinamik olarak elde ediliyor. Yaz
uzunluunun 1 fazlas kadar yer ayrlmas yaznn sonunda yer alacak sonlandrc
karakter iin de yer salanmas amac tayor. Dinamik alann balang adresinin per
nesnesinin name_ptr elemannda saklandn gryorsunuz. Daha sonra standart strcpy
ileviyle yerel dizideki isim ayrlan dinamik bloa kopyalanyor.
per nesnesi bylece kendi eleman olan name_ptr gstericisi yoluyla dinamik bir alan
kontrol eder hale geliyor, deil mi? Bir struct Person nesnesinin tuttuu isme ulamak iin
nce nesnenin name_ptr elemanna eriip bu elemann deerinden de dinamik bloa
eriilebilir. Nesnenin mrnn sona ermesinden nce, bellek szntsn (memory leak)
engellemek amacyla, dinamik bloun geri verilmesi gerekir.

369

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

free(per.name_ptr);
arsyla geri verme ileminin yapldn gryorsunuz.

Yap Deikenlerine lkdeer Verilmesi

Dizilere ilkdeer vermeye ilikin zel bir szdizimi olduunu biliyorsunuz. Yap
deikenlerine de benzer bir szdizimle ilkdeer verilebilir. Verilen ilkdeerler sras ile
yap elemanlarna yerletirilir. Daha az sayda yap elemanna ilkdeer verilebilir. Bu
durumda ilkdeer verilmemi yap elemanlar otomatik olarak 0 deeri alr.
#include <stdio.h>
struct Date {
int day, month, year;
};
int main()
{
struct Date x = {10, 12, 1999};
struct Date y = {10};
printf("%d %d %d\n", x.day, x.month, x.year);
printf("%d %d %d\n", y.day, y.month, y.year);
}

return 0;

lkdeer verme szdiziminde, yap nesnesinin isminden sonra yer alan atama ilecini bir
blok izler. Bu bloun iinde virgllerle ayrlan bir liste ile yap nesnesinin elemanlarna
ilkdeer verilir. lk ifadenin deeri yap nesnesinin ilk elemanna, ikinci ifadenin deeri
yap nesnesinin ikinci elemanna atanr.
Dizilerde olduu gibi, yaplarda da bir yap nesnesinin elemanlarndan daha fazla sayda
elemana ilkdeer vermek geersizdir. Yapnn iinde yaz tutmak iin bildirilen char
trden bir dizi var ise bu diziye de ift trnak iinde ayrca ilkdeer verilebilir:
#include <stdio.h>
#define

MAX_NAME_LEN

20

struct Person {
char name[MAX_NAME_LEN + 1];
int no;
};
int main()
{
struct Person per = {"Mustafa", 256};
printf("isim : %s\nNo
}

: %d\n", per.name, per.no);

return 0;

main ilevi iinde, struct Person trnden per deikenine ilkdeer veriliyor. Tanmlanan
per deikeninin name isimli char trden dizisine, ilkdeer verme szdizimiyle Mustafa
yazs yerletiriliyor. Yine per deikeninin no isimli elemanna da ilkdeer verme
szdizimiyle 256 deeri atanyor.

370

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yap eleman olan dizinin btn elemanlarna deil de, belirli sayda elemanna ilkdeer
vermek mmkndr. Aadaki rnei derleyerek altrn:
struct Sample {
int x;
int a[10];
double d;
};
#include <stdio.h>
int main()
{
struct Sample sam = {20, 1, 2, 3, 7.8};
int k;
printf("sam.x = %d\n", sam.x);
for (k = 0; k < 10; ++k)
printf("sam.a[%d] = %d\n", k, sam.a[k]);
printf("sam.d = %lf\n", sam.d);
}

return 0;

Programcnn sam.x nesnesine 20, sam.a dizisinin ilk elemanna srasyla 1, 2, 3


deerlerini atamak istediini, sam.a dizisinin geri kalan elemanlarnn otomatik olarak
sfrlanmasnn beklediini dnelim. sam.d nesnesine de 7.8 ilkdeerinin verilmek
istendiini dnelim. Bildirimi yaplm struct Sample trnden sam isimli nesneye
aadaki gibi ilkdeer aktarlyor:
struct Sample sam = {20, 1, 2, 3, 7.8};
Ancak yukardaki deyimle bu yaplamaz. Derleyici 20 deerini sam.x nesnesine
yerletirirken sam.a dizisinin ilk drt elemanna srasyla 1, 2, 3, 7.8 deerlerini
yerletirir. Tabi otomatik tr dnmyle double trden olan 7.8 dizinin drdnc
elemanna atanrken int trne dntrlr. double trden per.d nesnesine ise ilkdeer
verilmediinden, bu eleman otomatik olarak 0 deeriyle balatlr.
lkdeer verme deyiminde, ikinci bir blok kullanlarak eleman olan dizinin ilk 3 elemanna
ilkdeer atamas yaplmas salanabilir. lkdeer verme deyimini aadaki gibi
deitirerek kodu yeniden derleyip, altrn:
struct Sample sam = {20, {1, 2, 3}, 7.8};
Byle bir ilkdeer verme ileminde, ikinci kme ayrac ifti iinde yazlan virgllerle
ayrlm deerler, eleman olan dizinin ilk elemanna atanrken, kapanan kme ayracn
izleyen 7.8 deeri ise yap nesnesinin d isimli elemanna aktarlm olur.

Yap Trnden Adresler ve Gstericiler

Bir yap nesnesinin adres ilecinin terimi olmasyla, yap nesnesinin adresi elde edilebilir.
Bir yap trnden gsterici deikenler de tanmlanabilir. Bir yap trnden gsterici
deikene, ayn yap trnden bir adres atanmaldr:

371

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
struct Point {
double x, y;
};
int main()
{
struct Point p;
struct Point *ptr = &p;
printf("sizeof ptr = %d\n", sizeof(ptr));
printf("sizeof *ptr = %d\n", sizeof(*ptr));
}

return 0;

main ilevi iinde struct Point trnden p isimli bir deiken tanmlanyor. Bu nesnenin
adresi struct Point trnden bir gsterici deiken olan ptr'ye atanyor. Bu atamadan
sonra artk p deikenine ptr gsterici deikeni ile de ulalabilir, deil mi?
Bir gsterici deiken ne trden bir nesneyi gsterirse gstersin, gstericinin sizeof
deeri 2 ya da 4 byte'dr.
sizeof(ptr)
ifadesi ile ptr gsterici deikeninin kendi sizeof deeri elde edilirken
sizeof(*ptr)
ifadesi ile ptr'nin gsterdii nesnenin yani p deikeninin sizeof deeri elde ediliyor.

Yap Gstericisi le Yap Elemanlarna Eriim

ptr bir yap trnden bir gsterici ve mem de o yapnn bir eleman olmak zere ptr'nin
gsterdii nesnenin mem isimli elemanna aadaki gibi eriilebilir:
(*p).mem
erik ileci ile ncelik tablosunun ikinci dzeyindeyken, nokta ileci birinci ncelik
dzeyindedir. Burada *p ifadesinin ncelik ayrac iine alnmas zorunludur. Eer ifade
*p.mem

/* Geersiz */

biiminde yazlsayd, nce nokta ileci deer reteceinden, p.mem ifadesi ele
alnrd.Nokta ilecinin sol terimi bir yap nesnesi olmad iin, ifade geersiz olurdu.

Ok leci

Bir yap trnden adres sz konusu olduunda bu adresteki yap nesnesinin belirli bir
elemanna erimek iin ayr ile kullanlabilir: ncelik ileci, ierik ileci, nokta ileci.
Bu eriim, ismi ok ileci olan tek bir ilele yaplabilir.
Ok ileci - ve > karakterlerinin yanyana getirilmesiyle oluturulur. ki terimli araek
konumunda (Binary infix) bir iletir. Ok ileci ncelik tablosunun en yksek ncelik
seviyesindedir. -> ilecinin sol terimi bir yap trnden adres olmaldr. lecin sa terimi
ise ilgili yapnn bir eleman olmaldr. le, sol terimi olan adresteki yap nesnesinin, sa
terimi olan isimli elemanna erimek iin kullanlr.
ptr, bir yap trnden bir nesnenin adresini tutuyor olsun. Aadaki iki ifade edeerdir.

372

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

(*ptr).mem
ptr->mem
Nokta ve ok ilelerinin her ikisi de elemana erimek iin kullanlr. Ancak nokta ileci yap
deikeninin kendisiyle, ok ileci ise adresiyle eriim salar.

Yap Nesnelerinin levlere Geirilmesi

Bir ilevin deerle (call by value) ya da adresle (call by reference) arlabileceini


biliyorsunuz. Yap nesneleriyle ilgili bir i gren ilev de, deerle ya da adresle arlabilir.

Yap Nesnesinin Deerinin leve Gnderilmesi

Bir ileve gnderilen argman olan ifade, ilevin ilgili parametre deikenine kopyalanr.
Bu durumda bir ilevin parametre deikeni bir yap trnden ise, ilev ayn yap
trnden bir nesne ile arlabilir. Ayn trden yap nesnelerinin atama ileciyle birbirine
atanabileceini biliyorsunuz. Byle bir atama blok kopyalamas anlamna geldii iin, hem
bellek hem de ilem zaman asndan greli bir kayba neden olur. stelik bu yntemle,
ilev kendisine gnderilen argmanlar deitiremez. nk ilev deerle arlmaktadr.
Aadaki rnei inceleyin:
#include <stdio.h>
#define
#define

MAX_NAME_LEN
MAX_FNAME_LEN

16
24

struct Person {
char name[MAX_NAME_LEN + 1];
char fname[MAX_FNAME_LEN + 1];
int no;
double wage;
};
void display_person(struct Person per)
{
printf("%d %s %s %.2lf\n", per.no, per.name, per.fname, per.wage);
}
int main()
{
struct Person person = {"Necati", "ERGIN", 2345, 3.56};
display_person(person);
return 0;
}
display_person ilevinin parametre deikeni struct Person trnden bir nesnedir. main
ilevi iinde struct Person trnden ismi person olan bir nesnenin ilkdeer verilerek
tanmlandn gryorsunuz. display_person ilevine yaplan arda argman olarak
person nesnesinin deeri kullanlyor. lev arld zaman, yaratlan ilevin parametre
deikeni olan per nesnesine, main blou iindeki person deikeninin deeri kopyalanr.
Bu bir blok kopyalama ilemidir. sizeof(struct Person) byklnde bir blok kopyalanr.
per nesnesi person nesnesi ile ayn nesne deildir. per nesnesi deeri person nesnesinin
deerine edeer baka bir nesnedir. display_person ilevi iinde
per.wage = 5.60;
gibi bir atama yaplsayd, phesiz bu atamadan person nesnesi etkilenmemi olurdu.

373

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yerel bir yap nesnesinin deeri byle bir ilevle deitirilemez, deil mi? levin bir yap
nesnesinin deerini almas ou zaman gereksiz bir blok kopyalanmasna neden olur.
lgili yap trnn sizeof deeri bydke, bellek ve ilemci zaman kullanm asndan
verimsizlik artacandan, pek tercih edilen bir yntem deildir. Kk yap nesneleri iin
kullanlabilir.

Yap Nesnesinin Adresinin leve Gnderilmesi

Bir ilevin parametre deikeni yap trnden bir gsterici olursa, ilev de bu trden bir
yap nesnesinin adresi ile arlabilir. Byle bir ileve yaplan ar ile, yalnzca bir
gsterici nesnesinin sizeof'u kadar veri ileve gnderilir.
Bu yntem ounlukla daha iyidir. Hemen her zaman bu yntem kullanlmaldr. Bu
yntemde yap ne kadar byk olursa olsun, aktarlan yalnzca bir adres bilgisidir. stelik
bu yntemde ilev kendisine adresi gnderilen yap deikenini deitirebilir. phesiz
byle bir aktarm ilemi, yap nesnesinin bellekte tek bir blok olarak yer almas yznden
mmkndr. Daha nce tanmlanan display_person isimli ilev, bu kez bir yap
nesnesinin adresini alacak biimde yazlyor:
void display_person(const struct Person *ptr)
{
printf("%d %s %s %.2lf\n", ptr->no, ptr->name, ptr->fname, ptr->wage);}
int main()
{
struct Person person = {"Necati", "ERGIN", 2345, 3.56};
display_person(&person);
}

return 0;

display_person isimli ilevin parametre deikeninin


const struct Person *ptr
biiminde bildirildiini gryorsunuz. lev dardan struct Person trnden bir nesnenin
adresini istiyor. Bildirimde kullanlan const anahtar szcnn, adresi alnan yap
nesnesinde deiiklik yaplmayaca bilgisini ilettiini biliyorsunuz.
levin kodu iinde kullanlan
ptr->no
ifadesi int trdendir. Bu ifade dardan adresi alnan yap nesnesinin no isimli eleman
olan nesneye karlk gelir.

Bir Yap Trne Geri Dnen levler

Bir ilevin geri dn deeri bir yap trnden olabilir. Aadaki rnei inceleyin:
struct Point {
double m_x, m_y;
};
struct Point make_point(double x, double y);
int main()
{
struct Point a;

374

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

a = make_point(3, 5);
/***/
return 0;

struct Point make_point(double x, double y)


{
struct Point temp;
temp.m_x = x;
temp.m_y = y;
return temp;
}
levlerin geri dn deerlerini geici bir nesne yardmyla darya ilettiklerini
biliyorsunuz. Geri dn deeri reten bir ilev iinde kullanlan return ifadesi, ilevin geri
dn deerini iinde tutacak geici bir nesneye atanr. lev ar ifadesi de bu geici
nesnenin deerini temsil eder. Bu geici nesne, ilevin kodunun almas return deyimine
gelince yaratlr, ilev arsnn yer ald ifadenin deerlendirilmesi bitince yok edilir. Bir
ilevin geri dn deerinin tr, ilevin geri dn deerini iinde tayacak geici
nesnenin trdr.
Yukardaki kod parasnda make_point ilevinin geri dn deeri, struct Point
trndendir. Bu durumda ilevin geri dn deerinin aktarld geici nesne de struct
Point trnden olur. Byle bir ilevin geri dn deeri, ayn trden bir yap deikenine
atanabilir.
Ancak byle ilevler bellekte ok fazla bir yer kaplamayan kk yap nesneleri iin
kullanlmaldr. nk return ifadesiyle geici blgeye geici blgeden de geri dn
deerinin saklanaca deikene atamalar yaplr. Bu da kt bir teknik olmaya adaydr.
Kk yaplar iin tercih edilebilir. nk algsal karmakl daha azdr.

Yap Trnden Bir Alann Dinamik Olarak Elde Edilmesi

Nasl bir dizi iin bellek alan dinamik olarak elde edilebiliyorsa bir yap nesnesi iin de
dinamik bir bellek blou elde edilebilir. Aadaki rnei derleyerek altrn:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define
#define

MAX_NAME_LEN
MAX_FNAME_LEN

15
23

struct Person {
char name[MAX_NAME_LEN + 1];
char fname[MAX_FNAME_LEN + 1];
int no;
double wage;
};
void set_person(struct Person *ptr, const char *name_ptr, const char
*fname_ptr, int n, double w)
{
strcpy(ptr->name, name_ptr);
strcpy(ptr->fname, fname_ptr);
ptr->no = n;
ptr->wage = w;
}
void display_person(const struct Person *ptr)
{
printf("%d %s %s %.2lf\n", ptr->no, ptr->name, ptr->fname, ptr->wage);
375

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

}
int main()
{
struct Person *ptr;
ptr = (struct Person *)malloc(sizeof(struct Person));
if (ptr == NULL) {
printf("bellek tahsis edilemiyor!\n");
exit(EXIT_FAILURE);
}
set_person(ptr, "Kaan", "Aslan", 2345, 4.80);
display_person(ptr);
free(ptr);
return 0;
}
main ilevini inceleyin. malloc ileviyle struct Person trnden bir nesnenin sabilecei
byklkte bir bellek alan dinamik olarak elde ediliyor. Dinamik bloun balang adresi
struct Person trnden bir gsterici deiken olan ptr'de tutuluyor. set_person isimli
ilevin, dardan adresini ald yap nesnesini, dier parametrelerine aktarlan bilgilerle
doldurduunu gryorsunuz. Daha nce tanmlanan display_person isimli ilev ise, yine
adresini ald yap nesnesinin tuttuu bilgileri ekrana yazdryor. Bu ilevlere, yap
nesnesinin adresi olarak, elde edilen dinamik bloun balang adresinin geildiini
gryorsunuz.

Bir Yap Trnden Adrese Geri Dnen levler

Bir ilevin geri dn deeri, bir yap trnden adres de olabilir. Bu durumda ilevin geri
dn deerini iinde tutacak geici nesne bir yap trnden adrestir. lev ars, ilevin
geri dn deeri trnden bir gstericiye atanabilir. Aadaki ilev tanmn inceleyin:
struct Person *create_person(const char *name_ptr, const char
*fname_ptr,int n, double w)
{
struct Person *ptr;
ptr = (struct Person *)malloc(sizeof(struct Person));
if (ptr == NULL) {
printf("bellek elde edilemiyor!\n");
exit(EXIT_FAILURE);
}
set_person(ptr, name_ptr, fname_ptr, n, w);
}

return ptr;

create_person ilevi dinamik olarak yerini ayrd bir nesneyi parametrelerine aktarlan
bilgilerle dolduruyor. Daha sonra dinamik nesnenin adresiyle geri dnyor. Bu ilevi
kullanan bir kod paras aadaki gibi olabilir:
int main()
{
struct Person *ptr;
ptr = create_person("Kaan", "Aslan", 2345, 4.80);
display_person(ptr);

376

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

free(ptr);
/***/
return 0;

main ilevi iinde arlan create_person ilevinin geri dndrd adres, struct Person
trnden bir gsterici deiken olan ptr'de tutuluyor. lev, dinamik bir nesnenin adresini
dndrdnden, dinamik alan geri vermek, ilevi aran kod parasnn
sorumluluundadr.
Byle bir ilev yerel bir yap deikeninin adresine geri dnemez. Global bir yap
deikeninin adresine de geri dnmesinin ou zaman fazlaca bir anlam yoktur.
lev, dinamik olarak yeri ayrlm bir yap nesnesinin adresi ile de geri dnebilir.
Elde edilen dinamik alann "heap" bellek alanna geri verilmesi, ilevi aran kod
parasnn sorumluluundadr. main iinde free ilevine yaplan ar ile dinamik alann
geri verildiini gryorsunuz.
Bir ilevin yerel bir yap nesnesinin adresine geri dnmesi tipik bir gsterici hatasdr.
Yerel yap nesneleri de static anahtar szcyle bildirilebilir. phesiz bir ilevin static
bir yap nesnesinin adresine geri dnmesi bir gsterici hatas deildir.

Bileik Nesneler ve sel Yaplar

Bir yapnn eleman baka bir yap trnden olabilir.


Bir yapnn elemannn baka bir yap trnden olabilmesi iki ayr biimde salanabilir:
nce eleman olarak kullanlan yap tr bildirilir. Bu bildirimin grlr olduu bir yerde
elemana sahip olan yapnn bildirimi yaplr. Aadaki rnei inceleyin:
struct Date {
int day, month, year;
};
struct Student {
char name[30];
struct Date birth_date;
int no;
};
Yukardaki rnekte nce struct Date yaps bildiriliyor. Daha sonra yaplan struct Student
trnn bildiriminde, struct Date trnden bir eleman kullanlyor.
kinci yntemde, eleman olan yap deikeninin bildirimi, elemana sahip yapnn bildirimi
iinde yaplr:
struct Student {
char name[30];
struct Date {
int day, month, year;
}birth_date;
int no;
};
Yukardaki rnekte yer alan struct Date yaps gibi, bir yapnn iinde bildirilen yapya
"isel yap" (nested structure) denir. Burada, ite bildirilen yap da sanki darda
bildirilmi gibi ilem grr. Yani ieride bildirilen yap trnden deikenler tanmlanabilir.
Yukardaki kod paras yalnzca bir bildirime karlk gelir. birth_date isimli bir nesne
tanmlanm olmaz. struct Student trnden bir nesne tanmlandnda, bu yap
nesnesinin struct Date trnden birth_date isimli eleman olur.
ki ayr szdiziminden herhangi birinden sonra struct Student trnden bir nesne
tanmlanm olsun:
struct Student s;

377

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

s yap deikeninin struct Date trnden olan birth_date isimli elemanna nokta ileciyle
ulalabilir:
s.birth_date
Yukardaki ifade struct Date trnden bir nesne gsterir. stenirse bu nesnenin day, mon,
year isimli elemanlarna nokta ilecinin ikinci kez kullanlmasyla eriilebilir:
s.birth_date.mon
ifadesi int trden bir nesne gsterir. Nokta ilecinin ile ncelik tablosunun birinci ncelik
dzeyinde olduunu, bu ncelik dzeyine ilikin ncelik ynnn soldan saa olduunu
anmsayn.
Bir ya da birden fazla eleman programc tarafndan bildirilen bir trden olan yap
nesnelerine bileik nesne (composite object) denir. Yukardaki rnekte struct Student
trnden olan s deikeni bir bileik nesnedir.

Bileik Nesnelere lkdeer Verilmesi

Normal olarak ilkdeer vermede elemanlar srasyla, iteki yap da dikkate alnacak
biimde, yap elemanlarna atanr. Ancak iteki yapnn elemanlarna verilen deerlerin,
ayrca kme ayralar iine alnmas, okunabilirlii artrd iin salk verilir:
struct Student s = {"Necati Ergin", {10, 10, 1967},

123};

Eer iteki yap ayrca kme ayrac iine alnmsa iteki yapnn daha az sayda
elemanna ilkdeer vermek mmkn olabilir:
struct Student s = {"Necati Ergin", {10, 10}, 123};
Burada s deikeninin, birth_date elemannn year elemanna ilkdeer verilmiyor.
Derleyici bu elemana otomatik olarak 0 deeri yerletirir. Burada iteki kme ayralar
kullanlmasayd, 123 ilkdeeri year elemanna atanr, no elemanna ise 0 deeri verilirdi.
Aadaki gibi bir bildirim de geerlidir:
struct Data {
int a[3];
long b;
char c;
} x = {{1, 2, 3}, 50000L, 'A'}, *p;

Bileik Nesne Oluturmann Faydalar

Bir yapnn baka bir yap trnden elemana sahip olmas durumunda, ierilen elemann
ait olduu yap trnn arayznden, yani darya hizmet veren ilevlerinden
faydalanma olana doar.
Aadaki gibi bir yap bildirilmi olsun:
struct Person {
char name[16]
char fname[20]
struct Date bdate;
};
Yukardaki bildirimde struct Person yapsnn bir eleman struct Date trndendir.
struct Person per;

378

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

gibi bir nesne tanmlandnda bu nesnenin eleman olan


per.bdate
ifadesi struct Date trnden bir nesneye karlk gelir. per nesnesinin bu eleman sz
konusu olduunda, struct Date trnn darya kar hizmet vermek zere tanmlam
ilevleri arlabilir. rnein struct Date tryle ilgili olarak aadaki gibi bir ilevin
bildirilmi olsun:
void display_date(const struct Date *);
per nesnesinin iinde tuttuu tarih bilgisini ekrana yazdrmak iin dorudan display_date
ilevi arlabilir, deil mi?
void display_person(const struct Person *ptr)
{
printf("isim
: %s\n", ptr->name);
printf("soyisim
: %s\n", ptr->fname);
printf ("doum tarihi : ");
display_date(&ptr->bdate);
}
display_person ilevi, kendisine gnderilen adresteki struct Person trnden nesnenin
eleman olan, bdate nesnesi iinde saklanan tarih bilgisini ekrana yazdrmak amacyla
display_date isimli ilevi aryor. leve argman olarak bdate elemannn adresini
gnderiyor.

Yaplarn Neden Kullanlr

Yaplarn kullanlmasyla baz faydalar elde edilebilir:

Birbirleri ile ilikili olan deikenler yap elemanlar olarak bir yap iinde toplanrsa algsal
kolaylk salanr. rnein dzlemde bir nokta, bir tarih bilgisi, bir depoda bulunan
mamllere ilikin zellikler bir yap ile temsil edilebilir.
C dilinde bir ilev en fazla 8 - 10 parametre almaldr. Daha fazla parametreye sahip
olmas kt bir tekniktir. Bir ilev ok fazla parametrik bilgiye gereksinim duyuyorsa, bu
parametrik bilgiler bir yap biiminde ifade edilmelidir. O yap trnden bir deiken
tanmlanmal, bu deikenin adresi ileve parametre olarak gnderilmelidir. rnein bir
kiinin nfus czdan bilgilerini parametre olarak alp bunlar ekrana yazdracak bir ilev
tasarlayacak olalm. Nfus czdan bilgilerinin hepsi bir yap biiminde ifade edilebilir ve
yalnzca bu yapnn adresi ileve gnderilebilir.
levlerin tek bir geri dn deeri vardr. Oysa ilevlerin ok deiik bilgileri aran
ileve iletmesi istenebilir. Bu ilem yle yaplabilir: letilecek bilgiler bir yap biiminde
ifade edilir. Sonra bu trden bir yap deikeni tanmlanarak adresi ileve gnderilir. lev
de bu yap deikeninin iini doldurur. Yani ilev knda bilgiler yap deikeninin iinde
olur.

Yap Dizileri

Yaplar da bir tr belirttiine gre yap trnden de diziler sz konusu olabilir. Bir yap
dizisi elemanlar bellekte bitiik olarak yerletirilen , elemanlar ayn yap trnden olan
bir dizidir.
Yap dizilerine de ilkdeer verilebilir. lkdeer verme srasnda kullanlan iteki kme
ayralar okunabilirlii artrr. rnek:
#include <stdio.h>

379

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

struct Date {
int d, m, y;
};
int main()
{
struct Date bdates[5] = {{10, 10, 1958}, {4, 3, 1964},
{21, 6, 1967}, {22, 8, 1956}, {11, 3, 1970}};
struct Date *pdate;
int i;
pdate = bdates;
for (i = 0; i < 5; ++i) {
printf("%02d / %02d / %04d\n", pdate->d, pdate->m, pdate->y);
++pdate;
}
return 0;
}
Bir yap dizisi zerinde ilem yapan ilev de tanmlanabilir. Byle bir ilev, kendisini
aran koddan, ilgili yap dizisinin balang adresi ile boyutunu almaldr. Aada, yap
dizileri ile ilgili ilemler yapan baz ilevler tanmlanyor. lev tanmlarn dikkatle
inceleyin:

380

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include
#include
#include
#include
#define
#define
#define

<stdio.h>
<string.h>
<stdlib.h>
<time.h>
NAME_LEN
FNAME_LEN
ARRAY_SIZE

16
20
200

struct Person {
char m_name[NAME_LEN];
char m_fname[FNAME_LEN];
int m_no;
double m_wage;
};
void swap_persons(struct Person *p1, struct Person *p2);
void set_person(struct Person *ptr, const char *name, const char *fname,
int no, double wage);
void set_person_random(struct Person *ptr);
void display_person(const struct Person *ptr);
void set_person(struct Person *ptr, const char *name, const char *fname,
int no, double wage);
void display_person_array(const struct Person *ptr, int size);
void sort_person_array(struct Person *ptr, int size);
char *name_array[20] = {"Ali", "Veli", "Hasan", "Necati", "Burcu", "Kaan",
"Selami", "Salah", "Nejla", "Huseyin", "Derya", "Funda", "Kemal", "Burak",
"Ozlem", "Deniz", "Nuri","Metin", "Guray", "Anil"};
char *fname_array[20] = {"Aslan", "Gencer", "Eker", "Ergin", "Serce",
"Kaynak", "Acar", "Aymir", "Erdin", "Doganoglu", "Avsar", "Ozturk",
"Yilmaz", "Tibet", "Arkin", "Cilasun", "Yildirim", "Demiroglu", "Torun",
"Polatkan"};
/*************************************************************************/
void swap_persons(struct Person *p1, struct Person *p2)
{
struct Person temp = *p1;
*p1 = *p2;
*p2 = temp;
}
/*************************************************************************/
void set_person(struct Person *ptr, const char *name, const char *fname,
int no, double wage)
{
ptr->m_no = no;
ptr->m_wage = wage;
strcpy(ptr->m_name, name);
strcpy(ptr->m_fname, fname);
}
/*************************************************************************/
void set_person_random(struct Person *ptr)
{
ptr->m_no = rand() % 5000;
ptr->m_wage = (double)rand() / RAND_MAX + rand() % 5 + 2;
strcpy(ptr->m_name, name_array[rand() % 100]);
strcpy(ptr->m_fname, fname_array[rand() % 50]);
}
/*************************************************************************/
void display_person(const struct Person *ptr)
{
printf("%-16s %-20s%-5d\t%4.2lf\n", ptr->m_name, ptr->m_fname, ptr-

381

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

>m_no, ptr->m_wage);
}
/*************************************************************************/
void set_person_array_random(struct Person *ptr, int size)
{
int k;
for (k = 0; k < size; ++k)
set_person_random(ptr + k);

}
/*************************************************************************/
void display_person_array(const struct Person *ptr, int size)
{
int k;
for (k = 0; k < size; ++k)
display_person(ptr + k);
}
/*************************************************************************/
void sort_person_array(struct Person *ptr, int size)
{
int i, k;
for (i = 0; i < size - 1; ++i)
for (k = 0; k < size - 1 - i; ++k)
if(strcmp(ptr[k].m_fname, ptr[k + 1].m_fname) > 0)
swap_persons(ptr + k, ptr + k + 1);
}
/*************************************************************************/
int main()
{
struct Person a[ARRAY_SIZE];
srand(time(0));
set_person_array_random(a, ARRAY_SIZE);
printf("siralanmadan once : \n");
display_person_array(a, ARRAY_SIZE);
sort_person_array(a, ARRAY_SIZE);
printf("siralanmadan sonra: \n");
display_person_array(a, ARRAY_SIZE);
return 0;
}
Aadaki gibi bir ilev tanmlanmak istensin:
void search_display(const struct Person *ptr, int size, const char *name);
lev balang adresini ve boyutunu ald dizi iinde name parametresine aktarlan isimli
kiilerin bilgilerini, soyadlarna gre artan srada ekrana yazdrsn. levin tanm ile
snama amacyla yazlan yeni main ilevini inceleyin:

382

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

void search_display(const struct Person *ptr, int size, const char *name)
{
int i,k;
struct Person **pd = NULL;
struct Person *temp;
int count = 0;
for (k = 0; k < size; ++k)
if (!strcmp(ptr[k].m_name, name)) {
pd = (struct Person **)realloc(pd, (count + 1) * sizeof(struct
Person *));
if (pd == NULL) {
printf("bellek blogu elde edilemiyor!\n");
exit(EXIT_FAILURE);
}
pd[count++] = (struct Person *)(ptr + k);
}
if (!count) {
printf("aranan isim dizide bulunamadi\n");
return;
}
for (i = 0; i < count - 1; ++i)
for (k = 0; k < count - 1 - i; ++k)
if (strcmp(pd[k]->m_fname, pd[k + 1]->m_fname) > 0) {
temp = pd[k];
pd[k] = pd[k + 1];
pd[k + 1] = temp;
}
for (k = 0; k < count; ++k)
display_person(pd[k]);
free(pd);
printf("toplam %d kisi bulundu!\n", count);
}
int main()
{
struct Person a[ARRAY_SIZE];
char name_entry[20];
srand(time(0));
set_person_array_random(a, ARRAY_SIZE);
display_person_array(a, ARRAY_SIZE);
printf("aranan ismi giriniz : ");
gets(name_entry);
search_display(a, ARRAY_SIZE, name_entry);
}

return 0;

Yaplara likin Karmak Durumlar

Bir yapnn eleman baka bir yap trnden gsterici olabilir. rnein:

383

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

struct Date {
int day, month, year;
};
struct Person {
char name[30];
struct Date *bdate;
int no;
};
struct Person per;
eklinde bir tanmlama yaplm olsun:
per.bdate ifadesi struct Date * trndendir. Bu ifade bir nesne belirtir.
per.bdate->day ifadesinin tr int'dir. Bu ifade de nesne gsterir.
&per.bdate->day ifadesinin int * trndendir.
Tabi bu rnekte, bir deer atamas yaplmamsa, per.bdate ile belirtilen gsterici iinde
rastgele bir adres vardr. Bu gstericinin bir gsterici hatasna neden olmadan
kullanlabilmesi iin gvenilir bir adresi gstermesi gerekir. rnein bu alan malloc
ileviyle dinamik olarak elde edilebilir:
per.bdate = (struct Date *) malloc (sizeof(struct Date));
Yukardaki rnekte elimizde yalnzca struct Person trnden bir gsterici olduunu
dnelim.
struct Person *ptr;
1. ptr->bdate ifadesini struct Date * trndendir.
2. person->bdate->day ifadesinin tr int'dir.
Bu rneklerde henz hibir yer ayrma ilemi yaplmamtr. Hem ptr hem de ptr->date
gsterici deikenleri iin, dinamik bellek ilevleriyle yer elde edilmesi gerekir:
ptr = (struct Person *) malloc(sizeof(struct Person));
ptr->bdate = (struct Date *) malloc(sizeof(struct Date));
Burada dinamik olarak elde edilen alanlar ters srada serbest braklmaldr:
free(ptr->bdate);
free(ptr);
Bir yapnn eleman, kendi trnden bir yap deikeni olamaz. rnein:
struct Sample {
struct Sample a; /* GEERSZ */
};
nk burada struct Sample yapsnn uzunluu belirlenemez. Ancak bir yapnn eleman
kendi trnden bir gsterici olabilir. rnein:
struct Node {
int val;
struct Node *ptr;
};

384

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Bir gstericinin tr uzunluu neyi gsterdiinden bamsz olarak, belirli olduundan


yukardaki bildirimde derleyicinin struct Node trnn sizeof deerini saptamasna engel
bir durum yoktur.
Bu tr yaplar zellikle bal liste ve aa yaplarn (algoritmalarn) gerekletirmek
amacyla kullanlabilir.

Bal Liste Nedir

Bal listenin ne olduunu anlayabilmek iin nce "dizi" veri yapsn hatrlayn.
Ayn trden nesnelerin bellekte tutulmak istendiini dnn. Bu nesneler bellekte
birbirini izleyecek biimde yani aralarnda hibir boluk olmayacak biimde tutulabilir. C
dilinin dizi aracnda da dizinin elemanlarnn bellekte bu ekilde tutulduunu biliyorsunuz.
Ancak nesneleri bellekte bitiik olarak yerletirmek her zaman istene bir durum deildir.
Bellekte nesnelerin bitiik yerletirilmesi drumunda, nesnelerden herhangi birine ulam
deimez zamanda yaplabilir. Yani dizinin ya da dinamik dizinin herhangi bir elemanna
ulama maliyeti, dizide tutuklan eleman sys ile doru orantl deildir. Dizide 100
eleman da olsa dizide 1000 eleman da olsa herhangi bir elemana ulam maliyeti
deimez bir zaman olur. Neden? Zira dizinin elemanna aslnda bir adres ilemiyle ulalr
deil mi? rnein pd bir dizinin balang adresini tutan bir gsterici ise
pd[n] gibi bir ilem
*(pd + n)
ilemine karlk gelir. Bu ilemin de maliyetinin deimez olduu aktr.
Bellekte elemanlar ardl olarak bulunmayan listelere bal liste denir. Bal listelerde
her eleman kendinden sonraki elemann nerede olduu bilgisini de tutar. lk elemann
yeri ise ayr bir gstericide tutulur. Bylece, bal listenin ilk elemannn adresi ile, bal
listenin tm elemanlarna ulalabilir. Bal liste dizisinin her eleman bir yap nesnesidir.
Bu yap nesnesinin baz yeleri bal liste elemanlarnn deerlerini veya tayacaklar
dier bilgileri tutarken, bir yesi ise kendinden sonraki bal liste eleman olan yap
nesnesinin adres bilgisini tutar. Bu ekilde elde edilen bir elemana "dm" ("node")
denir. rnek:
struct Node {
int val;
struct Node *next;
};
Amacmz int trden deerleri bellekte bir liste eklinde tutmak olsun. Yukarda struct
Node isimli bir yapnn bildirimini gryorsunuz. Tutulacak int trden deerler yapmzn
val isimli elemannn deeri olarak bellekte yer alacak. Yapnn yine struct Node trnden
olan gsterici eleman ise kendisinden bir sonra gelen yap nesnesinin adresini tutacak.
Bylece bir struct Node nesnesinin adresi elimizdeyken, bu nesnenin iinde tutulan int
trden veriye ulaabileceimiz gibi, nesnenin iinde yer alan next gstericisi yardmyla
da bir sonraki elemana ulaabiliriz.

Bal Listelerle Dizilerin Karlatrlmas

Bir dizinin herhangi bir elemanna deimez bir zamanda eriilebilir. Zira bir elemana
ulama bir adres bilgisine bir tamsaynn toplanmasyla olur. Oysa bal listelerde bir
elemana eriebilmek iin, bal listede ondan nce yer alan btn elemanlar dolamak
gerekir. Bu durumda bir elemana ulamann ortalama maliyeti ortadaki elemana
ulamann maliyetidir. Bu da bal listedeki eleman saysnn artmasyla bir elemana
ulama maliyetinin dorusal biimde artaca anlamna gelir.
Dizilerde araya eleman ekleme ya da eleman silme ilemleri iin blok kaydrmas yapmak
gerekir. Oysa bal listelerde bu ilemler ok kolay yaplabilir.

385

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Diziler bellekte ardl bulunmak zorundadr. Bu durum bellein blnm olduu


durumlarda belirli uzunlukta dizilerin almasn engeller. Yani aslnda istenilen toplam
byklk kadar bo bellek vardr ama ardl deildir. te bu durumda bal liste tercih
edilir.
Bal liste kullanm srasnda eleman ekleme, eleman silme, bal listeyi gezme
(traverse), vb. ilemler yaplr.

386

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

TR SMLER BLDRMLER ve typedef


BELRLEYCS
C dilinde derleyicinin daha nce bildii bir tre her bakmdan onun yerini tutabilen yeni
isimler verilebilir. Bu typedef anahtar szc kullanlarak yaplan bir bildirim deyimi ile
salanr.
typedef bildiriminin genel biimi yledir:
typdef <isim> <yeni isim>;
rnek:
typedef unsigned int UINT;
Bu bildirimden sonra UINT ismi derleyici tarafndan unsigned int trnn yeni bir ismi
olarak ele alnr. Yani kaynak kod iinde, typedef bildiriminin grlr olduu bir noktada,
UINT ismi kullanldnda derleyici bunu unsigned int tr olarak anlamlandrr.
UINT x, y, z;
Bildiriminde artk x, y, z deikenleri unsigned int trnden tanmlanm olurlar.
typedef bildiriminden sonra artk UINT ismi tr belirten isim gereken her yerde
kullanlabilir:
printf("%d\n", sizeof(UINT));
typedef anahtar szc ile yeni bir tr ismi oluturulmas, bu tre ilikin nceki ismin
kullanlmasna engel olmaz. Yani yukardaki rnekte gsterilen typedef bildiriminin
yaplmasndan sonra
unsigned int result;
gibi bir bildirimin yaplmasna engel bir durum sz konusu deildir.
phesiz #define nilemci komutuyla da ayn i yaplabilirdi:
#define UINT

unsigned int

Ancak typedef bildirimi derleyici tarafndan ele alnrken, #define nilemci komutu ile
tanmlanan isimler nilemci program ilgilendirir. Yani yukardaki nilemci komutunun
kullanlmasndan sonra, zaten derleyici UINT ismini grmez. Derleyiciye sra geldiinde,
UINT isminin yerini unsigned int atomlar alm olur.
Alglanmas zor olan tr isimlerine, typedef bildirimleriyle alglanmas daha kolay tr
isimleri verilebilir. typedef bildirimleri iin aada verilen basit kural kolaylk salar:
typedef anahtar szc, her tr bildirimin nne gelebilir. typedef anahtar szc bir
bildirimin nne geldiinde, typedef kullanlmam olsayd deiken ismi olacak isimler,
typedef anahtar szc eklendiinde artk ilgili trn ismi olur. rnein:
char *pstr;
biiminde bildirilen pstr char* trnden bir deikendir.
typedef char *pstr;

387

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yukardaki deyim ise bir typedef bildirimidir. Artk pstr derleyici tarafndan bir tr ismi
olarak ele alnr. pstr, char trden bir adres trnn baka bir ismi olarak, geerli bir
trdr. Yani yukardaki typedef bildiriminden sonra
pstr p;
gibi bir tanmlama yaplabilir. Bu tanmlama
char *p
ile ayn anlama gelir.
Bir typedef bildirimi ile elde edilen fayda her zaman #define nilemci komutuyla
salanamayabilir:
#define pstr char*
gibi bir nilemci ismi tanmlamas yapldnda, nilemci pstr ismini grd yerde
bunun yerine char * atomlarn yerletirir.
char *str;
gibi bir bildirimin
pstr str;
olarak yazlmasnda bir hata sz konusu olmaz. nilemci pstr yerine char *
yerletirdiinde derleyiciye giden kod
char *str
haline gelir.
char *p1, *p2, *p3;
nilemci #define komutunun kullanlarak yukardaki gibi bir bildirimin yaplmak istensin.
pstr p1, p2, p3;
yazldnda, nilemci yer deitirme ilemini yaptktan sonra derleyiciye verilen kod
aadaki biime dnr:
char *p1, p2, p3;
Bu tanmlama yaplmak istenen tanmlamaya edeer deildir. Yukardaki bildirimde
yalnzca p1 bir gsterici deikendir. p2 ile p3 gsterici deikenler deildir. char trden
deikenlerdir.
Bir diziye ilikin de yeni tr ismi bildirimi yaplabilir:
char isimdizi[20];
Yukardaki deyim ile isimdizi isimli char trden 20 elemanl bir dizi tanmlanm olur.
typedef char isimdizi[20];
Yukardaki deyim ise bir bildirimdir. Bu bildirim ile isimdizi artk 20 elemanl int trden
dizilerin tr ismidir. Bu typedef bildiriminden sonra eer

388

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

isimdizi a, b, c;
Gibi bir tanmlama yaplrsa, artk a, b, c her biri 20 elemanl char trden dizilerdir.
Bir typedef bildirimi ile birden fazla tr ismi yaratlabilir:
typedef unsigned int WORD, UINT;
Yukardaki bildirim deyiminden sonra, hem WORD hem de UINT, unsigned int trnn
yerine geen yeni tr isimleridir:
WORD x, y;
UINT k, l;
Artk x, y, k, l unsigned int trden deikenlerdir.
10 elemanl char trden gsterici dizisi iin tr ismi bildirimi yle yaplabilir:
typedef char *PSTRARRAY[10];
Bu bildirim deyiminden sonra
PSTRARRAY s;
ile
char *s[10];
tamamen ayn anlama gelir.
Bir tr ismi baka tr isimlerinin bildiriminde de kullanlabilir:
typedef unsigned int WORD;
typedef WORD UINT;
Yeni oluturulan tr isimleri, okunabilirlik asndan ya tamamen byk harflerden seilir,
ya da bu isimlerin yalnzca ilk harfleri byk harf yaplr.

typedef Bildirimlerinin Yaplar in Kullanm

Bir yap bildirimiyle yeni bir tr yaratlm olur. Bu tr nce derleyiciye tantldktan sonra,
bu tre ilikin deikenler tanmlanabilir:
struct Data {
int a, b, c;
};
Yukardaki bildirimle yeni bir veri tr yaratlyor. C dilinde bu veri trnn ismi struct
Data'dr. Trn ismi Data deildir. Yani bu veri trnden bir nesne tanmlamak
istendiinde tr ismi olarak struct Data yazlmaldr.
[C++ dilinde yap isimleri (structure tags) ayn zamanda trn de ismidir. struct anahtar szc olmadan
kullanldnda da bu trn ismi olarak derleyici tarafndan kabul grr.]
Yukardaki bildirimden sonra rnein bir tanmlama yaplacak olsa
struct Data d;
biiminde yaplmaldr. C dilinde bu tanmlamann

389

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Data d;
biiminde yaplmas geersizdir. Oysa C++ dilinde bu durum geerlidir.
te struct anahtar szcnn, yap nesnesi tanmlamalarnda yap isminden nce
kullanlma zorunluluunu ortadan kaldrmak iin programclar, typedef bildirimiyle kendi
bildirdikleri yap trlerine ilikin yeni tr isimleri olutururlar.
Bir yap trne ilikin yeni bir tr isminin oluturulmas ayr biimde yaplabilir.
1. nce yap bildirimi yaplr. Daha sonra bildirilen yap tr iin ayr bir typedef bildirimi
yaplr:
struct tagPerson {
char name[30];
int no;
};
typedef struct tagPerson Person;
Person per = {"Necati Ergin", 123};
Yukardaki rnekte nce struct tagPerson isimli bir tr yaratlyor daha sonra typedef
bildirimiyle struct tagPerson trne yeni bir isim olarak Person ismi veriliyor. typedef
bildiriminden sonra, hem struct tagPerson hem de Person isimleri, tr isimleri olarak
kullanlabilir.
2. typedef bildirimi ile yap bildirimi tek bir bildirim biiminde birletirilebilir:
typedef struct tagPerson {
char name[30];
int no;
} Person;
Person per;
Daha nce verilen kural anmsayn: Bu bildirimin banda typedef anahtar szc
olmasayd Person ismi struct tagPerson trnden bir nesnenin ismi olurdu, deil mi?
Yukardaki rnekte hem ismi struct tagPerson olan bir yap bildiriliyor hem de typedef
bildirimiyle bu yapya yeni bir isim olarak Person ismi veriliyor. lgili bildirimden sonra
hem struct tagPerson hem de Person isimleri, tr isimleri olarak kullanlabilir.
3. Yap ismi (structure tag) kullanlmadan yaplan bir yap bildirimi ile typedef bildirimi
birletirilebilir:
typedef struct {
char name[30];
int no;
}Person;
Person y;
Yukardaki rnekte yaratlan trn tek bir ismi vardr. Bu isim Person ismidir. Bu tr
kullanlmak istendiinde artk struct anahtar szc kullanlamaz.
Programclarn ou, yap isimleriyle (structure tag), typedef bildirimiyle oluturulacak tr
isimleri iin farkl isimler bulmak yerine birka karakter kullanarak aralarnda iliki
kurarlar. ok kullanlan kalplardan biri, yap isminin bana bir "alt tire" karakteri
konularak tr isminden ayrlmasdr:

390

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

typedef struct _Employee {


int no;
char name[30];
double fee;
} Employee;
phesiz aadaki gibi bir bildirim de hata oluturmazd:
typedef struct Employee {
int no;
char name[30];
double fee;
}Employee;
Trn eski ismi Employee deil struct Employee dir. Yani struct Employee trne typedef
bildirimiyle Employee ismi verilmitir. Bu durum bir saknca oluturmaz.
Windows API programlarnda yap bildirimlerine ilikin typedef bildirimlerinde aadaki
gibi bir kalp da kullanlr:
typedef struct tagEmployee {
int no;
char name[30];
double fee;
} Employee;
Yap ismi tag nekiyle balatlyor, seilen typedef isminde tag neki kaldrlyor.
Bir yap bildirimi sz konusu olduunda, yap trne isim vermek yerine o yapya ilikin
adres trne yeni isim verilebilir. Aadaki rnei inceleyin:
struct {
int a, b, c;
}*Hdata;
Yukardaki bildirimde, bildirimi yaplan yapnn bir ismi yoktur. Ancak typedef bildirimiyle
bu yapya ilikin adres trne Hdata ismi veriliyor. Bu durumda Unix, Windows
sistemlerinde
sizeof(Hdata)
ifadesinin deeri 4
sizeof(*Hdata)
ifadesinin deeri 12 dir.

Standart Balk Dosyalarnda Bulunan Baz typedef Bildirimleri

Baz standart ilevlerin bildiriminde, dorudan doal bir veri trn kullanmak yerine
daha nceden belirlenmi baz typedef isimleri kullanlr. Doal trler sistemden sisteme
farkl uzunlukta olabileceinden, baz ilevlerin ara yznde doal tr isimlerini kullanmak
yerine bir typedef isminin kullanlmas, derleyiciyi yazanlara daha byk bir esneklik
salar. rnein standart malloc ilevinin stdlib.h balk dosyas iindeki bildirimi aadaki
gibidir:
void *malloc(size_t ntypes);
Bu bildirimde size_t isminin bir tr ismi olarak kullanldn gryorsunuz.
Derleyicilerin ounda bu tr isminin bildirimi stddef.h, stdio.h, stdlib.h balk
dosyalarnda aadaki gibi yaplr:

391

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

typedef unsigned int size_t;


Bu tr gerekte ne olduu derleyicileri yazanlara braklm olan bir trdr. Derleyiciler
ilgili balk dosyalarnda yaplan typedef bildirimleriyle iaretsiz bir tamsay trlerinden
birine size_t ismini verir. Standartlara gre size_t tr sizeof ilecinin rettii deerin
trdr. ANSI standartlarnda bir ok ilevin bildiriminde size_t tr geer. rnein strlen
ilevinin gerek bildirimi, string.h balk dosyasnn iinde
size_t strlen(const char *);
olarak yaplr.
Yani malloc ilevinin parametre deikeni ya da strlen ilevinin geri dn deeri size_t
trndendir. Bu trn gerekte ne olduu derleyicileri yazanlara braklr. Ancak hemen
hemen btn derleyicilerde size_t tr unsigned int trnn typedef ismi olarak
belirlenir.
size_t tr gibi aslnda ne olduu derleyiciye braklm olan, yani derleyici yazanlarn ilgili
balk dosyalarnda typedef bildirimlerini yapacaklar baka tr isimleri de C standartlar
tarafndan tanmlanmtr. Bu trlerden bazlar unlardr:
time_t : standart time ilevinin geri dn deerinin trdr. time.h balk dosyas iinde,
derleyiciyi yazanlar herhangi bir temel veri trne typedef bildirimiyle bu ismi verirler. Bir
zorunluluk olmasa da, time_t derleyicilerin hemen hepsinde long trnn typedef ismi
olarak seilir.
clock_t : standart clock ilevinin geri dn deerinin trdr. time.h balk dosyas
iinde, derleyiciyi yazanlar herhangi bir temel veri trne typedef bildirimiyle bu ismi
verirler. Derleyicilerin hemen hepsinde long trnn typedef ismi olarak seilir.
ptrdiff_t : Bir adres bilgisinden baka bir adres bilgisinin kartlmasyla bir tamsay elde
edildiini biliyorsunuz. ki adresin birbirinden fark ptrdiff_t trndendir. Zaten bu trn
ismi de pointer difference szcklerinden gelir. Bu tr iaretli tamsay trlerinden biri
olmak zorundadr. Derleyicilerin hemen hepsinde int trnn typedef ismi olarak seilir.
fpos_t: stdio.h balk dosyas iinde bildirilen fgetpos ve fsetpos ilevlerinin parametre
deikeni olan gstericilerin trdr.
wchar_t: Bu trn bildirimin stdlib.h ve stddef.h balk dosyalarnn iinde yaplmtr.
Sistem tarafndan desteklenen yredeki (locale) en byk geniletilmi karakter setini
temsil edebilecek bir trdr. rnein geniletilmi karakter setinin tm deerleri iki
byte'lk bir alanda ifade edilebiliyorsa wchar_t tr unsigned short int trnn typedef
ismi olabilir. wchar_t ismi wide character szcklerinden gelir. Geni karakterler, geni
karakter deimezleri, oklu karakterler gibi noktalara "yerelletirme" konusunda
ayrntl olarak deinilecek.
div_t ve ldiv_t: Bu trlerin bildirimleri stdlib.h isimli balk dosyasnda yaplmtr. div_t
stdlib.h iinde bildirilen standart div ilevinin geri dn deeri olan yap trdr. ldiv_t
tr de yine stdlib.h balk dosyas iinde bildirilen ldiv isimli ilevin geri dn deeri
olan yap trdr.

typedef ile Bildirimi Yaplan Tr simlerinin Bilinirlik Alanlar

typedef bildirimleri iin de bilinirlik alan kurallar geerlidir. Bir blok iinde tanmlanan bir
typedef ismi, o blok dnda bilinmez.

392

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

void func()
{
typedef int
}
void foo()
{
WORD x;
}

WORD;

/*Geersiz*/

Yukardaki programda
WORD x;
deyimi geersizdir. Zira WORD tr yalnzca func ilevinin ana blou iinde bilinen bir veri
trdr. Bu bloun dnda bilinmez.
C dilinde blok iinde yaplan bildirimlerin bloklarn banda yaplmas zorunludur. typedef
bildirimiyle blok iinde yaplan yeni tr ismi bildirimleri de bloklarn banda yaplmak
zorundadr.
Ancak hemen her zaman typedef bildirimleri global dzeyde yaplr. Uygulamalarda
typedef bildirimleri genellikle, ya kaynak dosyann banda ya da balk dosyalar iinde
yaplr. nk typedef isimleri ounlukla darya hizmet veren bir modln arayzne
aittir.
Ayn typedef ismi farkl iki trn yeni ismi olarak bildirilemez:
typedef int WORD;
/*...*/
typedef long WORD; /* Geersiz! */

typedef Bildirimlerinin Amac Nedir

Okunabilirlii artrmak iin typedef bildirimleri yaplabilir. Baz trlere onlarn kullanm
amalarna uygun isimler verilirse kaynak kod daha kolay okunur daha kolay
anlamlandrlr. rnein char tr genelde karakter deimezlerinin atand bir trdr.
char tr yalnzca bir byte'lk bir veri olarak kullanlacaksa, yani yaz ilemlerinde
kullanlmayacak ise aadaki gibi bir tr tanmlamas yerinde olur:
typedef char BYTE;
/*...*/
BYTE x;
C89 standartlarnda bool tr doal bir veri tr deildir. Ancak bir typedef bildirimiyle
int trne bool ismi verilebilir:
typedef int bool;
typedef bildirimleri yazm kolayl salar. Karmak pek ok tr ismi typedef bildirimi
kullanlarak kolay bir biimde yazlabilir. Program okuyanlar tr bilgisine karlk gelen
karmak atomlar yerine onu temsil eden yaln bir isimle karlarlar. Aada nce bir
ilev adresine ilikin tre typedef bildirimiyle yeni bir isim veriliyor, daha sonra bu trden
bir nesne tanmlanyor:
typedef struct Person * *Fpper)(struct Person *, int);
/*...*/
Fpper fptr;
3. typedef bildirimleri bazen de tanabilirlii artrmak amacyla kullanlr. typedef
bildirimlerinin kullanlmasyla, yazlan ilevlere ilikin veri yaplar deise bile kaynak

393

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

programn deimesi gerekmez. rnein, bir ktphanede birtakm ilevlerin geri dn


deerleri unsigned int trnden olsun. Daha sonraki uygulamalarda bu ilevlerin geri
dn deerlerinin trnn unsigned long tr olarak deitirildiini dnelim. Eer
programc bu bu ilevlere ilikin kodlarda typedef bildirimleri kullanmsa, daha nce
yazd kodlar deitirmesine gerek kalmaz, yalnzca typedef bildirimlerini deitirmesi
yeterli olur. rnein:
typedef unsigned int HANDLE;
/***/
HANDLE hnd;
hnd = GetHandle();
Burada GetHandle ilevinin geri dn deerinin tr sonraki uyarlamalarda deierek
unsigned long yaplm olsun. Yalnzca typedef bildiriminin deitirilmesi yeterli olur:
typedef unsigned long HANDLE;
Bir C programnda deerleri 0 ile 50000 arasnda deiebilecek olan saya amacyla
kullanlacak deikenler kullanlmak istensin. Bu ama iin long int tr seilebilir, nk
long int tr Windows ya da Unix sistemlerinde 2.147.483.647 ye kadar deerleri
tutabilir. Ama long int tr yerine int trn kullanmak, aritmetik ilemlerin daha hzl
yaplabilmesi asndan tercih edilebilir. Ayrca int trden olan deikenler baz
sistemlerde bellekte daha az yer kaplayabilir.
int trn kullanmak yerine bu ama iin yeni bir tr ismi yaratlabilir:
typedef int SAYAC;
SAYAC a, b, c;
Kaynak kodun int trnn 16 bit uzunluunda olduu bir sistemde derlenmesi
durumunda typedef bildirimi deitirilebilir:
typedef long

SAYAC;

Bu teknikle tanabilirlie ilikin btn sorunlarn zlm olaca dnlmemelidir.


rnein SAYAC trnden bir deiken printf ya da scanf ilevlerine yaplan arlarda
argman olan ifadenin tr olarak kullanlm olabilir:
#include <stdio.h>
typedef int SAYAC;
int main()
{
SAYAC a, b, c;
/***/
scanf("%d%d%d", &a, &b. &c);
/***/
printf("%d %d %d", a, b, c);
/***/
return 0;
}
Yukardaki deyimlerde a, b, c deikenleri SAYAC trnden yani int trden tanmlanyor.
printf ile scanf ilevlerine yaplan arlarda da bu deikenlere ilikin format karakterleri
olarak %d seiliyor. Ancak SAYAC trnn long tr olarak deitirilmesi durumunda
printf ve scanf ilevlerinde bu trden deikenlerin yazdrlmasnda kullanlan format
karakterlerinin de %d yerine %ld olarak deitirilmesi gerekir.

394

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

typedef le Adres Trlerine sim Verilmesi

typedef bildirimi ile gsterici trlerine yeni isim verilmesinde dikkat edilmesi gereken bir
nokta vardr. Tr niteleyicileri konusunda ele alnd gibi C dilinde aadaki gibi bir
tanmlama yapldnda
const int *ptr;
ptr gsterdii yer const olan bir gstericidir. Yani ptr deikeninin gsterdii yerdeki
nesne deitirilemez:
*ptr = 10;
gibi bir atama geersizdir. Ancak tanmlama
int *const ptr;
biiminde yaplrsa, ptr kendisi const olan bir gstericidir. ptr gstericisinin gsterdii
nesnenin deeri deitirilebilir, ama ptr gstericisinin iindeki adres deitirilemez, yani
ptr = (int *) 0x1F00;
gibi bir atama yaplmas geersizdir.
typedef int *IPTR;
gibi bir bildirimden sonra
const IPTR p;
biiminde bir tanmlama yapldnda, p gstericisinin deeri deitirilemez, p
gstericisinin gsterdii yerdeki nesnenin deeri deitirilebilir. Yani *p nesnesine atama
yaplabilir. Baka bir deyile
const IPTR ptr;
deyimi ile
int *const ptr;
deyimi edeerdir.
Windows iletim sistemi altnda alacak C ya da C++ programlarnn yazlmasnda
typedef bildirimleri sklkla kullanlr. windows.h isimli balk dosyasnda temel veri
trlerinin ouna typedef bildirimleriyle yeni isimler verilmitir. Windows API
programlamada windows.h balk dosyas kaynak koda eklenmelidir. Bu dosyann iinde
API ilevlerinin bildirimleri, eitli yap bildirimleri, typedef isimleri, nemli simgesel
deimezler bulunur.

windows.h inde Tanmlanan typedef simleri


typedef

int BOOL;

Bu trle ilikili iki simgesel deimez de tanmlanmtr.


#define FALSE
#define TRUE

0
1

395

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

BOOL tr, zellikle ilevlerin geri dn deerlerinde kullanlr. Bu durum ilevin


baarlysa 0 d bir deere, baarszsa 0 deerine geri dnecei anlamna gelir. Baar
kontrol, 1 deeriyle karlatrlarak yaplmamaldr.
Aadaki typedef isimleri, iaretsiz 1 byte, 2 byte ve 4 byte tam saylar simgeler.
typedef
typedef
typedef
typedef

unsigned
unsigned
unsigned
unsigned

char BYTE;
short WORD;
long int DWORD;
int UINT;

Gstericilere ilikin typedef isimleri P harfiyle balar. LP uzak gstericileri belirtmek iin
n ek olarak kullanlr. Win16 sistemlerinde uzak ve yakn gsterici kavramlar vard.
Dolaysyla o zamanlar, P nekli gstericiler yakn gstericileri, LP nekli gstericiler ise
uzak gstericileri temsil ediyordu. Fakat Win32 sistemlerinde yakn ve uzak gsterici
kavramlar yoktur. Bu durumda, P nekli gstericilerle LP nekli gstericiler arasnda
hibir fark yoktur. Ancak, Win16'daki alkanlkla hala LP nekli typedef isimleri kullanlr.
Windows.h iinde her ihtimale kar -Win16 programlar alabilsin diye- near ve far
szckleri aadaki gibi silinmitir.
#define
#define
typedef
typedef

far
near
char near *PSTR;
char far *LPSTR;

PSTR ya da LPSTR Win32 sistemlerinde tamamen ayn anlama gelir ve char* trn
belirtir.
typedef char *PSTR;
typedef char *LPSTR;
Gstericilerde const'luk P ya da LP'den sonra C ekiyle belirtilir. rnein;
typedef const char *PCSTR;
typedef const char *LPCSTR;
Klasik typedef isimlerinin hepsinin gsterici karlklar da vardr. Btn gsterici trleri,
Win16 uyumlu olmas iin P ve LP nekleriyle ayrca bildirilmitir.
typedef
typedef
typedef
typedef

BYTE *PBYTE;
WORD *PWORD;
const BYTE *PCBYTE;
const DWORD *LPCDWORD;

C'nin doal trlerinin hepsinin byk harf normal, adres ve const adres biimleri vardr.
typedef long LONG;
typedef int INT;
typedef char CHAR;
Windows programlamada H ile balayan, handle olarak kullanlan pek ok typedef ismi
vardr. Bu typedef isimlerinin hepsi void * trndendir. rnein:
typedef
typedef

void
void

*HWND;
*HICON;

396

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Tarih ve Zaman le lgili lem Yapan Standart levler

Standart balk dosyalarndan time.h iinde bildirilen, tarih ve zaman bilgileriyle ilgili
faydal iler yapmak iin tanmlanan baz standart ilevler vardr. Bu ilevlerin bazlarnn
parametre deikenleri ya da geri dn deerleri bir yap trnden adres bilgileridir.
Aada bu ilevler aklanyor:

time levi
time_t time (time_t *timer);
levin geri dn deeri standart bir typedef tr olan time_t trdr. Derleyicilerin
ounun bu tr long trnn typedef ismi olarak bildirir. levin parametre deikeni de
bu trden bir adrestir.
lev adresi gnderilen nesneye belirli bir tarihten (ou sistemde bu tarih 01.01.1970
tarihidir) ilev arsna kadar geen saniye says deerini yazar. Bu deer standartlarda
"takvim zaman" ("calender time") olarak geer. Tarih ve zaman zerinde ilem yapan
dier baz ilevler ilerini yapabilmek iin bu deere gereksinim duyar.
lev, bu deeri ayn zamanda geri dn deeri olarak da darya iletir. Eer takvim
zaman bilgisi elde edilemiyorsa ilev (time_t)-1 deerine geri dner.
Eer ileve NULL adresi gnderilirse, ilev bu deeri zel bir ileti olarak alglar, hibir
nesneye yazma yapmadan, saniye bilgisini yalnz geri dn deeri ile darya aktarr.
Aada ilevin kullanlmasyla ilgili basit bir kod paras veriliyor:
#include <stdio.h>
#include <time.h>
int main()
{
time_t timer1, timer2, timer3;
timer1 = time(&timer2);
printf("devam etmek iin bir tua basn : ");
getchar();
timer3 = time(NULL);
printf("timer1 = %ld\n", (long)timer1);
printf("timer2= %ld\n", (long)timer2);
printf("timer3= %ld\n", (long)timer3);
}

return 0;

localtime levi

01.01.1970'den geen saniye says yani takvim zaman dorudan kullanlabilecek bir
zaman bilgisi deildir. localtime ilevi bu bilgiyi alarak faydal paralara ayrr. levin
time.h balk dosyas iindeki bildirimi aadaki gibidir:
struct tm *localtime(const time_t *timer);
levin geri dn deeri, time.h iinde bildirilen bir yap olan struct tm trnden bir
adrestir. Bu yap aadaki gibi bildirilmitir:

397

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

struct tm {
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
};
Yapnn ismi tm nekiyle balayan tm elemanlar int trdendir. Her bir eleman tarih ya
da zaman ile ilgili faydal bir veriyi tutar. Aada yapnn elemanlar hakknda bilgi
veriliyor:
tm_sec
: saniye deeri (0 - 60)
tm_min
: dakika deeri (0 - 60)
tm_hour
: saat deeri (0 24)
tm_mday
: Ayn gn (1 31)
tm_mon
: Ay deeri (0 Ocak, 1 ubat, 2 Mart)
tm_year
: Yl deerinin 1900 eksii
tm_wday
: Haftann gn (0 Pazar, 1 Pazartesi, 2 Sal)
tm_yday
: Yln gn (1 Ocak iin 0)
tm_isdst
:Gn tasarruf modu ile ilgili bilgi. Bu elemann deerinin pozitif ise
tasarruf modunda olunduu bilgisi iletilmi olur. Bu deer 0 ise tasarruf modu deildir.
Elemann deerinin negatif olmas durumunda bu bilgi elde edilemiyor demektir.
struct tm yaps ile tutulan zaman bilgisine "ayrtrlm zaman bilgisi" (broken-down
time) denir.
localtime ilevi statik mrl bir struct tm nesnesinin adresi ile geri dner. levin geri
dn deeri olan adresteki yap nesnesinin deeri kullanlmadan ya da baka bir
nesneye aktarlmadan, ilev bir kez daha arlrsa, daha nceki ar ile ilgili olarak
retilen deerin stne yazlm olur. levin parametre deikeni time_t trnden bir
nesneyi gsteren gstericidir. lev adresini ald bu nesneden takvim zaman bilgisini
alr. Aada localtime ilevini kullanan rnek bir kod veriliyor:
#include <stdio.h>
#include <time.h>
char *months[12] = {"Ocak", "Subat", "Mart", "Nisan", "Mayis", "Haziran",
"Temmuz", "Agustos", "Eylul","Ekim", "Kasim", "Aralik"};
char *days[7] = {"Pazar","Pazartesi", "Sali", "Carsamba", "Persembe",
"Cuma", "Cumartesi"};
int main()
{
time_t timer;
struct tm *tptr;
time(&timer);
tptr = localtime(&timer);
printf("Tarih : %02d %s %04d %s\n",
tptr->tm_mday,months[tptr>tm_mon], ptr->tm_year + 1900, days[tptr>tm_wday]);
printf("Saat:%02d:%02d:%02d\n", tptr->tm_hour, tptr->tm_min,
tptr->tm_sec);
printf("bugun %d yilinin %d. gunu\n", tptr->tm_year + 1900,
tptr->tm_yday);
if (tptr->tm_isdst < 0)

398

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

printf("gun isigi tasarruf modu bilgisi elde edilemiyor!\n");


else if (tptr->tm_isdst > 0)
printf("gun isigi tasarruf modundayiz!\n");
else
printf("gun isigi tasarruf modunda degiliz!\n");
return 0;
}

ctime levi

Bu ilev, takvim zaman bilgisini girdi olarak alarak bu bilgiyi bir yazya dntrr.
levin bildirimi aadaki gibidir:
char *ctime(const time_t *time);
levin parametre deikeni time_t trnden bir adrestir. lev adresini ald nesneden
takvim zaman bilgisini okur. levin geri dn deeri 26 karakterlik bir yaznn balang
adresidir. Bu yaz ayrtrlm zaman bilgilerini ieren zel olarak formatlanm bir
yazdr:
F

\n

Fri Feb 23 12:25:12 2004


lev statik mrl bir dizinin adresiyle geri dner. levin geri dn deeri olan
adresteki yaz kullanlmadan ya da baka bir diziye aktarlmadan, ilev bir kez daha
arlrsa, daha nceki ar ile ilgili olarak retilen yaznn stne yazlm olur. Aada
ilevin kullanmna ilikin rnek bir kod paras yer alyor:
#include <stdio.h>
#include <time.h>
int main()
{
char *ptr;
time_t timer;
timer = time(NULL);
ptr = ctime(&timer);
printf("%s", ptr);
return 0;
}

asctime levi

ctime ilevinin yapt iin aynsn yapar. Ancak girdi olarak takvim zamann deil
ayrtrlm zaman bilgisini alr:
char *asctime (const struct tm *tblock);
levin parametre deikeni struct tm yaps trnden bir adrestir. lev, adresini ald
nesneden, ayrtrlm zaman bilgilerini okur. Bu bilgiyi bir yazya dntrerek, zel bir
formatta 26 karakterlik statik mrl bir dizi iine yazar. lev, ilgili yaznn balang
adresine geri dner. levin geri dn deeri olan adresteki yaz kullanlmadan ya da
baka bir diziye aktarlmadan, ilev bir kez daha arlrsa, daha nceki ar ile ilgili
olarak retilen yaznn stne yazlm olur. Aada ilevin kullanmna ilikin rnek bir
kod paras yer alyor:

399

'\0'

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
#include <time.h>
int main()
{
time_t timer;

timer = time(NULL);
printf("%s", asctime(localtime(&timer)));
return 0;

Yukardaki kod parasnda, localtime ilevinin geri dn deeri olan struct tm trnden
adres dorudan asctime ilevine argman olarak gnderiliyor. asctime ilevinin geri
dn deeri olan adres de printf ilevine geiliyor.

clock levi

levin geri dn deeri time.h balk dosyas iinde bildirilen standart bir typedef tr
olan clock_t trdr. Derleyicilerin hemen hepsinde bu tr long trnn typedef ismi
olarak bildirilir:
clock_t clock(void);
lev, programn almaya balamasyla ilev arsna kadar geen sreye geri dner.
Ancak ilevin geri dn deerine ilikin birim saniye deil ilemcinin zaman devresinin
tick saysdr. levin geri dn deerini saniyeye dntrmek iin, geri dn deeri
ilemcinin saniyedeki tick saysna blnmelidir. Zaman devresinin bir saniyedeki tick
sayisi time.h iinde CLOCKS_PER_SEC isimli bir simgesel deimez olarak tanmlanmtr.
#define

CLOCKS_PER_SEC

1000

Kodun tanabilirlii asndan bu simgesel deimez kullanlmaldr.


Derleyicilerin ou daha ksa bir simgesel deimezin kullanlmasn salamak zere
CLK_TCK isimli bir simgesel deimez daha tanmlar:
#define

CLK_TCK

CLOCKS_PER_SEC

Ancak tanabilirlik asndan CLOCKS_PER_SEC simgesel deimezi kullanlmaldr.


clock ileviyle ilgili aadaki rnek program inceleyin:
#include <stdio.h>
#include <math.h>
#include <time.h>
int main()
{
clock_t clock1, clock2;
long k;
clock1 = clock();
for (k = 1; k < 10000000; ++k)
sqrt(sqrt(k) + sqrt(k + 1));
clock2 = clock();
printf("dongu %lf saniye surdu!\n", (double)(clock2 - clock1) /
CLK_TCK);
}

return 0;

400

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Aada clock ilevinden faydalanan bir geciktirme ilevi yazlyor:


#include <math.h>
#include <time.h>
#define

SENSITIVITY

0.1

void delay(double sec)


{
double total = 0.;
clock_t tstart = clock();
clock_t tend;
double duration;

for (;;) {
tend = clock();
duration = (double)(tend - tstart) / CLOCKS_PER_SEC;
if (fabs(duration - sec) < SENSITIVITY)
return;
}

difftime levi

Standart difftime ilevi takvim zaman cinsinden verilen iki zaman bilgisi arasndaki
saniye farkn bulmak iin kullanlabilir. lev bildirimi aadaki gibidir:
double difftime(time_t timer2, time_t timer1);
levin geri dn deeri timer1 deeri ile timer2 deeri arasnda geen saniye saysdr.
#include <stdio.h>
#include <math.h>
#include <time.h>
int main()
{
time_t start,finish;
long i;
double result, elapsed_time;
printf("20000000 kez kare kok aliniyor.\n");
time(&start);
for (i = 1; i <= 20000000; i++)
result = sqrt(i);

time(&finish);
elapsed_time = difftime(finish, start);
printf("\nToplam sure = %lf saniye.\n", elapsed_time);
return 0;

mktime levi

Bu standart ilev ayrtrlm zaman bilgisini (broken-down time) takvim zamanna


(calender time) dntrr. levin bildirimi aadaki gibidir:
time_t mktime(struct tm *tptr):

401

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

ilevin parametresi ayrtrlm zaman bilgisinin tutan struct tm trnden nesnenin


adresidir. levin parametresinde kullanlan adresin const olmadna dikkat edin.
Buradan ilevin bu adrese yazma yapaca sonucunu karabilirsiniz. levin geri dn
deeri takvim zaman deeridir. Eer ilgili sistemde takvim zaman deeri elde
edilemiyorsa ilev -1 deerine geri dner.
levin yle bir yan etkisi de vardr. Eer parametresine ald adresteki yap nesnesinin
elemanlar olmas gereken deerleri ayorsa, mktime ilevi deerlerin fazla ksmn bir
sonraki elemana ekler.
Bu amala nce tm_sec isimli elemana baklr. Buradaki fazlalklar tm_min elemanna
verilir. Burada da bir fazlalk oluur ise srasyla yap nesnesinin tm_hour, tm_mday,
tm_mon ve tm_year elemanlar deitirilir. Bu elemanlar deeri alndktam sonra yap
nesnesinin tm_wday ve tm_yday isimli elemanlar sahip olmas gereken deerlere
getirilir.
Aadaki kod, ilevin bu zelliini kullanarak bir tarihin ne gnne geldiini buluyor:
#include <stdio.h>
#include <time.h>
int main()
{
struct tm t;
const char *days[] = {"Pazar", "Pazartesi", "Sali", "Carsamba",
"Persembe", "Cuma","Cumartesi", "bilinmiyor"};
t.tm_mday = 11;
t.tm_mon = 2;
t.tm_year = 2005 - 1900;
t.tm_sec = 1;
t.tm_min = 0;
t.tm_hour = 0;
t.tm_isdst = -1;
if (mktime(&t) == 1)
t.tm_wday = 7;
printf("gun = %s\n", days[t.tm_wday]);
}

return 0;

402

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yaplarla lgili Uygulamalar

Aadaki programda bir tarih bilgisini tutmak amacyla Date isimli bir yap bildiriliyor. Bu
yap trn kullanarak hizmet veren ilevler tanmlanyor.
/********** date.h **************************/
typedef struct {
int m_d;
int m_m;
int m_y;
}Date;
#define
#define
#define

YEAR_BASE
false
true

1000
0
1

typedef int bool;


void set_date(Date *ptr, int d, int m, int y);
void set_today(Date *ptr);
void set_random(Date *ptr);
void display_date(const Date *ptr);
void inc_date(Date *p);
void dec_date(Date *p);
Date ndays(const Date *p, int n);
int date_cmp(const Date *p1, const Date *p2);
int get_day(const Date *p);
int get_month(const Date *p);
int get_year(const Date *p);
int get_yearday(const Date *ptr);
int get_weekday(const Date *ptr);
bool isweekend(const Date *ptr);
bool isleap(int y);
/********** date.c **************************/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
#define
#define
#define

PUBLIC
PRIVATE
FACTOR

static
2

PRIVATE int daytabs[2][13] = {


{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
};
PRIVATE bool check_date(int d, int m, int y);
PRIVATE int totaldays(const Date *p);
PRIVATE Date revdate(int totaldays);
PRIVATE bool check_date(int d, int m, int y)
{
if (y < YEAR_BASE)
return false;
if (m < 1 || m > 12)
return false;

403

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

if (d < 1 || d > daytabs[isleap(y)][m])


return false;
return true;
}
/*************************************************************************/
PRIVATE int totaldays(const Date *ptr)
{
int sum = 0;
int k;
for (k = YEAR_BASE; k < ptr->m_y; ++k)
sum += 365 + isleap(k);
return sum + get_yearday(ptr);
}
/*************************************************************************/
PRIVATE Date revdate(int totaldays)
{
Date ret_val;
int val;
int index;
ret_val.m_y = YEAR_BASE;
while (totaldays > (val = isleap(ret_val.m_y) + 365)) {
totaldays -= val;
ret_val.m_y++;
}
ret_val.m_m = 1;
index = isleap(ret_val.m_y);
while (totaldays > daytabs[index][ret_val.m_m])
totaldays -= daytabs[index][ret_val.m_m++];
ret_val.m_d = totaldays;
return ret_val;
}
/*************************************************************************/
PUBLIC int get_yearday(const Date *ptr)
{
int sum = ptr->m_d;
int k;
int index = isleap(ptr->m_y);
for (k = 1; k < ptr->m_m; ++k)
sum += daytabs[index][k];
return sum;
}
/*************************************************************************/
PUBLIC int dayofweek(const Date *ptr)
{
return totaldays(ptr) % 7;
}
/*************************************************************************/
PUBLIC bool isleap(int y)
{
return y % 4 == 0 && y % 100 != 0 || y % 400 == 0;
}
/*************************************************************************/
PUBLIC void set_date(Date *ptr, int d, int m, int y)
{
assert(check_date(d, m, y));

404

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

ptr->m_d = d;
ptr->m_m = m;
ptr->m_y = y;

}
/*************************************************************************/
PUBLIC void set_today(Date *ptr)
{
time_t timer = time(NULL);
struct tm *tptr = localtime(&timer);
ptr->m_d = tptr->tm_mday;
ptr->m_m = tptr->tm_mon + 1;
ptr->m_y = tptr->tm_year + 1900;
}
/*************************************************************************/
PUBLIC void set_random(Date *ptr)
{
ptr->m_y = rand() % 50 + 1960;
ptr->m_m = rand() % 12 + 1;
ptr->m_d = rand() % daytabs[isleap(ptr->m_y)][ptr->m_m] + 1;
}
/*************************************************************************/
PUBLIC void display_date(const Date *ptr)
{
static const char *days[] = {"Pazar", "Pazartesi", "Sali", "Carsamba",
"Persembe", "Cuma",
"Cumartesi"};
static const char *mons[] = {"", "Ocak", "Subat", "Mart", "Nisan",
"Mayis", "Haziran",
"Temmuz", "Agustos", "Eylul","Ekim", "Kasim",
"Aralik"};
printf("%02d %s %4d %s\n", ptr->m_d, mons[ptr->m_m], ptr->m_y,
days[get_weekday(ptr)]);
}
/*************************************************************************/
PUBLIC int date_cmp(const Date *p1, const Date *p2)
{
if (p1->m_y != p2->m_y)
return p1->m_y - p2->m_y;
if (p1->m_m != p2->m_m)
return p1->m_m - p2->m_m;
return p1->m_d - p2->m_d;
}
/*************************************************************************/
PUBLIC void inc_date(Date *p)
{
*p = revdate(totaldays(p) + 1);
}
/*************************************************************************/
PUBLIC void dec_date(Date *p)
{
*p = revdate(totaldays(p) - 1);
}
/*************************************************************************/
PUBLIC Date ndays(const Date *p, int n)
{
return revdate(totaldays(p) + n);
}
/*************************************************************************/
PUBLIC int get_weekday(const Date *ptr)
{
return (totaldays(ptr) + FACTOR) % 7;
}

405

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

/*************************************************************************/
PUBLIC bool isweekend(const Date *ptr)
{
int day = get_weekday(ptr);
return day == 6 || day == 0;
}
/*************************************************************************/
int main()
{
Date today;
Date ndaysafter;
set_today(&today);
ndaysafter = ndays(&today, 10);
while (date_cmp(&today, &ndaysafter)) {
display_date(&today);
inc_date(&today);
}
}

return 0;

406

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Aadaki programda bir tekli bal liste oluturuluyor.


/********** datelist.h **************************/
#include "date.h"
typedef struct tagNode {
Date date;
struct tagNode *pnext;
}Node;
typedef struct {
Node *pstart;
Node *pend;
size_t size;
}*ListHandle;
ListHandle openlist(void);
void closelist(ListHandle);
void push_front(ListHandle handle);
void push_back(ListHandle handle);
void display_list(ListHandle handle);
void pop_front(ListHandle handle);
void pop_back(ListHandle handle);
void remove_date(const Date *);
void clear_list(ListHandle handle);
size_t get_size(ListHandle handle);
/********** datelist.c **************************/
PRIVATE Node *create_node(void);
PRIVATE void free_nodes(Node *p);
/*************************************************************************/
PRIVATE void free_nodes(Node *p)
{
Node *temp;
while (p) {
temp = p;
p = p->pnext;
free(temp);
}
}
/*************************************************************************/
PRIVATE Node *create_node(void)
{
Node *pd = (Node *)malloc(sizeof(Node));
if (!pd) {
printf("cannot allocate memory!\n");
exit(EXIT_FAILURE);
}
return pd;
}
/*************************************************************************/
PUBLIC ListHandle openlist(void)
{
ListHandle pd = (ListHandle)malloc(sizeof(*pd));
if (!pd) {
printf("cannot allocate memory!\n");
exit(EXIT_FAILURE);
}
pd->pstart = pd->pend = NULL;
pd->size = 0;

407

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

return pd;
}
/*************************************************************************/
PUBLIC void closelist(ListHandle handle)
{
clear_list(handle);
free(handle);
}
/*************************************************************************/
PUBLIC void push_front(ListHandle handle)
{
Node *pnew = create_node();
set_random(&pnew->date);
handle->size++;
if (handle->pstart == NULL) {
handle->pstart = handle->pend = pnew;
pnew->pnext = NULL;
return;
}
pnew->pnext = handle->pstart;
handle->pstart = pnew;
}
/*************************************************************************/
PUBLIC void push_back(ListHandle handle)
{
Node *pnew = create_node();
set_random(&pnew->date);
pnew->pnext = NULL;
handle->size++;
if (handle->pstart == NULL) {
handle->pstart = handle->pend = pnew;
return;
}
handle->pend->pnext = pnew;
handle->pend = pnew;
}
/*************************************************************************/
PUBLIC void display_list(ListHandle handle)
{
Node *cur = handle->pstart;
if (!handle->size) {
printf("empty list!\n");
return;
}
while (cur) {
display_date(&cur->date);
cur = cur->pnext;
}

}
/*************************************************************************/
PUBLIC void clear_list(ListHandle handle)
{
free_nodes(handle->pstart);
handle->pstart = handle->pend = NULL;
}
/*************************************************************************/
PUBLIC size_t get_size(ListHandle handle)
{
return handle->size;
}

408

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

/*************************************************************************/
PUBLIC void pop_front(ListHandle handle)
{
Node *temp;
if (!handle->size) {
printf("liste bos!\n");
return;
}
handle->size--;
if (handle->pstart == handle->pend) {
free(handle->pstart);
handle->pstart = handle->pend = NULL;
return;
}
temp = handle->pstart;
handle->pstart = handle->pstart->pnext;
free(temp);

}
/*************************************************************************/
PUBLIC void pop_back(ListHandle handle)
{
Node *temp, *cur;
if (!handle->size) {
printf("liste bos!\n");
return;
}
handle->size--;
if (handle->pstart == handle->pend) {
free(handle->pstart);
handle->pstart = handle->pend = NULL;
return;
}
temp = handle->pend;
for (cur = handle->pstart; cur->pnext != handle->pend; cur = cur>pnext)
;
cur->pnext = NULL;
handle->pend = cur;
free(temp);
}
/*************************************************************************/
void display_menu()
{
printf("[1] PUSH FRONT\n");
printf("[2] PUSH BACK\n");
printf("[3] DISPLAY LIST\n");
printf("[4] POP FRONT\n");
printf("[5] POP BACK\n");
printf("[6] EMPTY LIST\n");
printf("[7] EXIT\n");
printf("seciminiz : ");
}
/*************************************************************************/
int get_option()
{
int option;

409

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

display_menu();
scanf("%d", &option);
if (option < 1 || option > 7)
option = 0;
return option;

}
/*************************************************************************/
int main()
{
int option;
ListHandle handle = openlist();
for (;;) {
option = get_option();
switch (option) {
case 1: push_front(handle); break;
case 2: push_back(handle); break;
case 3: display_list(handle);break;
case 4: pop_front(handle);break;
case 5: pop_back(handle);break;
case 6: clear_list(handle); break;
case 7: goto END;
case 8: printf("invalid entry!\n");
}
}
END:
closelist(handle);
printf("end of program!\n");
}

return 0;

410

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

BRLKLER
Programc tarafndan yeni bir tr yaratmasna olanak veren bir baka ara da "birlikler"dir
(unions).
Birlikler yaplara ok benzer. Bir birliin kullanlabilmesi iin, yani bir birlik trnden
nesnelerin tanmlanabilmesi iin nce birliin bildirimi yaplmaldr. Birlik bildirimleri ayn
yap bildirimleri gibi yaplr. Tek fark struct anahtar szc yerine union anahtar
szcnn kullanlmasdr.
Aadaki rnei inceleyin:
union Dword {
unsigned char byte;
unsigned int word;
unsigned long dword;
};
Yukardaki deyimle, ismi union Dword olan yeni bir tr bildirilmi olur. Bu bildirimin
grlr olduu yerlerde, bu tr kullanlabilir. Bir typedef bildirimi yaplarak, bu trn
isminin, yalnzca Dword olmas da salanabilir:
typedef union {
unsigned char byte;
unsigned int word;
unsigned long dword;
}Dword;

Birlik Trnden Deikenlerinin Tanmlanmas


Birlik deikenleri ayn yap deikenleri gibi tanmlanr. Birliklerde de, bellekte yer
ayrma ilemi yap bildirimi ile deil, yap nesnesinin tanmlanmas ile yaplr.
Dword a, b;
deyiminden sonra, a ve b, Dword trnden iki deikendir.
Yine yaplarda olduu gibi, birliklerde de bildirim ile tanmlama ilemi birlikte yaplabilir:
union Double {
double d;
unsigned char s[8];
} a, b, c;
Bu durumda a, b ve c deikenlerinin bilinirlik alanlar, birlik bildiriminin yapld yere
bal olarak, yerel ya da global olabilir.
Birlik elemanlarna da yap elemanlarnda olduu gibi nokta ileciyle eriilir. rnein
yukardaki tanmlamadan sonra a.d birliin double trnden ilk elemann belirtir. Benzer
biimde birlik trnden nesneleri gsterecek, gsterici deikenler de tanmlanabilir. Ok
ileci ile yine yaplarda olduu gibi birliklerde de, adres yoluyla birlik elemanlarna
ulalabilir:
union Dword *p;
p->word = 100;
p->word ifadesi ile, p adresindeki birlik nesnesinin word isimli elemanna eriilir.

411

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Birlik Nesnelerinin Bellekteki Yerleimi

Birlik nesneleri iin birliin en uzun eleman kadar yer ayrlr. Birlik elemanlarnn hepsi
ayn saysal adresten balayacak ekilde bellee yerleir. rnein:
union Dword {
unsigned char byte;
unsigned short word;
unsigned long dword;
};
union Dword a;
bildirimi ile, Dword trden a deikeni iin bellekte Unix, Windows sistemlerinde 4 byte
yer ayrlr. nk a deikeninin dword isimli eleman, 4 byte ile birliin en uzun
elemandr.

1F00
1F01
1F02
1F03

a.byte

a
a
a

a.word
a.dword

Birlik bir dizi ieriyorsa dizi tek bir eleman olarak alnr. rnein:
typedef union {
float f;
unsigned char bytes[4];
}Float;
Float x;
tanm ile x deikeni iin ne kadar yer ayrlr? Float birliinin iki eleman vardr. Birincisi
4 byte uzunluunda float trden bir deiken, ikincisi de 4 byte uzunluunda bir karakter
dizisidir. ki uzunluk da ayn olduuna gre x nesnesi iin 4 byte yer ayrlaca
sylenebilir.

Buna gre
Float x;
x.f = 10.2F;
ile x.bytes[0], x.bytes[1], x.bytes[2], x.bytes[3] srasyla float trden elemann byte
deerleridir.
Aadaki program inceleyin:

412

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
typedef union {
char ch;
int i;
double d;
char s[4];
}Data;

int main()
{
Data data;
printf("&data
printf("&data.ch
printf("&data.i
printf("&data.d
printf("data.s

=
=
=
=
=

%p\n",
%p\n",
%p\n",
%p\n",
%p\n",

&data);
&data.ch);
&data.i);
&data.d);
data.s);

return 0;
}
Yukardaki programn derlenip altrlmasyla ekrana hep ayn adres yazdrlr.
Birlik elemanlarnn ayn orjinden, yani ayn saysal adresten balayarak yerletirilmesi bir
elemann deeri deitirildiinde, dier elemanlarn da deerlerinin deiecei anlamna
gelir. Zaten birliklerin kullanlmasnn asl amac da budur.

Birlik Nesnelerine lkdeer Verilmesi

C standartlarna gre, birlik nesnelerinin yalnzca ilk elemanna ilkdeer verilebilir. Bir
birlik nesnesinin birden fazla elemanna ilkdeer vermek geersizdir:
union Dword {
unsigned char byte;
unsigned int word;
unsigned long dword;
} x = {'m'};
union Dword

y = {'a', 18, 24L};

/* Geersiz */

Birlikler Neden Kullanlr


Birlikler balca ama iin kullanlabilir. Birinci ama bellekte yer kazanmaya yneliktir.
Birlik kullanarak farkl zamanlarda kullanlacak birden fazla deiken iin ayr ayr yer
ayrma zorunluluu ortadan kaldrlr. rnein bir hediyelik eya katalou ile deiik
rnn satldn dnelim: kitap, tshort ve saat. Her bir rn iin bir stok numaras,
fiyat bilgisi ve rn tip bilgisinin dnda rne bal olarak baka zelliklerin de tutulmak
zorunda olduunu dnelim:
kitaplar : isim, yazar, sayfa says.
t-short : desen, renk, boyut
saat : model

413

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

typedef struct {
int stok_no;
float fiyat;
int urun_tipi;
char kitapisim[20];
char yazar[20];
int sayfa_sayisi;
char desen[20];
int renk;
int boyut;
char saatisim[20];
int model;
}Katalog;
Yukardaki bildirimde Katalog yapsnn urun_tipi isimli eleman rnn ne olduu bilgisini
tutar. Bu elemann deeri yalnzca KITAP, TSHORT ya da SAAT olabilir. Bunlarn simgesel
deimezler olarak tanmlandn dnelim. Yukarda bildirilen yap rnlerin btn
zelliklerini tutabilir ancak yle bir sakncas vardr:
Eer rn tipi KITAP deil ise isim[20], yazar[30] ve sayfa_sayisi isimli elemanlar hi
kullanlmaz. Yine rn tipi TSHORT deil ise desen[20], renk, boyut elemanlar hi
kullanlmaz.
Unix ya da Windows sistemlerinde byte hizalama altnda yukarda bildirilen Katalog
trnn sizeof deeri 108'dir. Yani Katalog trnden bir nesne tanmlandnda bu nesne
bellekte 108 byte yer kaplar.
#include <stdio.h>
int main()
{
Katalog katalog;

printf("sizeof(katalog) = %d\n", sizeof(katalog));


return 0;

Ama Katalog yapsnn bir elemannn bir birlik trnden olmasyla yer kazanc
salanabilir:

414

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

typedef struct {
char isim[20];
char yazar[20];
int sayfa_sayisi;
}Kitap;
typedef struct {
char desen[20];
int renk;
int size;
}Tshirt;
typedef struct {
char isim[20];
int model;
}Saat;
typedef union {
Kitap kitap;
Tshirt tshirt;
Saat saat;
}Data;
typedef struct {
int stok_no;
float fiyat;
int urun_tipi;
Data data;
}Katalog;
Yukardaki bildirimleri inceleyin. nce kitap, tshirt ve saate ilikin bilgileri tutmak
amacyla Kitap, Tshirt ve Saat isimli yaplar bildirilmi. Unix, Windows sistemlerinde
Kitap, Tshirt ve Saat yaplarnn sizeof deerleri srasyla 44, 28 ve 24'dr. Daha sonra
Data isimli bir birliin bildirildiini gryorsunuz. Bu birliin elemanlar Kitap, Tshirt ve
Saat trlerinden olduuna gre bu birliin sizeof deeri en uzun elemannn yani Kitap
yaps trnden olan elemannn sizeof u kadardr, yani 44 dr.
Katalog isimli yapnn bildiriminde ise Data birlii trnden data isimli bir eleman yer
alyor. Bu durumda Katalog yapsnn sizeof deeri yalnzca 56 olur. Birliin
kullanlmasyla Katalog yapsnn sizeof deeri 108 den 56'ya drlyor.
#include <stdio.h>
int main()
{
printf("sizeof(Katalog) = %u\n", sizeof(Katalog));
return 0;
}
Katalog yapsyla ilgili ilem yapan kod paralar, Katalog yaps trnden nesnenin nce
urun_tipi isimli elemannn deerine bakarak, rnn cinsi bilgisini elde ettikten sonra,
duruma gre, data isimli elemanlar farkl biimde kullanabilir:
Katalog katalog;
/***/
if (katalog.urun_tipi == KITAP)
puts(katalog.data.kitap.isim)

415

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Birlik kulanmnn ikinci nedeni herhangi bir veri trnn paralar zerinde ilem yapmak
ya da paralar zerinde ilem yaparak bir btn oluturmaktr. Aadaki rnei
inceleyin:
int trnn 2 byte olduu bir sistemde aadaki bildirimlerin yapldn dnelim:
typedef struct {
unsigned char low_byte;
unsigned char high_byte;
}Word;
typedef union {
unsigned int i;
Word w;
}Wordform;
bildirimlerinden sonra, Wordform trnden bir nesne tanmlanrsa bu birlik nesnesi, alak
(low_byte) ve yksek (high_byte) anlaml byte'larna ayr ayr eriilebilen bir tamsay
olarak kullanlabilir:
#include <stdio.h>
int main()
{
Wordform wf;
wf.w.low_byte = 0x12;
wf.w.high_byte = 0x34;
printf("%x\n", wf.i);
}

return 0;

Yani Intel ilemcilerinin bulunduu 16 bit sistemlerde yukardaki main ilevinin derlenip
altrlmasyla:
printf("%x\n", wf.i);
ars ile 3412 says ekrana yazdrr. Motorola ilemcilerinde (big endian) dk saysal
adreste dk anlaml dk anlaml byte deeri olacana gre saynn ters olarak
grlmesi gerekir.
Benzer bir tema, ilemcilerin yazmalarnn yazlmsal olarak temsil edilmesinde karmza
kar.
8086 ilemcilerinde toplam 14 yazma vardr.
- 4 tane genel amal yazma: AX, BX, CX, DX
- 4 tane segment yazmac: CS, DS, CS, ES
- 2 tane indeks yazmac: SI, DI
- 3 tane gsterici yazmac: IP, BP, SP
- 1 tane bayrak yazmac: F
Btn yazmalar 16 bit uzunluundadr. Genel amal yazmalar olan AX, BX, CX, DX
yazmalar 8'er bitlik iki paraya ayrlr. Genel amal yazmalar aadaki gibi bamsz
8 bitlik yazmalar gibi de kullanlabilir.
AX
AH
BX

AL

416

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

BH
CX
CH
DX
DH

BL
CL
DL

Bu yazmalar ayn zamanda btnn paralardr, yani AH ve AL yazmalarna ayr ayr


deerler yazp AX yazmac btnsel bir deer olarak ekilebilir. Yazmalar bellekte bir
birlik (union) ile temsil edilebilirler.
struct BYTEREGS {
unsigned char al, ah, bl, bh, cl, ch, dl, dh;
};
struct WORDREGS {
unsigned ax, bx, cx, dx, si, di, flags, cflag;
};
union REGS {
struct BYTEREGS h;
struct WORDREGS x;
};

regs.x.cx
regs.x.bx
regs.x.cx
regs.x.dx

<-<-<-<-<-<-<-<--

regs.h.al
regs.h.ah
regs.h.bl
regs.h.bh
regs.h.cl
regs.h.ch
regs.h.dl
regs.h.dh

regs.x.si
regs.x.di
regs.x.flags
regs.x.cflag

Birliklerin Kark Veri Yaplarnda Kullanlmas


Birlikler kullanlarak, elemanlar farkl trden olan diziler oluturulabilir:
Bir dizinin elemanlar char, int, double veya programc tarafndan yaratlan bir tr olan
Complex trnden olabilsin. Dizinin herhangi bir eleman bu drt trden herhangi
birinden olabilecek ekilde kullanlabilsin.
nce Complex isimli bir tr yaratalm:

417

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
#include <stdlib.h>
typedef struct _Complex {
double m_r, m_i;
}Complex;
void set_cr(Complex *p)
{
p->m_r = (rand() % 2 ? 1:-1) * ((double)rand() / RAND_MAX + rand()% 9);
p->m_i = (rand() % 2 ? 1:-1) * ((double)rand() / RAND_MAX + rand()% 9);
}
void display_c(const Complex *p)
{
printf("(%.2lf %+.2lfi)", p->m_r, p->m_i);
}
Yukarda tanmlanan set_cr ilevi adresini ald bir Complex nesnesini rastgele bir
deerle set ediyor. display_c isimli ilev ise adresini ald bir Complex nesnesinin
deerini ekrana yazdryor.
nce okunabilirlii artrmak iin baz simgesel deimezler tanmlayalm:
#define
#define
#define
#define

CHAR
INT
DOUBLE
COMPLEX

0
1
2
3

imdi ismi Data olan bir birlik tr yaratalm.


typedef union{
char ch;
int i;
double d;
Complex c;
}Data;
Data trnn sizeof deeri en uzun eleman olan Complex trden c isimli elemann sizeof
deeri kadar olur deil mi? Unix ya da Windows sistemlerinde Data trnn sizeof deeri
16 byte olur. imdi de ismi Element olan bir yap tr yaratalm:
typedef struct {
char type;
Data data;
}Element;
Element trnn sizeof deeri elemanlarnn sizeof deerlerinin toplam kadar olduuna
gre (byte alignment'n etkin olduu varsaylyor) UNIX ve Windows sistemlerinde
Element trnden bir nesne bellekte 17 byte yer kaplar. Oluturulacak dizinin elemanlar
Element trnden olur. Element trnn eleman olan type Element trden bir nesnenin
eleman olan data'nn hangi elemannn kullanld bilgisini tutar. imdi Element trden
bir nesneyi rastgele bir deerle set edecek bir ilev tanmlayalm:

418

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

void set_elem_random(Element *ptr)


{
switch (rand() % 4) {
case CHAR
:
ptr->type = CHAR; ptr->data.ch = rand() % 26 + 'A';
break;
case INT
:
ptr->type = INT; ptr->data.i = rand(); break;
case DOUBLE :
ptr->type = DOUBLE;
ptr->data.d = (double)rand() / RAND_MAX + rand() % 10;
break;
case COMPLEX: ptr->type = COMPLEX; set_cr(&ptr->data.c);
}
}
imdi de Element trnden bir nesnenin deerini ekrana yazdran bir ilev tanmlayalm:
void display_elem(const Element *ptr)
{
switch (ptr->type) {
case CHAR
: printf("(%c)", ptr->data.ch); break;
case INT
: printf("(%d)", ptr->data.i); break;
case DOUBLE : printf("(%.2lf)", ptr->data.d); break;
case COMPLEX
: display_c(&ptr->data.c);
}
}
imdi de Element trnden bir diziyi rastgele deerlerle set edecek ve dizinin
elemanlarn ekrana yazdracak ilevler yazalm:
void display_array(const Element *ptr, int size)
{
int k;

for (k = 0; k < size; ++k) {


if (k && k % 5 == 0)
printf("\n");
display_elem(ptr + k);
}

void set_array(Element *ptr, int size)


{
int k;

for (k = 0; k < size; ++k)


set_elem_random(ptr + k);

imdi aadaki main ilevini inceleyin:

419

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#define

ARRAY_SIZE

50

int main()
{
Element a[ARRAY_SIZE];
srand(time(0));
set_array(a, ARRAY_SIZE);
display_array(a, ARRAY_SIZE);
return 0;
}
main ilevi iinde Element trnden a isimli bir dizi tanmlanyor.
set_array(a, ARRAY_SIZE);
arsyla a dizisinin elemanlarna rastgele deerler atanyor. Tabi bu durumda dizinin
elemanlar rastgele bir biimde char, int, double ya da Complex trlerinden seiliyor.
display_array(a, ARRAY_SIZE);
arsyla dizinin elemanlarnn deerleri ekrana yazdrlyor. Aada programn
altrlmasyla elde edilen rnek bir ekran kts veriliyor:
(1.07)(4.49)(19755)(1.69 -8.82i)(0.91)
(4.45)(9.35)(1.41)(V)(5.57 +5.51i)
(K)(T)(11331)(7.78)(22316)
(26066)(28923)(2.36 -2.31i)(C)(8.39)
(9951)(8.79)(28301)(7.50)(18583)
(20564)(7.02)(-0.23 -5.46i)(28931)(-4.76 +2.32i)
(5850)(14891)(J)(-5.40 +8.65i)(H)
(7.50 -3.32i)(-3.81 +3.17i)(D)(-5.38 -6.72i)(2.15 +2.47i)
(-4.04 +2.10i)(4737)(-0.21 -0.61i)(-9.00 -3.72i)(4276)
(12552)(-6.95 -0.11i)(E)(0.71)(-4.72 +7.21i)

420

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

NUMARALANDIRMALAR
Yazlan birok programda, yalnzca belirli anlaml deerler alabilen deikenler kullanma
gereksinimi duyulur. rnein bir "Boolean" deikeni, yalnzca iki deere sahip olabilir:
"Doru" ve "Yanl". Haftann bir gnn tutacak bir deiken, haftann yedi gn
olduuna gre yedi farkl deerden birini alabilir.
Baka bir rnek olarak bir oyun kadnn rengini tutacak bir deikeni verilebilir. Byle
bir deiken yalnzca 4 deiik deer alabilir: Sinek, Karo, Kupa, Maa.
Byle deikenler tamsay trlerinden tanmlanabilir:
int renk;
renk = 1;
Yukardaki rnekte renk isimli deiken bir oyun kadnn renk bilgisini tutuyor. Bu
deikene 1 deerinin atanmas renk deerinin Karo olduunu gsteriyor.
Byle bir teknik uygulamalarda pekala kullanlabilir. Ancak bu tekniin baz sakncalar
vardr.
1. Kodu okuyan renk isimli deikene yaplan atamalarda kullanlan tamsay
deimezlerinin neyi temsil ettii konusunda dorudan bilgi alamaz. Kodun okunabilirlii
azalr. rnein
renk = 1;
eklinde bir atama dorudan renk deikenine "karo" deerinin verilmi olduu biiminde
de anlamlandramaz.
2. Derleyici renk deikeni ile ek bir kontrol yapamaz. Derleyici renk deikeninin
yalnzca 4 farkl deerden birini almas gerektiinin farknda deildir. Derleyiciye byle
bir bilgi verilmemitir. rnein byle bir deikene 10 gibi bir deerin atanmas
anlamszdr. Ancak derleyici derleme srasnda bu yanll bulamaz, bir hata ya da bir
uyar iletisiyle veremez.
C dili, isimlendirilmi belirli tamsay deerlerini alabilen, bir tr yaratlmasna olanak
veren bir araca sahiptir. Bu araca numaralandrrma (enumaration) ve bu arala ilikili
kullanlan deimezlere (enumaration constants) "numaralandrma deimezleri" denir.
Bir numaralandrma trnn ve bir numaralandrma trne ilikin deimezlerin bildirimi
aadaki gibi yaplr:
enum [enum trnn isimi] {deimez1,deimez2, ......};
enum bir anahtar szcktr. Derleyici kme ayralar arasnda isimlendirilmi
deimezleri 0 deerinden balayarak artan tamsay deerleriyle eler. rnek :
enum Renk {Sinek, Karo, Kupa, Maca};
Yukardaki bildirimle Sinek deimezi 0, Karo deimezi 1, Kupa deimezi 2, Maca
deimezi ise 3 deerini alr.
enum Bool {TRUE, FALSE};
burada TRUE deimezi 0 FALSE deimezi ise 1 deerini alr.
enum Months {January, February, March, April, May, June, July, August,
September, Oktober, November, December};

421

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Bu bildirim ile numaralandrma deimezlerine


January = 0, February = 1, ... December = 11 biiminde artan deerler verilir.
Numaralandrma deimezlerine atama ileci ile kme ayralar iinde deerler verilebilir,
bu biimde deer verilmi bir numaralandrma deimezinden sonraki deimezin deeri
nceki deerden bir fazlasdr.
enum Months {January = 1, February, March, April, May, June, July,
August,September, Oktober, November, December};
Bu bildirim ile numaralandrma deimezlerine January = 1, February = 2, ... December
= 12 biiminde artan deerler verilmi olur.
enum deimezlerine int tr say snrlar iinde pozitif ya da negatif deerler verilebilir:
enum RTVals {
RT1 = -127,
RT2,
RT3,
RT4 = 12,
RT5,
RT6,
RT7 = 0,
RT8,
RT9 = 90
};
Yukardaki bildirim ile numaralandrma deimezlerinin alaca deerler aadaki gibi
olur:
RT1 = -127, RT2 = -126, RT3 = -125, RT4 = 12, RT5 = 13,
RT8 = 1,
RT9 = 90

RT6 = 14, RT7 = 0,

Bir numaralandrma bildiriminde kullanlan farkl numaralandrma deimezlerinin deeri


ayn olabilir. Aadaki bildirim geerlidir:
enum Bool {YANLIS, FALSE = 0, DOGRU, TRUE = 1};
Bir numaralandrma deimezinin ismi, ayn bilinirlik alannda kullanlan tm isimlerden
farkl olmaldr. Bir numaralndrma deimezi ismi ile ayn bilinirlik alannda bildirilen bir
deikenin isminin ya da bir baka numaralandrma deimezinin isminin ayn olmas
geersizdir.
Numaralandrma isimleri (enum tag), yap ve birlik isimleri gibi bilinirlik alan kurallarna
uyar. Bu isimler ayn bilinirlik alanndaki dier numaralandrma, yap ve birlik isimlerinden
farkl olmaldr.
Bildirimlerde numaralandrma ismi (enumeration tag) hi belirtilmeyebilir. Bu durumda
genellikle kme ayracnn kapanmasndan sonra o numaralandrma trnden nesne(ler)
tanmlanarak deyim sonlandrc atom ile bitirilir.
enum {Sunday = 1, Monday, Tuesday, Wednesday, Thursday, Friday,
Saturday}day1, day2, day3;
Yukardaki rnekte day1, day2, day3 bildirimi yaplm numaralandrma trnden (belirli
bir tr ismi seilmemitir) yaratlm deikenlerdir. Byle bir bildirim + tanmlama
ileminin dezavantaj, artk bir daha ayn numaralandrma trnden baka bir deikenin
yaratlmamasdr.

422

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Bildirilen bir numaralandrma trnden nesne tanmlamak da zorunlu deildir:


enum {LOW = 10, HIGH = 20};
Yukardaki bildirim geerlidir. Bildirilen trn bir ismi yoktur ama bu bildirimin grlr
olduu her yerde LOW ve HIGH numaralandrma deimezleri kullanlabilir.

Numaralandrma Trlerinin sizeof Deerleri

Bir numaralandrma trnden tanmlanm bir nesne iin derleyici, kullanlan sistemde int
trnn uzunluu kadar bir yer ayrr. Derleyici iin numaralandrma trnden bir nesne
ile int trden bir nesne arasnda fiziksel olarak herhangi bir fark bulunmaz.
rnein Unix altnda :
sizeof(enum Days) == sizeod(int) ==

ifadesi dorudur.
Tabi bu kuraln bir kt taraf int trnn 2 byte olduu bir sistemde kullanlabilecek en
byk numaralandrma deimezinin deeri 32767 olabilir.

Numaralandrmalar ve typedef Bildirimi

Bir numaralandrma tr iin de bir typedef bildirimi yaplabilir. Bylece trn


kullanmnda artk enum anahtar szcnn kullanlmasna gerek kalmaz:
typedef enum tagRenk{SINEK, KARO, KUPA, MACA} Renk;
Bildiriminden sonra artk enum anahtar szc kullanlmadan
Renk kart1, kart2, kart3, kart4;
gibi bir tanmlama yaplabilir. typedef bildiriminden sonra artk Renk bir tr ismi belirtir.
imdi de aadaki rnee bakalm:
typedef enum {FALSE, TRUE} Bool;
Artk Bool ismi FALSE ve TRUE deerlerini alabilen bir trn ismidir.
[C++ dilinde yap, birlik ve numaralandrma trlerine ilikin isimler (tag) ayn zamanda trn genel ismi olarak
kullanlabilecei iin yukardaki gibi bir typedef bildirimine gerek yoktur.]

Numaralandrma Trlerinin Kullanm

enum bildirimi ile yeni bir tr yaratldna gre, bu trden nesne ya da gsterici
tanmlanabilir. Tanmlanacak ilevlerin geri dn deerleri ve/veya parametre
deikenleri de byle bir trden olabilir:
typedef enum {Sunday, Monday, Tuesday, Wednesday, Thursday,
Friday, Saturday}Days;
typedef struct {int d, m, y}Date;
Bir yap trnn bildiriminde, elemanlar bir numaralandrma trnden seilebilir:
typedef struct {
Days day;
Months month;
int year;
}Date;

423

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yukardaki rnekte Date isimli yap trnn day ve month isimli elemanlar Days ve
Months isimli numaralandrma trlerindendir.

Numaralandrma Deimezleri Deimez fadesi Olarak


Kullanlabilir

Bir numaralandrma deimezi bir deimez ifadesi (constant expression) oluturur. Bu


yzden numaralandrma deimezleri deimez ifadesi gereken yerlerde kullanlabilir.
Aadaki kodu inceleyin:
enum {MIN_SIZE = 100, AVERAGE_SIZE = 500, MAX_SIZE = 1000};
void func()
{
int a[MIN_SIZE];
int b[AVERAGE_SIZE];
int c[MAX_SIZE];
/***/
}
Yukardaki main ilevinin iinde tanmlanan a, b ve c isimlerinin boyutlar numalandrma
deimezleri ile belirlenmitir. Numaralandrma deimezlerin switch deyiminin case
ifadeleri olarak kullanlmalar ok sk karlalan bir durumdur:
Renk renk;
/***/
switch (renk) {
case SINEK: /***/
case KARO : /***/
case KUPA : /***/
case MACA : /***/
}

Numaralandrma Trleri ile #define Deimezlerinin


Karlatrlmas

#define nilemci komutu nilemci programa ilikindir. Fakat numaralandrma


deimezleri derleme aamasnda ele alnr.
Bir #define simgesel deimezi iin bilinirlik alan diye bir kavram sz konusu deildir,
nk bilinirlik alan derleyicinin anlamlandrd bir kavramdr. Ancak numaralandrma
trleri ve deimezleri iin bilinirlik alan kurallar geerlidir. Eer bir numaralandrma
tr, bir ilev iinde bildirilmise bu tre ilikin numaralandrma deimezleri sz konusu
ilevin dnda bilinmez.
Birden fazla #define simgesel deimezi, mantksal bir iliki iinde kullanlsa bile,
derleyici bu ilikinin farknda olmaz. Bu yzden, derleyici programn, bu simgesel
deimezlerin yanl kullanmna ilikin bir uyar iletisi retme ansna sahip olmaz. Ancak
derleyici ayn tr kapsamnda bildirilen numaralandrma deimezlerinin arasndaki
mantksal ilikinin farkndadr. Bunlarn yanl kullanlmas durumunda uyar iletisi
retebilir.
Numaralandrma deimezleri de #define komutuyla tanmlanm simgesel deimezler
gibi, nesne belirtmez. rnein :
enum METAL {Demir, Bakir, Kalay, Cinko, Kursun};
/***/
Kalay = 3;
/* Geersiz */

424

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Numaralandrma deimezleri, mantksal iliki iinde bulunan belirli sayda tanmlamalar


iin tercih edilir. Mantksal iliki iindeki baz isimlerin bir tr kapsam altnda ele alnmas
okunabilirlii artrr. rnein:
enum Gun {Pazartesi, Sali, Carsamba, Persembe, Cuma, Cumartesi, Pazar};
Derleyicilerin sistemlere ynelik salad balk dosyalarnda, birok numaralandrma
tr ve bu trlere ilikin numaralandrma deimezleri tanmlanr. rnein aadaki
numaralandrma bildirimi 80x86 sistemlerinde alan bir Borland derleyicisinin graphics.h
isimli balk dosyasndan alnmtr:
enum COLORS {
BLACK,
BLUE,
GREEN,
CYAN,
RED,
MAGENTA,
BROWN,
LIGHTGRAY,
DARKGRAY,
LIGHTBLUE,
LIGHTGREEN,
LIGHTCYAN,
LIGHTRED,
LIGHTMAGENTA,
YELLOW,
WHITE
};

Numaralandrma Trlerine likin Tr Dnmleri

C dilinde bir numaralandrma tr derleyici tarafndan fiziksel olarak int tr biiminde


ele alnr. Numaralandrma trleri ile dier doal trler arasnda otomatik tr dnm
sz konusudur. rnein bir numaralandrma deikenine int tden bir deer atanabilir.
Ya da int trden bir deikene bir numaralandrma deimezi atanabilir:
typedef enum {OFF, HOLD, STANDBY, ON}Position;
void func()
{
Position pos = 2;
int x = ON;
/***/
}

/* Geerli */
/* Geerli */

Ancak numaralandrma deikenlerine dier doal trlerden atama yapldnda tr


dntrme ilecinin kullanlmas programn okunabilirliini artrr:
pos = (Position)2;

Numaralandrma Deimezlerinin Ekrana Yazdrlmas

Bir numaralandrma deeri ekrana standart printf ileviyle %d format karakteriyle


elenerek yazdrlabilir. Numaralandrma deimezinin tamsay deerini deil de ismini
ekrana yazdrmann dorudan bir yolu yoktur. Bu amala bir ilev yazlabilir:

425

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
#include <stdlib.h>
typedef enum {Sunday, Monday, Tuesday, Wednesday, Thursday, Friday,
Saturday}Days;
void print_day(Days day)
{
static const char *days[] = {"Sunday", "Monday", "Tuesday",
"Wednesday", "Thursday", "Friday", "Saturday"};
printf("%s ", days[day]);
}
int main()
{
Days day;
int k;
for (k = 0; k < 10; ++k) {
day = (Days)(rand() % 7);
print_day(day);
}
}

return 0;

426

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

BTSEL LELER
Bitsel ileler (bitwise operators), bir tamsaynn bitleri zerinde ilemler yapar. Daha ok
sistem programlarnda ya da dk seviyeli kodlarda kullanlrlar. Bitsel ilelerin ortak
zellikleri, ileme soktuklar tamsaylar bir btn olarak deil, bit bit ele almalardr. Bu
ilelerin terimleri tamsay trlerinden olmak zorundadr. Terimlerinin gerek say
trlerinden olmas geersizdir.
C dilinde toplam 11 bitsel ile vardr. Aadaki tabloda bitsel ileler kendi aralarndaki
ncelik srasna gre listeleniyor:
ncelik
seviyesi
2
5
8
9
10
14

simge
~
<<
>>
&
^
|
<<=
>>=
&=
^=
|=

ile
Bitsel deil (bitwise not)
Bitsel sola kaydrma (bitwise left shift)
Bitsel saa kaydrma (bitwise right shift)
Bitsel ve (bitwise and)
Bitsel zel veya (bitwise exor)
Bitsel veya (bitwise or)
Bitsel ilemli atama ileleri
(bitwise compound assignment operators)

Yukardaki ileler iinde, yalnzca "Bitsel deil" (bitwise not) ileci, tek terimli nek
konumunda (unary prefix) bir iletir. Dierleri iki terimli (binary) araek konumunda
(infix) bulunan ilelerdir.

Bitsel Deil leci


Bitsel deil ileci (bitwise not), dier tm tek terimli ileler gibi ile ncelik tablosunun
ikinci seviyesindedir.
Bu ile, terimi olan tamsaynn bitleri zerinde 1'e tmleme ilemi yaparak bir deer elde
eder. Yani terimi olan tamsay deerinin 1 olan bitlerini 0, 0 olan bitlerini 1 yaparak deer
retir. lecin yan etkisi (side effect) yoktur. lecin terimi bir nesne ise, bu nesnenin
deeri deitirilmez.
Aada program inceleyin:
#include <stdio.h>
int main()
{
unsigned int x = 0x1AC3;
unsigned int y;
y = ~x;
printf("y = %X\n", y);

return 0;

Yukardaki programn, int trnn 4 byte olduu bir sistemde derlendiini dnelim. x
deikenine atanan 0x1AC3 deeri, ikilik say sisteminde aadaki biimde ifade edilir:
0000 0000 0000 0000 0001 1010 1100 0011
427

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Bu durumda y deikenine atanan deer


1111 1111 1111 1111 1110 0101 0011 1100
olur. printf ilevi ekrana
y = FFFFE53C
yazar. imdi de aadaki program derleyerek altrn:
#include <stdio.h>
int main()
{
int x = 0;
int y = ~x;
printf("y = %d\n", y);
return 0;
}
aretli ikilik say sisteminde, 0'n bire tmleyeni -1 deeridir, deil mi?

Bitsel Kaydrma leleri

ki tane bitsel kaydrma ileci (bitwise shift operator) vardr:

Bitsel saa kaydrma ileci >> (bitwise right shift)


Bitsel sola kaydrma ileci << (bitwise left shift)
Her iki ile de, ncelik tablosunun 5. seviyesinde bulunur. Dolaysyla bu ilelerin
ncelii tm aritmetik ilelerden daha dk, fakat karlatrma ilelerinden daha
yksektir. Bitsel kaydrma ileleri iki terimli araek konumundaki (binary infix) ilelerdir.
Bitsel sola kaydrma ileci, soldaki terimi olan tamsaynn, sadaki terimi olan tamsay
kadar sola kaydrlmasndan elde edilen deeri retir. Snr dna kan bitler iin, saynn
sandan 0 biti ile besleme yaplr. rnek:
#include <stdio.h>
int main()
{
unsigned int x = 52;
unsigned int y = 2;
unsigned int z;
z = x << y;
printf("z = %u\n", z);
}

/* x = 0000 0000 0011 0100 */

/* z = 0000 0000 1101 0000


/* z = 208 */

*/

return 0;

Bir tamsayy, sola bitsel olarak 1 kaydrmakla o tamsaynn ikiyle arplm deeri elde
edilir.
Bitsel saa kaydrma ileci, soldaki terimi olan tamsaynn, sadaki terimi olan tamsay
kadar saa kaydrlmasndan elde edilen deeri retir. Sol terim iaretsiz (unsigned) bir
tamsay trnden ise, ya da iaretli (signed) bir tamsay trnden ancak pozitif deere
sahip ise, snr dna kan bitler yerine, saynn solundan besleme 0 biti ile yaplr. Saa
kaydrlacak ifadenin iaretli bir tamsay trnden negatif deerli olmas durumunda snr

428

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

dna kan bitler iin soldan yaplacak beslemenin 0 ya da 1 bitleriyle yaplmas


derleyiciye baldr (implementation specified). Yani derleyiciler bu durumda saynn
iaretini korumak iin soldan yaplacak beslemeyi 1 biti ile yapabilecek bir kod
retebilecekleri gibi, saynn iaretini korumay dnmeksizin 0 biti ile besleyecek bir
kod da retebilirler. aretli negatif bir tamsaynn bitsel saa kaydrlmas tanabilir bir
zellik deildir.
Bir tamsayy saa bitsel olarak 1 kaydrmakla, o saynn ikiye blnm deeri elde
edilir:
#include <stdio.h>
int main()
{
unsigned int x = 52;
unsigned int y = 2;
unsigned int z = x >> y;
printf("z = %u\n", z);
}

/* x = 0000 0000 0011 0100 */


/* z = 0000 0000 0000 1101 */
/* z = 13

*/

return 0;

Bitsel kaydrma ilelerinin yan etkileri yoktur. Yani sol terimleri bir nesne ise, bu
nesnenin bellekteki deeri deimez. Kaydrma ilemi ile sol terim olan nesnenin deeri
deitirilmek isteniyorsa, bu ilelerin ilemli atama biimleri kullanlmaldr.
Kaydrma ilelerinin sa terimi, sol terimin ait olduu trn toplam bit saysndan daha
kk olmaldr. Bu koul salanmam ise oluan durum tanmszdr (undefined
behaviour). rnein Windows sistemlerinde int trden bir deerin 32 ya da daha fazla
sola ya da saa kaydrlmas tanmszdr. Bu durumdan kanlmaldr.
Bitsel kaydrma ilelerinin ncelik yn soldan saadr:
x << 4 >> 8
x, 2 byte'lk iaretsiz bir tamsay deiken olsun. Yukardaki ifade derleyici tarafndan
x << 4) >> 8
biiminde ele alnr. Bu ifade ile x deikeninin ortadaki 8 biti elde edilir.

Bitsel ve leci

"Bitsel ve" ileci (bitwise and), ile ncelik tablosunun 8. seviyesindedir. Bu seviyenin
ncelik yn soldan saadr. lecin yan etkisi yoktur. Terimleri nesne gsteren bir ifade
ise, bu terimlerin bellekteki deeri deimez. Deer retmek iin terimi olan tamsaylarn
karlkl bitlerini "ve" ilemine sokar. "Ve" ilecine ilikin ilem tablosu tablosu aada
yeniden veriliyor:

429

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

"Bitsel ve" ilecinin rettii deer, terimlerinin karlkl bitlerinin "ve" ilemine
sokulmasyla elde edilen deerdir:
#include <stdio.h>
int main()
{
unsigned int x = 0x1BC5;
unsigned int y = 0X3A0D;
unsigned int z = x & y;
printf("z = %X\n", z);
}

/*
/*
/*
/*

x
y
z
z

=
=
=
=

0001 1011 1100 0101 */


0011 1010 0000 1101 */
0001 1010 0000 0101 */
0x1A05 */

return 0;

1 biti "bitsel ve" ileminde etkisiz elemandr.


0 biti "bitsel ve" ileminde yutan elemandr.
"Mantksal ve" ileci yerine yanllkla "bitsel ve" ilecini kullanmak sk yaplan bir
hatadr. Aadaki kodu dikkatli bir ekilde inceleyin:
#include <stdio.h>
int main()
{
int x = 85;
int y = 170;
if (x && y)
printf("dogru!\n");
else
printf("yanlis!\n");
if (x & y)
printf("dogru!\n");
else
printf("yanlis!\n");
}

return 0;

Yukardaki programda "mantksal ve" (&&) ileci yerine yanllkla "bitsel ve" (&) ileci
kullanlyor. Hem "mantksal ve" hem de "bitsel ve", iki terimli, araek konumunda
ilelerdir. Derleyiciler yukardaki kod iin bir hata ya da uyar iletisi retmez. Yukardaki
rnekte "mantksal ve" ilecinin kullanlmas durumunda, mantksal "doru" biiminde
yorumlanacak olan ifade, bitsel ve ilecinin kullanlmasyla 0 deeri retir, mantksal
"yanl" olarak yorumlanr.

Bitsel zel Veya leci

Bitsel "zel veya" ileci (bitwise exor) ile ncelik tablosunun 9. seviyesindedir. ncelik
yn soldan saadr. Yan etkisi yoktur, terimleri olan nesnelerin bellekteki deeri
deimez. Deer retmek iin, terimi olan tamsaylarn karlkl bitlerini zel veya
(exclusive or) ilemine sokar. Bitsel "zel veya" ilecine ilikin ilem tablosu aada
veriliyor:

430

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yukardaki tablo yle zetlenebilir: Terimlerinden ikisi de ayn deere sahip ise, retilen
deer 0, terimlerden biri dierinden farkl ise retilen deer 1 olur.
#include <stdio.h>
int main()
{
unsigned int x = 0x1BC5;
unsigned int y = 0X3A0D;
unsigned int z = x ^ y;
printf("z = %X\n", z);
return 0;
}

/*
/*
/*
/*

x
y
z
z

=
=
=
=

0001
0011
0010
21C8

1011 1100 0101 */


1010 0000 1101 */
0001 1100 1000 */
*/

Bir tamsay, arka arkaya ayn deerle bitsel zel veya ilemine sokulursa, tamsaynn
kendi deeri elde edilir:
#include <stdio.h>
int main()
{
unsigned int a = 0X1BC5;
unsigned int b = 0X3A0D;
a ^= b;
a ^= b;
printf("a = %X\n", a);

/* a = 0001 1011 1100 0101 */


/* b = 0011 1010 0000 1101 */
/* a = 0010 0001 1100 1000*/
/* b = 0001 1011 1100 0101 */
/* a = 0X1BC5 */

return 0;
}
Baz ifreleme algoritmalarnda "zel veya" ileminin bu zelliinden faydalanlr.

Bitsel Veya leci

"Bitsel veya" (bitwise or operator) ileci, ile ncelik tablosunun 10. seviyesindedir.
ncelik yn soldan saadr. Yan etkisi yoktur, terimleri nesne gsteren bir ifade ise
bellekteki deerlerini deitirmez. Deer retmek iin terimi olan tamsaylarn karlkl
bitlerini "veya" ilemine sokar. Bitsel veya ilecine ilikin ilem tablosu aada veriliyor:

Bitsel veya ileci, terimlerinin karlkl bitlerinin "veya" ilemine sokulmasyla elde edilen
deeri retir:

431

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
int main()
{
unsigned int x = 0x1BC5;
unsigned int y = 0X3A0D;
unsigned int z = x | y;
printf("z = %X\n", z);
}

/*
/*
/*
/*

x
y
z
z

=
=
=
=

0001 1011 1100 0101 */


0011 1010 0000 1101 */
0011 1011 1100 1101 */
0x3BCD */

return 0;

0 biti bitsel veya ileminde etkisiz elemandr. 1 biti bitsel ve ileminde yutan elemandr.
Aadaki programda bitsel ve, zel veya, veya ilelerinin rettikleri deerler ikilik say
sisteminde ekrana yazdrlyor. Program derleyerek altrn:
#include <stdio.h>
#include <stdlib.h>
void bit_print(int val)
{
char bits[sizeof(val) * 8 + 1];
itoa(val, bits, 2);
printf("%10d %032s\n", val, bits);
}
int main()
{
int x, y;
printf("iki sayi giriniz ");
scanf("%d%d", &x, &y);
bit_print(x);
bit_print(y);
printf("bitsel ve islemi\n");
bit_print(x & y);
printf("*********************************************************\n");
printf("bitsel ozel veya islemi\n");
bit_print(x ^ y);
printf("*********************************************************\n");
printf("bitsel veya islemi\n");
bit_print(x | y);
return 0;
}

Bitsel leler Ksa Devre Davran Gstermez

Bitsel ileler ksa devre davranna sahip deidir. Yani bu ilelerin her iki terimi de
mutlaka ilenir.

Bitsel lemli Atama leleri

Bitsel deil ilecinin dnda, tm bitsel ilelere ilikin ilemli atama ileleri vardr. Daha
nce de sylendii gibi bitsel ilelerin yan etkileri (side effect) yoktur. Bitsel ileler
terimleri olan nesnelerin bellekteki deerlerini deitirmez. Eer terimleri olan nesnelerin
deerlerinin deitirilmesi isteniyorsa bu durumda ilemli atama ileleri kullanlabilir:

432

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

x
x
x
x
x

=
=
=
=
=

x
x
x
x
x

<< y
>> y
& y
^ y
| y

yerine
yerine
yerine
yerine
yerine

x
x
x
x
x

<<= y
>>= y
&= y
^= y
|= y

kullanlabilir.
Bitsel zel veya ilemli atama ileci, tamsay trlerinden iki deikenin deerlerinin, geici
bir deiken olmakszn takas (swap) edilmesinde de kullanlabilir:
#include <stdio.h>
int main()
{
int x, y;
printf("iki sayi giriniz ");
scanf("%d%d", &x, &y);
printf("x = %d\ny = %d\n", x, y);
x ^= y ^= x ^= y;
printf("x = %d\ny = %d\n", x, y);
}

return 0;

Yukardaki programda, x ve y deikenlerinin deerleri bitsel zel veya ilecinin


kullanlmasyla takas ediliyor.

Bitsel lelerin Kullanlmasna likin Baz Temalar

Bitsel ilelerin kullanlmasna daha ok sistem programlarnda rastlanr. Sistem


programlarnda bir tamsaynn bitleri zerinde baz ilemler yaplmas sklkla gerekli olur.
Aada bitsel dzeyde sk yaplan ilemler aklanyor:

Bir Tamsaynn Belirli Bir Bitinin Birlenmesi

Buna tamsaynn belirli bir bitinin "set edilmesi" de denebilir. Bir tamsaynn belirli bir
bitini birlemek iin, sz konusu tamsay, ilgili biti 1 olan ve dier bitleri 0 olan bir sayyla
"bitsel veya" ilemine sokulmaldr. nk bitsel veya ileminde 1 yutan eleman 0 ise
etkisiz elemandr.
Aadaki rnekte bir saynn 5. biti birleniyor:
#include <stdio.h>
int main()
{
int ch = 0x0041;
int mask = 0x0020;
ch |= mask;
printf("ch = %d\n", ch);

/* ch = 65 (0000 0000 0100 0001) */


/* mask = 32 (0000 0000 0010 0000) */
/* ch = 97 (0000 0000 0110 0001)
/* ch = 97 */

*/

return 0;
}
x bir tamsay k da bu saynn herhangi bir bit numaras olmak zere bir tamsaynn k.
bitini birleyecek bir ifade u biimde yazlabilir:
x |= 1 << k

433

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Byle ilemleri gerekletirmek iin kullanlan 1 << k gibi ifadelere "bitsel maske"
(bitmask) ya da yalnzca "maske" denir.

Bir Tamsaynn Belirli Bir Bitinin Sfrlanmas

Bir tamsaynn belirli bir bitini sfrlamak(clear) iin, sz konusu tamsay, ilgili biti 0 olan
ve dier bitleri 1 olan bir maskeyle "bitsel ve" ilemine sokulmaldr. nk "bitsel ve"
ileminde, 0 yutan eleman 1 ise etkisiz elemandr. Aadaki rnekte bir tamsaynn 5.
biti sfrlanyor:
#include <stdio.h>
int main()
{
int ch = 0x0061;
int mask = ~0x0020;
ch &= mask;
printf("ch = %d\n", ch);

/*
/*
/*
/*

ch =
mask
ch =
ch =

97 (0000 0000 0110 0001)


*/
= ~32 (1111 1111 1101 1111)*/
65 (0000 0000 0100 0001)
*/
65 */

return 0;
}
x, bir tamsay, k da bu saynn herhangi bir bit numaras olmak zere, bir saynn k. bitini
sfrlayan bir ifade aadaki gibi genelletirilebilir:
x

&= ~(1 << k);

Bir Tamsaynn Belirli Bir Bit Deerinin Elde Edilmesi (0 m 1 mi)

Bir tamsaynn belirli bir bitinin 0 m 1 mi oldugunun renilmesi iin, sz konusu


tamsay, ilgili biti 1 olan ve dier bitleri 0 olan bir maskeyle "bitsel ve" ilemine sokularak
mantksal olarak yorumlanmaldr. nk "bitsel ve" ileminde 0 yutan eleman, 1 ise
etkisiz elemandr. fade mantksal olarak "dogru" biiminde yorumlanrsa, ilgili bit 1,
yanl olarak yorumlanrsa ilgili bit 0 demektir.
x bir tamsay, k da bu saynn herhangi bir bit numaras olmak zerebir saynn k. bitinin
1 ya da 0 olduunu snayan bir deyim aadaki biimde yazlabilir:
if (x & 1 << k)
/* k. bit 1 */
else
/* k. bit 0 */
Bir pozitif tamsaynn tek say olup olmad "bitsel ve" ileciyle snanabilir. Bir tamsay
tek say ise saynn 0. biti 1 dir.
#include <stdio.h>
int main()
{
int x;
printf("bir sayi giriniz ");
scanf("%d", &x);
if (x & 1)
printf("%d tek sayi\n", x);
else
printf("%d cift sayi\n", x);
}

return 0;

434

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Bir Tamsaynn Belirli Bir Bitini Ters evirmek

Baz uygulamalarda bir tamsaynn belirli bir bitinin deerinin ters evrilmesi (toggle flip) gerekir. Yani sz konusu bit 1 ise 0, 0 ise 1 yaplmaldr. Bu amala "bitsel zel veya"
ileci kullanlr. Bitsel zel veya ilecinde 0 biti etkisiz elemandr. Bir saynn k. bitinin
deerini deitirmek iin, say, k. biti 1 dier bitleri 0 olan bir maske ile "bitsel zel veya"
ilemine sokulur.
x, bir tamsay, k da bu saynn herhangi bir bit numaras olmak zere, bir saynn k. bitini
ters eviren bir ifade u ekilde yazlabilir:
x ^= 1 << k;

Birden Fazla Bit zerinde lem Yapmak

Bir tamsaynn belirli bitlerini sfrlamak iin ne yaplabilir? rnein int trden bir
tamsaynn 7., 8. ve 9. bitlerini, dier bitlerin deerlerini deitirmeden sfrlamak
isteyelim. Bunu gerekletirmek iin, tamsay 7., 8. ve 9. bitleri 0 olan dier bitleri 1 olan
bir maske ile bitsel ve ilemine sokulabilir. rnein int trnn 16 bit olduu bir sistemde
bu say aadaki bit dzenine sahip olur:
1111 1100 0111 1111
Bu deerin onaltlk say sisteminde gsterimi 0xFC7F biimindedir, deil mi?
x &= 0xFC7F;
Tamsaylarn belirli bitleri zerinde yaplan ileri, ilevlere yaptrmaya ne dersiniz?
void clearbits(int *ptr, size_t startbit, size_t nbits);
clearbits ilevi adresi gnderilen ifadenin startbit nolu bitinden balayarak nbits tane bitini
sfrlar.
rnein x isimli unsigned int trden bir deikenin 7. 8. 9. bitlerini sfrlamak iin ilev
aadaki biimde arlr:
clearbits(&x, 7, 3);
void clearbits(unsigned int *ptr, size_t startbit, size_t nbits)
{
size_t k;
for (k = 0; k < nbits; ++k)
*ptr &= ~(1 << nbits + k);
}
Benzer biimde setbits ilevi de yazlabilir. x isimli unsigned int trden bir deikenin 7.
8. 9. bitlerini birlemek iin ilev aadaki biimde arlr:
clearbits(&x, 7, 3);
void setbits(unsigned int *ptr, size_t startbit, size_t nbits)
{
size_t k;
for (k = 0; k < nbits; ++k)
*ptr |= ~(1 << nbits + k);
}
Peki rnein 32 bitlik bir alan birden fazla deeri tutacak ekilde kullanlabilir mi?

435

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Negatif saylarn kullanlmad dnlrse 4 bitlik bir alanda 0 15 aralndaki deerler


tutulabilir. Bir deikenin deerinin 0 15 aralnda deitiini varsayalm: Baz
durumlarda 4 bitle ifade edilebilen bir deerin 2 ya da 4 byte yer kaplayan bir tamsay
trnde tutulmas istenmeyebilir. 32 bitlik bir alan iinde aslnda 4 ayr deer tutulabilir,
deil mi?
Bir saynn belirli bir bit alannda bir tamsay deerini tutmak iin ne yaplabilir? nce
saynn ilgili bitleri sfrlanr. Bu ama iin yukarda yazlan clearbits gibi bir ilev
arlabilir. Daha sonra say, uygun bir deerle bitsel veya ilemine sokulabilir. Aadaki
ilev tanmn inceleyin:
void putvalue(unsigned int*ptr, size_t startbit, size_t nbits, int value)
{
clearbits(ptr, startbit, nbits);
*ptr |= value << startbit;
}
putvlaue ilevi adresi gnderilen nesnenin startbit nolu bitinden balayarak nbits bitlik
alanna value deerini yerletirir. lev aadaki gibi arlabilir:
putvalue(&x, 4, 3, 7);
Bir tamsay deikenin belirli bit alanlar iinde saklanm deer nasl elde edilebilir?
phesiz bu i de bir ileve yaptrlabilir:
unsigned getvalue(unsigned int x, size_t startbit, size_t nbits);
getvalue ilevi birinci parametresine aktarlan tamsay deerin, startbit numaral bitinden
balayarak nbits bitlik alannda saklanan deerle geri dner:
unsigned int getvalue(unsigned int number, size_t startbit, size_t nbits)
{
number <<= sizeof(int) * 8 - startbit - nbits;
return number >>= sizeof(int) * 8 - nbits;
}

Bitsel lelerin Kullanmna likin Baz rnek Uygulamalar

Aada int trden bir deeri, ekrana ikilik say sisteminde yazdran showbits isimli bir
ilev tanmlanyor:
#include <stdio.h>
void showbits(int x)
{
int i = sizeof(int) * 8 - 1;
for (; i >= 0; --i)
putchar (x >> i & 1 ? '1' : '0');
}
int main()
{
int val;

printf("bir sayi giriniz : ");


scanf("%d", &val);
showbits(val);
return 0;

Aada ayn ii deiik bir biimde yapan showbits2 isimli bir ilevin tanm yer alyor:

436

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

void showbits2(int x)
{
unsigned int i = (~((unsigned)~0 >> 1));

while (i) {
putchar (x & i ? '1' : '0');
i >>= 1;
}

Aada tammlanan reverse_bits isimli ilev, int trden bir deerin bitlerini ters eviriyor:
#include <stdio.h>
int reverse_bits(int number)
{
int k;
int no_of_bits = sizeof(int) * 8;
int rev_num = 0;
for (k = 0; k < no_of_bits; ++k)
if (number & 1 << k)
rev_num |= 1 << (no_of_bits - 1 - k);
return rev_num;
}
Aada tammlanan reverse isimli ilev, unsigned char trden bir deerin bitlerini ters
eviriyor:
#include <stdio.h>
unsigned char reverse(unsigned char byte)
{
unsigned char dest;
dest = (byte << 4) | (byte >> 4);
dest = ((dest << 2) & 0xCC) | ((dest >> 2) & 0x33);
}

return ((dest << 1) & 0xAA) | ((dest >> 1) & 0x55);

Aada tanmlanan no_of_setbits isimli ilev, kendisine gnderilen int trden bir deerin
ka tane bitinin 1 olduu bilgisi ile geri dnyor:
#include <stdio.h>
int no_of_setbits(unsigned int value)
{
int counter = 0;
int k;
for (k = 0; k < sizeof(int) * 8; ++k)
if (value & 1<<k)
counter++;
return counter;
}
int main()

437

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

int number;
printf("bir say girin : ");
scanf("%d", &number);
printf("saynzn %d biti 1n", no_of_setbits(number));

return 0;

imdi de ok daha hzl alacak bir ilev tasarlayalm:


int no_of_setbits(unsigned int value)
{
static int bitcounts[] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3,
4};
int counter = 0;
for (; value != 0; value >>= 4)
counter += bitcounts[value & 0x0F];
}

return counter;

Yukarda tannmlanan ilevde yer alan for dngs iinde, dngnn her turunda value
deikeninin dk anlaml 4 bitindeki birlenmi bitlerin says, 4 bitin saysal deerinin
bitcounts isimli diziye indis yaplmasyla elde ediliyor. rnein 4 bitlik alanda ifade edilen
tamsaynn deeri 11 olsun:
11 = 1011
Bu saynn toplam 3 biti 1'dir.
bitcounts dizisinin 11 indisli elemann deeri 3'tr. Dngnn bir sonraki turuna
gemeden nce value deikeni saa 4 kez kaydrlarak bu kez value'nun bir sonraki 4
bitlik alanndaki bitlere baklyor.
Aada ilem hzn daha da artran bir ilev tanmlanyor:
const
0, 1,
1, 2,
1, 2,
2, 3,
1, 2,
2, 3,
2, 3,
3, 4,
1, 2,
2, 3,
2, 3,
3, 4,
2, 3,
3, 4,
3, 4,
4, 5,
};

static char
1, 2, 1, 2,
2, 3, 2, 3,
2, 3, 2, 3,
3, 4, 3, 4,
2, 3, 2, 3,
3, 4, 3, 4,
3, 4, 3, 4,
4, 5, 4, 5,
2, 3, 2, 3,
3, 4, 3, 4,
3, 4, 3, 4,
4, 5, 4, 5,
3, 4, 3, 4,
4, 5, 4, 5,
4, 5, 4, 5,
5, 6, 5, 6,

bit_array[]
2, 3, 1, 2,
3, 4, 2, 3,
3, 4, 2, 3,
4, 5, 3, 4,
3, 4, 2, 3,
4, 5, 3, 4,
4, 5, 3, 4,
5, 6, 4, 5,
3, 4, 2, 3,
4, 5, 3, 4,
4, 5, 3, 4,
5, 6, 4, 5,
4, 5, 3, 4,
5, 6, 4, 5,
5, 6, 4, 5,
6, 7, 5, 6,

= {
2, 3,
3, 4,
3, 4,
4, 5,
3, 4,
4, 5,
4, 5,
5, 6,
3, 4,
4, 5,
4, 5,
5, 6,
4, 5,
5, 6,
5, 6,
6, 7,

2,
3,
3,
4,
3,
4,
4,
5,
3,
4,
4,
5,
4,
5,
5,
6,

3,
4,
4,
5,
4,
5,
5,
6,
4,
5,
5,
6,
5,
6,
6,
7,

3,
4,
4,
5,
4,
5,
5,
6,
4,
5,
5,
6,
5,
6,
6,
7,

4,
5,
5,
6,
5,
6,
6,
7,
5,
6,
6,
7,
6,
7,
7,
8

int count1bits(unsigned long x)


{

438

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

return bit_array[x & 0xff] + bit_array[(x >> 8) & 0xff] +


bit_array[(x >> 16) & 0xff] + bit_array[(x >>24) & 0xff];
}

count1bits ilevi 32 bitlik bir tamsaynn deeri 1 olan bitlerini sayyor. lev bu ii
yaparken 8 bitlik bir gruptaki 1 olan bitlerin saysn bit_array dizisini kullanarak buluyor.
Aada tanmlanan gcd_b ileviyle, iki tamsaynn ortak blenlerinden en by
hesaplanyor. levin tanm iinde kalan ilecinin kullanlmadna, bitsel ilelerin
kullanldna dikkat edin:
unsigned int gcd_b(unsigned int x, unsigned int y)
{
unsigned int temp;
unsigned int cpof = 0;
if (x == 0)
return y;
if (y == 0)
return x;
while (((x | y) & 1) == 0) {
x >>= 1;
y >>= 1;
++cpof;
}
while ((x & 1) == 0)
x >>= 1;

while (y) {
while (!(y & 1))
y >>= 1;
temp = y;
if (x > y)
y = x - y;
else
y -= x;
x = temp;
}
return x << cpof;

439

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

BT ALANLARI
Bir yapnn eleman bit seviyesinde tutulan bir tamsay deiken olabilir. Yaplarn byle
elemanlarna "bit alan" (bit fields) denir.
Bit alanlar, C'nin bit seviyesinde eriime olanak veren bir aracdr. Bit seviyesinde eriim
amacyla phesiz daha nceki konuda anlatlan bitsel ileler kullanlabilir. Ancak bit
alanlar programcya byle ulamlar iin daha kolay bir arayz sunar.
Bir yap iinde bir bit alan oluturmak iin zel bir szdizim kuralna uymak gerekir.
Elemann yap iindeki bildiriminde eleman ismini ':' atomu izler. Bu atomdan sonra bit
alannn ka bit yer kaplayaca bilgisini gsteren bir tamsay deimezi yazlr. Aadaki
bildirimi inceleyin:
struct Data {
unsigned int a: 5;
unsigned int b: 4;
unsigned int c: 7;
};
struct Data isimli yapnn a isimli eleman, yap iinde 5 bit yer kaplarken, b isimli eleman
4 bit, c isimli eleman 7 bit yer kaplar. Yapnn elemanlar unsigned int trnden olduuna
gre bu trden bir nesnenin
a eleman 0 - 31
b eleman 0 -15
c eleman 0 - 127
arasnda tamsay deerler tutabilir.

Bit Alan Elemanlarn Trleri

Bir bit alan eleman, iaretli ya da iaretsiz int trlerden olabilir. Bir bit alan eleman
gerek say trlerinden olamaz. C standartlar bit alan elemanlarnn char, short, long
trlerinden olamayacan belirtse de C derleyicilerin ou seimlik olarak bu duruma izin
verir. Tanabilirlik asndan bit alan elemann bildiriminde signed ya da unsigned
szcklerinin kullanlmas yerinde olur. nk derleyici yalnzca int anahtar szcyle
bildirilen bir bit alannn trn iaretli ya da iaretsiz int tr olarak alabilir.
Bit alan eleman bir dizi olamaz.

Bit Alanlar Neden Kullanlr:

Baz dsal aygtlar verileri bitsel dzeyde iletiyor olabilir.


Baz sktrma ilemlerinde bir tamsaynn belirli sayda biti kullanlyor olabilir.
Baz ifreleme ilemlerinden bir tamsaynn belirli bit alanlarnda yaplan kodlama yapyor
olabilir.
ok sayda bayrak deikeni bit alanlar olarak tutulabilir.
phesiz bu ilemleri yapmak iin bitsel ileler de kullanlabilir. Ancak bit alanlar bu
ilerin yaplmas iin programcya ok daha kolay bir arayz sunar, programcnn iini
kolaylatrr.
rnein DOS iletim sistemi dosyalara ilikin tarih ve zaman bilgilerini 16 bitlik alanlarda
tutar:

441

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

struct file_date
unsigned int
unsigned int
unsigned int
};

{
day: 5;
mon: 4;
year: 7;

Yukardaki bildirimden de grld gibi, tarih bilgisinin yl iin 7 bitlik bir alan
ayrlmtr. 7 bitlik bir alanda tutulabilecek en byk deer 127 dir. DOS iletim
sisteminde byle bir bit alannda yl deerinin 1980 fazlas tutulur.
Aadaki ilev file_date yaps iinde tutulan tarih bilgisini ekrana yazdryor:
void display_file_date(const file_date *ptr)
{
printf("%02u/%02u/%u", ptr->day, ptr->mon, ptr->year);
}
Bir yapnn bit alan elemanlarna, yine nokta ya da ok ileleriyle eriilir. phesiz,
derleyicinin rettii kod bitsel ilemlerin yaplmasn salar.
Bu kez zaman bilgisini tutmak iin elemanlar bit alanlar olan bir yap bildiriliyor:
struct file_time
unsigned int
unsigned int
unsigned int
};

{
hour: 5;
min: 6;
sec: 5;

Zaman bilgisinin saniye deeri iin 5 bitlik bir alan ayrlyor. 5 bitlik bir alanda
tutulabilecek en byk deer 31'dir. DOS iletim sisteminde, byle bir bit alannda gerek
saniye deerinin yars tutulur.
Aadaki ilev file_time yaps iinde tutulan zaman bilgisini ekrana yazdryor:
void display_file_date(const file_time *ptr)
{
printf("%02u:%02u%u", ptr->hour, ptr->min, 2 * ptr->sec);
}

Bitalan Elemanlarn Adresleri

Bir bitalan elemann adresi alnamaz. Bir bit alan elemann adres ilecinin terimi olmas
geersizdir:
#include <stdio.h>
void func();
{
struct file_date fdate;
scanf("%d", &fdate.day);
/***/

/* Geersiz */

Bit Alanlarnn Bellekte Yerleimi

Bir bit alannn bellekte yerleimi konusunda derleyiciler geni lde serbest
braklmtr. Bit alanlarnn bellekte yerleimi "saklama birimi" (storage unit) isimli bir
terimle aklanr. Saklama birimi, belirli bir byte uzunluudur ve derleyicinin seimine
baldr. rnein derleyicinin setii saklama birimi 1, 2, 4 vs. byte olabilir.
Bit alanlarnn bildirimiyle karlaan derleyici bit alanlarn, aralarnda boluk brakmadan
tek bir saklama birimine yerletirmeye altrr. Saklama biriminde bir bit alan iinde
yeteri kadar yer kalmaz ise bir sonraki saklama birimine geilir. Smayan elemann her

442

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

iki saklama biriminde mi tutulaca yoksa tamamen yeni saklama biriminde mi yer
alaca derleyicinin seimine braklmtr. Bir elemann ilgili bit alan iinde yerleiminin
soldan saa ya da sadan sola olmas da yine derleyicinin seimine braklmtr.
Bir bit alan uzunluu saklama biriminin kendi uzunluundan daha byk olamaz.
rnein saklama birimi 8 bit ise 9 bitlik bir bit alan eleman kullanlmaz.
Bit alan elemanlarn yerleimi zerinde daha fazla denetimin salanmas iin, elemana
isim vermeme olana da getirilmitir. Bir bit alan elemana isim verilmeyebilir. smi
olmayan bir bit alan eleman ii derleyici yine gerekli yeri ayrr. Bylece programc
kullanaca elemanlarn isel yerleimini kendine gre ayarlayabilir.
typedef struct {
int
: 5;
int hour
: 5;
int min
: 6;
}Time;
Yukardaki rnekte Time yapsnn isim verilmeyen birinci eleman iin, derleyici yine 5 bit
ayrr. Yani yapnn hour isimli eleman 5. bitten balayarak yerletirilir.
Bir baka olanak da, bit alan elemann uzunluunu 0 olarak belirlemektir. Bunun
nceden belirlenmi zel bir anlam vardr. Bir elemann uzunluunun 0 olduunu gren
derleyici bir sonraki elaman yeni bir saklama biriminden balatr:
Aadaki ilgili sistemin saklama birimi uzunluu bit says olarak elde ediliyor:
#include <stdio.h>
#include <limits.h>
typedef struct {
int : 1;
int : 0;
int : 1;
}StorageCheck;
int main()
{
printf("Saklama birimi = %u bit\n", sizeof(StorageCheck) / 2 *
CHAR_BIT);
}

return 0;

Yukardaki rnekte StorageCheck isimli yap tanmlanyor. Bu yapnn isim verilmeyen ilk
bitalan eleman iin 1 bit yer ayrldn gryorsunuz. kinci eleman iin ise uzunluk 0
olarak belirleniyor. Son elemann uzunluu yine 1 bitdir. Derleyici 3. eleman iin gereken
yeri bir sonraki saklama biriminden ayrr. Bu durumda eer saklama birimi 8 bit ise
yapnn toplam uzunluu 16 bit, saklama birimi 16 bit ise yapnn uzunluu 32 bit nihayet
saklama birimi 32 bit ise yapnn uzunluu 64 bit olur.

443

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

KOMUT SATIRI ARGMANLARI


Bir program altrld zaman, programn almasn ynlendirecek ya da deitirecek
baz parametreler, alacak programa gnderilmek istenebilir. Programa gnderilecek bir
parametre rnein bir dosya ismi olabilecei gibi, programn deiik biimlerde
almasn salayacak bir seenek de olabilir. UNIX iletim sistemindeki ls komutunu
dnelim. Eer ls program
ls
yazarak altrlrsa, bulunulan dizin iindeki dosyalarn isimleri listelenir. Ama ls yerine
ls -l
yazlarak program altrlrsa bu kez yalnzca dosya isimleri deil, dizindeki dosyalarn
bykln, dosyalarn sahiplerini, yaratlma tarih ve zamanlarn vs. gsteren daha
ayrntl bir liste ekranda grntlenir. ls program yine
ls -l sample.c
yazarak altrlrsa, yalnzca sample.c dosyasna ilikin bilgiler grntlenir. te bir
program altrrken program isminin yanna yazlan dier parametrelere komut satr
argmanlar (command line arguments) denir.
Komut satr argmanlar yalnzca iletim sistemi komutlar iin geerli deildir. Tm
programlar iin komut satr argmanlar kullanlabilir. Komut satr argmanlarna C dili
standartlarnda program parametreleri (program parameters) denir.
C programlarnn almaya balad main ilevi de, istee bal olarak iki parametre
deikenine sahip olabilir. Bu parametre deikenleri geleneksel olarak argc ve argv
olarak isimlendirilir.
int main(int argc, char *argv[])
{
/***/
}
argc "argument count" szcklerinden ksaltlmtr. Komut satr argmanlarnn saysn
gsterir. Bu sayya programn ismi de dahildir. argv ise "argument vector" szcklerinden
ksaltlmtr. argv, dizgeler eklinde saklanan komut satr argmanlarn gsteren, char
trden bir gsterici dizisinin adresini alan gstericidir. Yani argv gstericisinin gsterdii
yerde bir gsterici dizisi vardr. Bu gsterici dizisinin her eleman, komut satr argman
olan yazlar tutar. Bu durumda argv[0] gstericisi programn ismi olan yaznn balang
adresini tutar. argv[1]'den argv[argc - 1] e kadar olan gstericiler ise program ismini
izleyen dier komut satr argman olan yazlarn balang adreslerini tutar.
argv[argc] gstericisi ise NULL adresi deerine sahiptir.
Yukardaki rnekte kullanc ls programn
ls -l sample.c
eklinde altrdnda
argc, 3 deerini alr.
argv[0], program ismini gsterir.
argv[0] = "ls";
argv[1] program ismini izleyen birinci argman gsterir.
argv[1] = "-l";

445

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

argv[2] program ismini izleyen ikinci argman gsterir.


argv[2] = "sample.c";
argv[argc] yani argv[3] ise NULL adresini gsterir.
Bir ilevin, gstericiyi gsteren gsterici (pointer to pointer) parametresinin iki ayr
biimde tanmlanabileceini anmsayn:
void func(char **ptr);
void foo(char *ptr[]);
Her iki ilevin de parametre deikeni char trden gstericiyi gsteren bir gstericidir. Bu
durumda, komut satr argmanlarn ileyecek bir main ilevinin de gstericiyi gsteren
gsterici olan argv parametresi, iki farkl biimde tanmlanabilir:
int main(int argc, char **argv)
{
/***/
}
int main(int argc, char **argv)
{
/***/
}
Komut satr argmanlar boluklarla birbirinden ayrlm olmaldr. Yukardaki rnekte
program
ls -lsample.c
biiminde altrlrsa
argc, 2 deerine sahip olurdu.
Komut satr argmanlar, iletim sistemi tarafndan komut satrndan alnarak derleyicinin
rettii giri kodu yardmyla main ilevine gnderilir.
Aada komut satr argmanlarn ekrana basan rnek bir program gryorsunuz:
#include <stdio.h>
int main(int argc, char *argv[])
{
int i;
for (i = 0; i < argc; ++i)
printf("argv[%d] : %s\n", i, argv[i]);
}

return 0;

main ilevinde yer alan dng deyimi aadaki biimde de yazlabilirdi:


for (i = 0; argv[i] != NULL ; ++i)
printf("argv[%d] : %s\n", i, argv[i]);
Komut satrndan altrlan programlar genellikle, nce girilen argmanlar yorumlar ve
snar. rnein bir dosyann kopyasn karmak zere, ismi kopyala olan bir programn,
komut satrndan altrlmak istendiini dnelim. Program, komut satrndan
kopyalanacak dosyann ismini ve yeni yaratlacak dosyann ismini istesin:

446

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

kopyala deneme.c test.c


Program komut satrndan yukardaki gibi altrldnda, ismi deneme.c olan bir
dosyann ismi test.c olan bir kopyasn olutursun. Bu durumda argc 3 degerini alr, deil
mi?
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
/***/
if (argc != 3) {
printf("kullanim : <kopyala> <kaynak dosya ismi> <yeni dosya
ismi>\n");
exit(EXIT_FAILURE);
}
/***/
return 0;
}
Yukardaki main ilevinde, program 3 komut satr argman verilerek altrlmadysa,
yani eksik ya da fazla argmanla altrldysa, program bir hata iletisiyle sonlandrlyor.
Komut satrndan argmanlar doru girilmedii zaman bir program sonlandrlmak
zorunda deildir. Dardan doru olarak girilemeyen argmanlarn bu kez, programn
almas durumunda program kullanan kii tarafndan girilmesi istenebilir.
Aadaki rnei inceleyin:
#include <stdio.h>
#include <string.h>
#define

NAME_LEN

80

int main(int argc, char *argv[])


{
char source_name[NAME_LEN];
char dest_name[NAME_LEN];

if (argc != 3) {
printf("kaynak dosyanin ismini giriniz : ");
gets(source_name);
printf("kopya dosyanin ismini giriniz : ");
gets(dest_name);
}
else {
strcpy(source_name, argv[1]);
strcpy(dest_name, argv[2]);
}
/***/
return 0;

DOS iletim sisteminde olduu gibi, baz sistemlerde main ilevi nc bir parametre
alabilir. nc parametre sistemin evre deikenlerine ilikin bir karakter trnden
gstericiyi gsteren gstericidir.
int main(int argc, char *argv[], char *env[])
{
/***/
}

447

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Aadaki programda, komut satrndan girilen szckler ters srada ve tersten


yazdrlyor:
#include <stdio.h>
int main(int argc, char **argv)
{
int k, i;
for (k = argc - 1; k > 0; --k) {
for (i = 0; argv[k][i] != '\0'; ++i)
;
for (i--; i >= 0; --i)
putchar(argv[k][i]);
putchar('\n');
}
}

return 0;

Aada, komut satrndan altrlacak basit bir hesap makinesi programnn kodu
veriliyor:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(int argc, char *argv[])
{
char ch;
int op1, op2;
if (argc != 4) {
printf("usage : cal Op1 Operator Op2\n");
exit(EXIT_FAILURE);
}
op1 = atoi(argv[1]);
op2 = atoi(argv[3]);
ch = argv[2][0];
printf(" = ");

switch (ch) {
case '+' :
case '-' :
case '/' :
case '*' :
case '%' :
case 'k' :
default :
}
return 0;

printf("%d\n", op1 + op2); return 0;


printf("%d\n", op1 - op2); return 0;
printf("%lf\n", (double)op1 / op2); return 0;
printf("%d\n", op1 * op2); return 0;
printf("%lf\n", (double)op1 * op2 / 100); return 0;
printf("%lf\n", pow(op1, op2)); return 0;
printf("hatal ile\n");

Aadaki program, komut satrndan gn, ay ve yl deerleri girilen bir tarihin haftann
hangi gnne geldiini ekrana yazdryor:

448

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
#include <stdlib.h>
char *days[] = {"Pazar", "Pazartesi", "Sali", "Carsamba", "Persembe",
"Cuma", "Cumartesi"};
int day_of_week(int d, int m, int y)
{
static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4,6, 2, 4};
y -= m < 3;
return (y + y / 4 - y / 100 + y / 400 + t[m - 1] + d) % 7;
}
int main(int argc, char **argv)
{
int day, mon, year;
if (argc != 4) {
printf("gun ay ve yil degerini giriniz : ");
scanf("%d%d%d", &day, &mon, &year);
}
else {
day = atoi(argv[1]);
mon = atoi(argv[2]);
year = atoi(argv[3]);
}
printf("%s\n", days[day_of_week(day, mon, year)]);
return 0;
}

449

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

DOSYALAR
kincil belleklerde tanmlanm blgelere dosya denir. Dosya ilemleri tamamen iletim
sisteminin kontrol altndadr. Her dosyann bir ismi vardr. Ancak dosyalarn
isimlendirme kurallar sistemden sisteme gre deiebilir.
letim sistemi de bir programdr. Bu program da ayr ayr yazlm ilevlerin birbirlerini
armas biiminde alr. rnein komut satrnda bir programn isminin yazlarak
altrlmas aslnda birka sistem ilevinin arlmas ile yaplr. Komut satrndan yazlan
yazy alan, diskte bir dosyay arayan, bir dosyay bellee ykleyen, bellekteki program
altran ilevler dzenli olarak arlr.
letim sisteminin almas srasnda kendisinin de ard, sistem programcsnn da
dardan arabildii iletim sistemine ait ilevlere sistem ilevleri denir. Bu tr ilevlere
Windows sisteminde API (Application Programming Interface) ilevleri, UNIX iletim
sisteminde ise sistem arlar (system calls) denir.
Aslnda btn dosya ilemleri, hangi programlama dili ile allrsa allsn, iletim
sisteminin sistem ilevleri tarafndan yaplr. Sistem ilevlerinin isimleri ve parametrik
yaplar sistemden sisteme deiebilir.

Dosyann Almas

Bir dosya zerinde ilem yapmadan nce dosya almaldr. Dosya aabilmek iin iletim
sisteminin "dosya a" isimli bir sistem ilevi kullanlr. Dosyann almas srasnda dosya
ile ilgili eitli ilk ilemler iletim sistemi tarafndan yaplr.
Bir dosya aldnda, dosya bilgileri, ismine "Dosya Tablosu" (File table) denilen ve
iletim sisteminin iinde bulunan bir tabloya yazlr. Dosya tablosunun biimi sistemden
sisteme deiebilir. rnein tipik bir dosya tablosu aadaki gibi olabilir:
Dosya tablosu
Sra No
0
1
...
12
...

Dosya ismi

Dosyann Diskteki Dosyann


Yeri
zellikleri

Dierleri

AUTOEXEC.BAT

...

...

...

letim sisteminin sistem ilevlerinin de parametre deikenleri, geri dn deerleri


vardr. "Dosya a" sistem ilevinin parametresi alacak dosyann ismidir.lev, dosya
tablosunda dosya bilgilerinin yazld sra numaras ile geri dner ki bu deere "file
handle" denir. Bu handle deeri dier dosya ilevlerine parametre olarak geirilir.
Dosyann almas srasnda buna ek olarak baka nemli ilemler de yaplr.

Dosyann Kapatlmas

Dosyann kapatlmas almas srasnda yaplan ilemlerin geri alnmasn salar. rnein
dosyann kapatlmas srasnda, iletim sisteminin dosya tablosunda bulunan bu dosyaya
ilikin bilgiler silinir. Alan her dosya kapatlmaldr. Bir dosyann kapatlmamas eitli
sorunlara yol aabilir.

Dosyaya Bilgi Yazlmas ve Okunmas

letim sistemlerinin dosyaya n byte veri yazan ve dosyadan n byte veri okuyan sistem
ilevleri vardr. Yazma ve okuma ilemleri bu ilevler kullanlarak yaplr.

451

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Dosya Konum Gstericisi


Bir dosya byte'lardan oluur. Dosyadaki her bir byte a 0'dan balayarak artan srada bir
say karlk getirilir. Bu sayya ilgili byte n ofset numaras denir. Dosya konum gstericisi
isel olarak tutulan long trden bir deikendir, bir ofset deeri yani bir byte numaras
belirtir. Dosyaya yazan ve dosyadan okuma yapan standart ilevler, bu yazma ve okuma
ilemlerini her zaman dosya konum gstericisinin gsterdii yerden yapar. Bu ilevler,
dosyann neresine yazlacan ya da dosyann neresinden okunacan gsteren bir deer
istemez. rnein dosya konum gstericisinin gsterdii yer 100. ofset olsun. Dosyadan
10 byte bilgi okumak iin bir sistem ilevi arldnda, 100. ofsetden balayarak 10 byte
bilgi okunur. letim sisteminin dosya gstericisini konumlandran bir sistem ilevi vardr.
Dosya ilk aldnda dosya konum gstericisi 0. ofseti gsterir. rnein bir dosyann 100.
byte ndan balayarak 10 byte okunmak istenirse sras ile u ilemlerin yaplmas
gerekir:
lgili dosya alr
dosya konum gstericisi 100. offset'e konumlandrlr
Dosyadan 10 byte okunur
Dosya kapatlr.
C dilinde dosya ilemleri iki biimde yaplabilir :
1. letim sisteminin sistem ilevleri dorudan arlarak.
2. Standart C ilevleri kullanlarak.
Bildirimleri stdio.h iinde olan standart dosya ilevlerinin hepsinin ismi f ile balar.
Standart C ilevleri da ilemlerini yapabilmek iin aslnda iletim sisteminin sistem
ilevlerini arr. letim sisteminin sistem ilevleri tanabilir deildir. simleri ve
parametrik yaplar sistemden sisteme deiebilir. Bu yzden standart C ilevlerinin
kullanlmas tavsiye edilir.

fopen levi
FILE *fopen (const char *fname, const char *mode);
levin birinci parametresi alacak dosyann ismidir. kinci parametre a modu bilgisidir.
Her iki bilgi de bir yaz olarak ileve iletilir. Dosya ismi yol bilgisi de ierebilir. Dizin
geileri iin '/' karakteri de kullanlabilir. Bir dosya belirli modlarda alabilir. A modu
bilgisi, alacak dosya ile ilgili olarak hangi ilemlerin yaplabileceini belirler. Yine a
modu bilgisi, almak istenen dosyann var olup olmamas durumunda ilevin nasl
davranacan belirler. Aadaki tabloda, fopen ilevine a modu bilgisini iletmek zere
geilmesi gereken yazlar listelenmitir:
Mod
"w"

"w+"

"r"
"r+"
"a"
"a+"

Anlam
Dosya yazmak iin alr. Dosyadan okuma yaplamaz. Dosyann var olmas
zorunlu deildir. Dosya yok ise verilen isimde bir dosya yaratlr. Dosya var ise
dosya sfrlanr.
Var olan bir dosyay bu modda amak dosyann kaybedilmesine neden olur.
Dosyay hem yazma ve okuma iin aar. Dosyann var olmas zorunlu deildir.
Dosya yok ise veriln isimde bir dosya yaratlr. Dosya var ise sfrlanr.
Var olan bir dosyay bu modda amak dosyann kaybedilmesine neden olur.
Dosya okumak iin alr. Dosyaya yazlamaz. Dosya yok ise alamaz.
Dosya hem okuma hem yazma iin alr. Dosya yok ise alamaz.
Dosya sona ekleme iin alr. Dosyadan okuma yaplamaz. Dosyann var
olmas zorunlu deildir. Dosya yok ise verilen isimde bir dosya yaratlr. Dosya
var ise dosya sfrlanmaz.
Dosyay sonuna ekleme ve dosyadan okuma iin aar. Dosyann var olmas
zorunlu deildir. Dosya yok ise verilen isimde bir dosya yaratlr. Dosya var ise
sfrlanmaz.

452

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

levin geri dn deeri FILE yaps trnden bir adrestir. lev, alan dosyaya ilikin
birtakm bilgileri FILE yaps trnden bir nesnenin elemanlarnda saklar ve bu nesnenin
adresini geri dndrr. levin geri dn deerine ilikin FILE yaps stdio.h balk
dosyas iinde bildirilmitir. Bu yapnn elemanlar standart deildir. Sistemden sisteme
deiiklik gsterebilir. Zaten programc bu yapnn elemanlarna gereksinim duymaz.
fopen ilevi iletim sisteminin dosya a sistem ilevini ararak dosyay aar ve dosyaya
ilikin baz bilgileri FILE yaps trnden bir nesnenin elemanlarna yazarak bu nesnenin
balang adresini geri dndrr. rnein "file handle" deeri de bu yapnn ierisindedir.
Tabi fopen ilevinin geri verdii FILE trnden adres gvenli bir adrestir. Dosya eitli
sebeplerden dolay alamayabilir. Bu durumda fopen ilevi NULL adresine geri dner.
levin geri dn deeri kesinlikle kontrol edilmelidir. Tipik bir snama ilemi aadaki
gibi yaplabilir:
/*..*/
FILE *f;
if ((f = fopen("mektup.txt", "r")) == NULL) {
printf("cannot open file"...\n);
exit(EXIT_FAILURE);
}
Yukardaki rnekte ismi mektup.txt olan bir dosya okuma amacyla almaya allyor.
Dosya almaz ise ekrana bir hata iletisi verilerek, standart exit ilevi ile program
sonlandrlyor. Yukardaki kod parasnn atama ilecinin rettii deerin nesneye atanan
deer olmasndan faydalandn gryorsunuz. phesiz fopen ilevi ile almak istenen
bir dosyann alamamas durumunda programn sonlandrlmas zorunlu deildir. Ancak
bundan sonra verilecek kod rneklerinde, bir dosyann almamas durumunda imdilik
program sonlandrlacak.
Dosya ismi dosyann yeri hakknda src, yol gibi bilgi ierebilir. Dosya ismi bir dizge ile
veriliyorsa yol bilgisi verirken dikkatli olmak gerekir. Yol bilgisi '\' (ters bl) karakteri
ierebilir. dizge iinde '\' karakterinin kullanlmas, '\ 'karakterininin onu izleyen
karakterle birlikte, nceden belirlenmi ters bl karakter deimezi (escape sequence)
olarak yorumlanmasna yol aabilir. rnein :
fopen("C:\source\new.dat", "r");
Yukardaki ilev arsnda derleyici '\n' karakterini "newline" karakteri olarak yorumlar
'\s' karakterini ise "undefined" kabul eder. Bu sorundan saknmak '\' karakteri yerine
'\\' kullanlmasyla mmkn olur:
fopen("C:\\source\\new.dat", "r");
Sona ekleme modlar ("a", "a+") ok kullanlan modlar deildir. Dosyaya yazma
durumunda "w" modu ile "a" modu arasnda farkllk vardr. "w" modunda dosyada olan
byte n zerine yazlabilir. "a" modunda ise dosya ierii korunarak sadece dosyann
sonuna yazma ilemi yaplabilir.
Bir dosyann hem okuma hem de yazma amacyla almas durumunda yani a modunu
belirten dizgede '+' karakterinin kullanlmas durumunda dikkatli olmak gerekir. Okuma
ve yazma ilemleri arasnda mutlaka ya dosya konum gstericisinin konumlandrlmas
(mesela fseek ilevi ile) ya da dosyaya iliken tampon bellek alannn (buffer) boaltlmas
gerekir. Bu konuya ileride ayrntl bir ekilde deinilecek.
Bir dosyann alp alamayaca aadaki kk programla snanabilir:
Program komut satrndan

453

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

canopen dosya.dat
eklinde altrldnda ekrana "dosya.dat dosyas alabilir" ya da "dosya.dat dosyas
alamaz" yazar.
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *fp;
if (argc != 2) {
printf("usage: canopen filename\n");
return 1;
}
if ((fp = fopen(argv[1], "r")) == NULL) {
printf("%s dosyas alamaz\n", argv[1]);
return 2;
}
printf("%s dosyas alabilir\n", argv[1]);
fclose(fp);
return 0;
}
stdio.h balk dosyas iinde FOPEN_MAX isimli bir simgesel deimez tanmlanyor.
FOPEN_MAX simgesel deikeni ayn zamanda alabilecek en byk dosya saysdr.

fclose levi

Standart bu ilevin stdio.h balk dosyas iindeki bildirimi aadaki gibidir:


int fclose(FILE *stream);
Bu ilev alm ola bir dosyay kapatr. lev fopen ya da fropen ilevinden elde edilen
FILE yaps trnden adresi parametre olarak alr ve ak olan dosyay kapatr. levin
geri dn deeri 0 ise dosya baarl olarak kapatlm demektir. levin geri dn
deeri EOF ise dosya kapatlamamtr.
EOF , stdio.h balk dosyas iinde tanmlanan bir simgesel deimezdir, derleyicilerin
ounda (-1) olarak tanmlanmtr:
#define

EOF

(-1)

levin baars ancak phe altnda snanmaldr. Normal koullar altnda dosyann
kapatlmamas iin bir neden yoktur.
#include <stdio.h>
int main()
{
FILE *f;
if ((f = fopen("mektup.txt", "w")) == NULL) {
printf("mektup.txt dosyas yaratlamyor!\n");
exit(EXIT_FAILURE);
}
fclose(f);
printf("mektup.txt dosyasi kapatildi!\n");
return 0;
}

454

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Derleyicilerin ounda bulunmasna karlk standart olmayan fcloseall isimli bir ilev de
vardr:
int fcloseall(void);
Bu ilev arldnda ak olan dosyalarn hepsi kapatlr. levin geri dn deeri,
kapatlan dosya saysdr.
imdi de alm bir dosyadan okuma yapan ya da alm bir dosyaya yazma yapan
standart C ilevlerini inceleyelim:

fgetc levi
int fgetc(FILE *f);
C'nin standart yazma ve okuma yapan ilevleri yazlan ve okunan ofset says kadar
dosya konum gstericisini ilerletirler. fgetc ilevi dosya gstericisinin gsterdii yerdeki
byte okur ve bu byte n tamsay deerini geri dn deeri olarak verir. lev baarsz
olursa, yani okuma ilemi yaplamaz ise stdio.h dosyas iinde simgesel deimez olarak
tanmlanm EOF deerine geri dner.
fgetc ilevinin geri dn deerini char trden bir deikene atamak yanl sonu
verebilir, bu konuda dikkatli olunmal ve ilevin geri dn deeri int trden bir
deikende saklanmaldr.
char ch;
ch = fgetc(fp);
Yukarda dosyadan okunan karakterin 255 numaral ASCII karakteri (0x00FF) olduunu
dnelim. Bu say char trden bir deikene atandnda yksek anlaml byte
kaybedilerek ch deikenine 0xFF deeri atanr. Bu durumda ch deikeni iaretli char
trden olduundan ch deikeni iinde negatif bir tamsaynn tutulduu anlam kar.
if (ch == EOF)
gibi bir karlatrma deyiminde, if ayrac iindeki karlatrma ileminin yaplabilmesi iin
otomatik tr dnm yaplr, yani ch tam sayya ykseltilir (integral promotion). Bu
otomatik tr dnmnde iaretli int trne evrilecek ch deikeni negatif olduu iin
FF byte' ile beslenir. Bu durumda eitlik karlatrmas doru sonu verir, yani dosyann
sonuna gelindii (ya da baka nedenden dolay okumann yaplamad) yorumu yaplr.
Oysa ch deikeni int trden olsayd, ch deikenine atanan deer 0x00FF olurdu. Bu
durumda karlatrma yapldnda ch deikeni ile EOF deerinin (0xFFFF) eit olmad
sonucuna varlrd.
fgetc ilevi kullanlarak okuma amacyla alm bir dosya karakter karakter okunabilir.
Aadaki programda klavyeden isimi alnan bir dosyann ierii ekrana yazdrlyor:

455

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

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

FILENAME_LEN

256

int main()
{
FILE *f;
char file_name[FILENAME_LEN];
int ch;
printf("Yazdirilacak dosyann ismi : ");
gets(file_name);
if ((f = fopen(file_name, "r")) == NULL) {
printf("cannot open file...\n");
exit(EXIT_FAILURE);
}
while ((ch = fgetc(f)) != EOF)
putchar(ch);
fclose(f);
return 0;
}
Yukardaki kodu inceleyin. nce yazdrlacak dosyann ismi klavyeden alnarak file_name
isimli diziye yerletiriliyor. smi file_name dizisine alnan dosya fopen ilevine yaplan
ar ile okuma amacyla alyor. fopen ilevinin baarsz olmas durumunda program
sonlandrlyor.
while ((ch = fgetc(f)) != EOF)
putchar(ch);
dng deyimiyle, fgetc ilevi EOF deerini dndrnceye kadar dosyadan bir karakter
okunuyor ve okunan karakterin grnts standart putchar ileviyle ekrana yazdrlyor.
Okuma ilemi tamamlannca standart fclose ileviyle dosya kapatlyor.
imdi de komut satrndan altrlacak aadaki program inceleyin. lev komut
satrndan
<say> <dosya ismi> <karakter>
biiminde altrlr. Program ekrana ismi verilen dosyada nc komut satr argman
olarak verilen karakterden ka tane bulunduu bilgisini yazar. Program nce inceleyin
daha sonra derleyerek altrn:

456

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

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

FILENAME_LEN

256

int main(int argc, char **argv)


{
FILE *f;
char file_name[FILENAME_LEN];
int ch, cval;
int char_counter = 0;
if (argc != 3) {
printf("Dosya ismi : ");
gets(file_name);
printf("sayilacak karakter : ");
cval = getchar();
}
else {
strcpy(file_name, argv[1]);
cval = *argv[2];
}
if ((f = fopen(file_name, "r")) == NULL) {
printf("%s dosyasi acilamiyor!\n", file_name);
exit(EXIT_FAILURE);
}
while ((ch = fgetc(f)) != EOF)
if (ch == cval)
char_counter++;
fclose(f);
printf("%s dosyasinda %d adet %c karakteri var!\n", file_name,
har_counter, ch);
}

return 0;

Son olarak unu da ekleyelim. fgetc bir ilevdir. Ancak stdio.h balk dosyas iinde getc
isimli bir de makro tanmlanmtr. Derleyicilerin ou getc makrosuyla ayn isimli bir de
ilev tanmlar. Ancak fgetc bir makro deil ilevdir. Makrolar konusuna ilerdeki
blmlerde deinilecek.

fputc levi

int fputc(int ch, FILE *p);


Bu ilev dosya konum gstericisinin bulunduu yere 1 byte bilgiyi yazar. levin birinci
parametresi yazlacak karakter, ikinci parametresi ise yazlacak dosyaya ilikin FILE yaps
adresidir. levin geri dn deeri EOF ise yazma ilemi baarsz olmu demektir.
Yazma ilemi baarl olmusa ilev yazlan karakterin sra numaras ile geri dner.
Sk yaplan bir hata ileve gnderilecek argumalarn srasn kartrmaktr. rnein f FILE
yaps trnden bir nesneyi gsteren gsterici olsun. fputc ilevi
fputc('A', f)
yerine yanllkla
fputc(f, 'A');

457

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

biiminde arlrsa f adresi int trne ve 'A' tamsay deeri de FILE yaps trnden bir
adrese dntrlr. Bu durumda phesiz yazma ilemi baarsz olur.
Aada fgetc ve fputc ilevlerini kullanarak bir dosyann kopyasn kartan bir programn
kodunu gryorsunuz. Program komut satrndan
<kopyala> <kaynak dosya ismi> <hedef dosya ismi>
eklinde altrlr. Programn altrlmasyla ikinci komut satr argmanyla ismi verilen
dosyann nc komut satr argmanyla verilen isimli bir kopyas kartlr. Program
dikkatle inceleyin:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_FILE_NAME_LEN

256

int main(int argc, char **argv)


{
FILE *fsource, *fdest;
char source_name[MAX_FILE_NAME_LEN];
char dest_name[MAX_FILE_NAME_LEN];
int ch;
int byte_counter = 0;
if (argc != 3) {
printf("kopyalanacak dosyann ismi : ");
gets(source_name);
printf("kopya dosyann ismi : ");
gets (dest_name);
}
else {
strcpy(source_name, argv[1]);
strcpy(dest_name, argv[2]);
}
if ((fsource = fopen(source_name, "r")) == NULL) {
printf("%s dosyasi acilamiyor\n", source_name);
exit(EXIT_FAILURE);
}
printf("%s dosyasi acildi!\n", source_name);
if ((fdest = fopen(dest_name, "w")) == NULL) {
printf("%s dosyasi yaratilamiyor\n", dest_name);
fclose(fsource);
exit(EXIT_FAILURE);
}
printf("%s dosyasi yaratildi!\n", dest_name);
while ((ch = fgetc(fsource)) != EOF) {
fputc(ch, fdest);
byte_counter++;
}
fclose(fsource);
printf("%s dosyasi kapatildi!\n", source_name);
fclose(fdest);
printf("%s dosyasi kapatildi!\n", dest_name);
printf("%d uzunlugunda %s dosyasinin %s isimli kopyasi cikarildi!\n",
byte_counter, source_name, dest_name);
}

return 0;

458

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

fputc bir ilevdir. Ancak stdio.h balk dosyas iinde getc isimli bir de makro
tanmlanmtr. Derleyicilerin ou putc makrosuyla ayn isimli bir de ilev tanmlar.
Ancak fgetc bir makro deil ilevdir.

fprintf levi
int fprintf(FILE *, const char *, );
Bu ilev tpk printf ilevi gibidir. Ancak ilk parametresi yazma ileminin hangi dosyaya
yaplacan belirtir. Dier parametreleri printf ilevin de olduu gibidir. printf ilevi
ekrana yazarken, fprintf ilevi birinci parametre deikeninde belirtilen dosyaya yazar.
Aadaki rnei inceleyin:
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *f;
int i, ch;
if ((f = fopen("data.txt", "w")) ==NULL) {
printf("cannot open file...\n");
exit(EXIT_FAILURE);
}
printf("data.txt dosyasi yaratld!\n");
for (i = 0; i < 10; ++i)
fprintf(f, "sayi = %d\n", i);
fclose(f);
printf("data.txt dosyas kapatild!\n");
if ((f = fopen("data.txt", "r")) == NULL) {
printf("cannot open file...\n");
exit(EXIT_FAILURE);
}
printf("data.txt dosyasi okuma amacyla ald!\n");
while ((ch = fgetc(f)) != EOF)
putchar(ch);
fclose(f);
}

return 0;

Programn ekran kts:


data.txt dosyasi yaratild!
data.txt dosyasi kapatild!
data.txt dosyasi okuma amacyla ald!
sayi = 0
sayi = 1
sayi = 2
sayi = 3
sayi = 4
sayi = 5
sayi = 6
sayi = 7
sayi = 8
sayi = 9

fscanf levi

Dosyadan okuma yapan bir ilevdir. scanf ilevine ok benzer.

459

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Nasl fprintf ilevi, ekrana yazmak yerine, yazma ilemini birinci parametresiyle belirlenen
dosyaya yapyorsa, fscanf ilevi de, okumay klavyeden yapmak yerine belirtilen bir
dosyadan yapar. fscanf ilevi scanf ilevinden farkl olarak, birinci parametre deikenine
FILE trnden bir adres alr. levin bildirimi aadaki gibidir:
int fscanf(FILE *, const char *, );
levin geri dn deeri, dosyadan okunarak bellekteki alanlara yazlan deer saysdr.
Hibir alana yazma yaplmadysa, ilev 0 deerine geri dner. Eer ilk alana atama
yaplamadan dosyann sonuna gelinmise, ya da bir hata olumusa ilev EOF deerine
geri dner. kinci parametresine geilecek yazda kullanlacak format karakterleri scanf
ilevi ile ayndr. Aadaki program dikkatle inceleyin:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define
#define

SIZE
PASS_GRADE

100
60

char *name[50] = {"Ali", "Veli", "Hasan", "Necati", "Aye", "Kaan",


"Selami","Salah","Nejla", "Huseyin", "Derya", "Funda", "Kemal", "Burak",
"Ozlem", "Deniz", "Nuri", "Metin", "Guray", "Anil", "Umut", "Selda",
"Belgin", "Figen", "Korhan", "hsan", "Ufuk", "Necmettin", "Taylan",
"Abdullah", "Perihan", "Soner", "Can", "Ata", "Berk", "Melahat", "Zarife",
"Yelda", "Ertan", "Mustafa", "Gizem", "Funda", "Aleyna", "Simge", "Damla",
"Kaan", "Kerim", "Cumali", "Ferda", "Sami"};
char *fname[30] = {"Aslan", "Ozkan", "Eker", "Ergin", "Serce", "Kaynak",
"Acar", "Aymir", "Erdin", "Doganoglu", "Avsar", "Ozturk", "Ylmaz",
"Tibet", "Arkn", "Cilasun", "Yildirim", "Demiroglu", "Torun", "Polatkan",
"Burakcan", "Kale", "Nergis", "Kayserili", "Duman", "Tansel", "Kurt",
"Tonguc", "Melek", "Mungan"};
int main()
{
FILE *fgrades, *fpass, *ffail;
int no_of_lines, k;
char name_entry[SIZE];
char fname_entry[SIZE];
int grade;
int pass_counter = 0;
int fail_counter = 0;
srand(time(0));
fgrades = fopen("notlar.txt", "w");
if (fgrades == NULL) {
printf("notlar.txt dosyasi yaratilamiyor!\n");
exit(EXIT_FAILURE);
}
printf("notlar.txt dosyasi yaratildi!\n");
no_of_lines = rand() % 2000 + 1000;
for (k = 0; k < no_of_lines; ++k)
fprintf(fgrades, "%s %s %d\n", name[rand() % 50], fname[rand() %
30], rand() % 101);
printf("notlar.txt dosyasina %d satir kayit yazildi!\n", no_of_lines);
fclose(fgrades);
printf("notlar.txt dosyasi kapatildi!\n");
fgrades = fopen("notlar.txt", "r");
if (fgrades == NULL) {
460

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

printf("cannot open notlar.txt!\n");


exit(EXIT_FAILURE);
}
printf("notlar.txt dosyasi acildi!\n");
fpass = fopen("gecen.txt", "w");
if (fpass == NULL) {
printf("gecen.txt dosyasi yaratilamiyor!\n");
exit(EXIT_FAILURE);
}
printf("gecen.txt dosyasi yaratildi!\n");
ffail = fopen("kalan.txt", "w");
if (ffail == NULL) {
printf("kalan.txt dosyasi yaratilamiyor!\n");
exit(EXIT_FAILURE);
}
printf("kalan.txt dosyasi yaratildi!\n");
while (fscanf(fgrades, "%s%s%d", name_entry, fname_entry, &grade) !=
EOF) {
if (grade >= PASS_GRADE) {
fprintf(fpass, "%s %s %d\n", name_entry, fname_entry, grade);
pass_counter++;
}
else {
fprintf(ffail, "%s %s %d\n", name_entry, fname_entry, grade);
fail_counter++;
}
}
fprintf(fpass, "TOPLAM GECEN OGRENCI SAYISI = %d\n", pass_counter);
fprintf(ffail, "TOPLAM KALAN OGRENCI SAYISI = %d\n", fail_counter);
if (fcloseall() != 3) {
printf("dosya kapatilamiyor!\n");
exit(EXIT_FAILURE);
}
return 0;
}
Programda her satr rastgele bir isim soyisim ve not deerinden oluan "notlar.txt" isimli
bir dosya yaratlyor. Daha sonra bu dosya okuma amacyla alarak, dosyann her
satrnda bulunan isim ile soyisimler char trden dizilere, not deerleri ise int trden bir
deikene okunuyor. Okunan not deerinin PASS_GRADE deerinden yksek olup
olmamasna gre ilgili satr, yazma amacyla alm "gecen.txt" ya da "kalan.txt" isimli
dosyalara yazdrlyor. Bylece "notlar.txt" dosyasndan "gecen.txt" ve "kalan.txt" isimli
iki farkl dosya oluturuluyor.
fscanf ilevinde kullanlan format karakterlerine ilikin nemli bir ayrntya deinelim:
Dosyadan yaplan her okumann dntrlerek mutlaka bellekte bir alana yazlmas
zorunlu deildir. Boluk karakterleriyle ayrlan bir karakter grubu bir yere atanmadan
dosya tampon alanndan karlmak isteniyorsa, format karakter grubunda %
karakterinden sonra '*' karakteri kullanlr. rnein bir metin dosyasnda dosya konum
gstericisinin gsterdii yerde
1376

----------

4567

gibi bir satrn bulunduunu dnelim. Yaplacak okuma sonucunda yalnzca 1376 ve
4567 deerlerinin x ve y deikenlerine aktarlmas gerektiini dnelim. Bunun iin
aadaki gibi bir ar yaplabilir:

461

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

fscanf(f, "%d%*s%d", &x, &y);

fgets levi
char *fgets(char *buf, int n, FILE *f);
Bu ilev dosya konum gstericisinin gsterdii yerden bir satrlk bilgiyi okur. lev
dosyadan '\n' karakterini okuyunca onu da birinci parametresinde verilen adrese yazarak
ilemini sonlandrr.
levin birinci parametresi okunacak bilginin bellekte yerletirilecei yerin adresidir. kinci
parametresi ise okunacak maksimum karakter saysdr. fgets ilevi en fazla n 1
karakteri okur. Okuduu karakterlerin sonuna sonlandrc karakteri ekler ve ilemini
sonlandrr. Eer satr zerindeki karakter says n - 1'den az ise tm satr okur ve
ilemini sonlandrr. rnein bu parametrenin 10 olarak girildiini dnelim. Satr
zerinde 20 karakter olsun. lev 9 karakteri okuyarak diziye yerletirir, sonuna
sonlandrc karakteri ekler. Ancak satr zerinde \n dahil olmak zere 5 karakter olsayd
ilev bu 5 karakteri de okuyarak sonuna da sonlandrc karakteri ekleyerek ilemini
sonlandrrd. levin ikinci parametresine char trden bir dizinin ya da dinamik olarak
elde edilen bir bloun boyutunu gemek tama hatalarn dorudan engeller. Zira fgets
ilevi en fazla, dizinin boyutundan bir eksik sayda karakteri okuyarak diziye yazar,
dizinin son elemanna da sonlandrc karakterin deerini yazar.
levin geri dn deeri, en az 1 karakter okunmu ise birinci parametresi ile belirtilen
adresin ayns, hibir karakter okunmamsa NULL adresidir.
Bir dng iinde fgets ilevi srekli olarak arlarak btn dosya okunabilir.
fgets ilevi ile bir dosyay satr satr ekrana yazdran aadaki program inceleyin:
#include <stdio.h>
#include <stdlib.h>
#define
#define

MAX_FILE_NAME_LEN
BUFFER_SIZE

256
100

int main()
{
FILE *f;
char file_name[MAX_FILE_NAME_LEN];
char buf[BUFFER_SIZE];
printf("Dosya ismi : ");
gets(file_name);
if ((f = fopen(file_name, "r")) == NULL) {
printf("cannot open the file %s\n", file_name);
exit(EXIT_FAILURE);
}
while (fgets(buf, BUFFER_SIZE, f) != NULL)
printf("%s", buf);
fclose(f);
return 0;
}
while (fgets(buf, BUFFER_SIZE, f) != NULL)
printf("%s", buf);
Dngsyle f ile gsterilen dosyadan satr satr okuma yaplarak okunan karakterler buf
dizisine yazlyor. Eer dosyadan okunacak bir karakter kalmadysa fgets ilevi NULL
adresine geri dner.

462

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

fputs levi

levin bildirimi aadaki gibidir:


int fputs(const char *str, FILE *stream);
lev, birinci parametresine geilen adresteki yazy ikinci parametresine geilen FILE
trnden adresle ilikilendirilen dosyaya yazar. Yaznn sonunda yer alan sonlandrc
karakter ilev tarafndan dosyaya yazlmaz. lev, yazma ileminde baarsz olursa EOF
deerine geri dner. Baar durumunda ilevin geri dn deeri negatif olmayan bir
tamsaydr. Aadaki programda, fputs ve fgets ilevleri kullanlarak bir metin dosyasnn
kopyas karlyor:
#include <stdio.h>
#include <stdlib.h>
#define FILE_NAME_LEN
#define BUFFER_SIZE

256
100

int main()
{
char source_file_name[FILE_NAME_LEN];
char dest_file_name[FILE_NAME_LEN];
char buffer [BUFFER_SIZE];
FILE *fs, *fd;
printf("kopyalanacak dosya ismi: ");
gets(source_file_name);
printf("kopya dosya ismi: ");
gets(dest_file_name);
fs = fopen(source_file_name, "r");
if (fs == NULL) {
printf("%s dosyasi acilamiyor!\n", source_file_name);
exit(EXIT_FAILURE);
}
fd = fopen(dest_file_name, "w");
if (fd == NULL) {
printf("%s dosyasi yaratilamiyor!\n", dest_file_name);
fclose(fd);
exit(EXIT_FAILURE);
}
while (fgets(buffer, BUFFER_SIZE, fs))
fputs(buffer, fd);
printf("kopyalama basari ile tamamlandi!\n");
fclose(fs);
fclose(fd);
return 0;
}

Metin Dosyalar ve kilik Dosyalar

Bir dosya text modunda ya da binary modda alabilir. Varsaylan (default) a modu
text modudur. Yani dosyann hangi modda ald ak bir ekilde belirtilmezse dosyann
text modunda ald varsaylr. Dosyay binary modda aabilmek iin a mod yazsna
'b' eklemek gerekir. Aada bir dosyay binary modda aabilmek iin fopen ilevine
gnderilebilecek geerli dizgeler veriliyor:
"rb", "r+b", "rb+", "w+b", "wb+","a+b", "ab+"

463

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

DOS ve WINDOWS gibi baz iletim sistemlerinde bir dosyann text modu ya da binary
modda almas arasnda baz nemli farklar vardr:
DOS iletim sisteminde bir dosya yazdrldnda bir karakter aa satrn banda
grnyorsa bunu salamak iin o karakterden nce CR (carriage return) ve LF (line
feed) karakterlerinin bulunmas gerekir. CR karakteri C'de '\r' ile belirtilir. 13 numaral
ASCII karakteridir. LF karakteri C'de \n ile belirtilir. 10 numaral ASCII karakteridir.
rnein bir dosya yazdrldnda grnt
a
b
eklinde olsun. Dosyadaki durum a\r\nb eklindedir. Oysa UNIX tabanl sistemlerinde
aa satrn bana geebilmek iin sadece LF karakteri kullanlr. UNIX iletim sisteminde
a
b
grntsnn dosya karl
a\nb biimindedir.
DOS iletim sisteminde LF karakteri bulunulan satrn aasna ge CR karakteri ise
bulunulan satrn bana ge anlamndadr. rnein DOS iletim sisteminde bir bir
dosyann ierii a\nb biiminde ise dosya yazdrldnda
a
b
grnts elde edilir. Eer dosyann ierii a\rb biiminde ise dosya yazdrldnda
b
grnts elde edilir.
printf levinda \n ekranda aa satrn bana geme amacyla kullanlr. Aslnda printf
ilevinin 1. parametresi olan dizgenin iine \n yerletirildiinde UNIX'de yalnzca \ni DOS
iletim sisteminde ise \r ve\n ile bu gei salanr.
Text dosyalar ile rahat alabilmek iin dosyalar text ve binary olarak ikiye ayrlmtr.
Bir dosya text modunda aldnda dosyaya \n karakteri yazlmak istendiinde dosya
ilevleri otomatik olarak \r ve \n karakterlerini dosyaya yazar. Benzer bir biimde dosya
text modda almsa dosya gstericisi \r\n iftini gsteriyorsa dosyadan yalnzca /n
karakteri okunur. DOS iletim sisteminde text ve binary dosyalar arasndaki baka bir
fark da, CTRL Z (26 numaral ASCII karakterinin) dosyay sonlandrdnn
varsaylmasdr. Oysa dosya binary modda aldnda byle bir varsaym yaplmaz.
UNIX iletim sisteminde, text modu ile binary mod arasnda hibir fark yoktur. Yani UNIX
iletim sisteminde dosyann binary mod yerine text modunda almasnn bir sakncas
olmaz. Ancak DOS altnda text dosyas olmayan bir dosyann binary mod yerine text
modunda almasnn sakncalar olabilir. rnein DOS altnda bir exe dosyann binary
mod yerine text modunda aldn dnelim. Bu dosyada 10 numaral ve 13 numaral
ASCII karakterleri yanyana bulunduunda dosyadan yalnzca 1 byte okunur. Ayn ekilde
dosyadan 26 numaral ASCII karakteri okunduunda dosyadan artk baka bir okuma
yaplamaz. Dosyann sonuna gelindii varsaylr.
Aadaki program text modu ile binary mod arasndaki fark gsteriyor:

464

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fp;
int k, ch;
fp = fopen("deneme", "w");
if (fp == NULL) {
printf("dosya alamyor\n");
exit(EXIT_FAILURE);
}
/* dosyaya 5 tane \n karakteri yazdrlyor */
for (k = 0; k < 5; ++k)
fputc('\n', fp);
fclose(fp);
printf("\ndosya binary modda alarak yazdrlyor\n");
fp = fopen("deneme", "rb");
if (fp == NULL) {
printf("dosya alamyor\n");
exit(EXIT_FAILURE);
}
while ((ch = fgetc(fp)) != EOF)
printf("%d ", ch);
/* ekran kts
13 10 13 10 13 10 13 10 13 10
*/
fclose(fp);
printf("\ndosya kapatld. imdi dosya text modunda alarak
yazdrlyor .\n");
fp = fopen("deneme", "r");
if (fp == NULL) {
printf("dosya alamyor\n");
exit(EXIT_FAILURE);
}
while ((ch = fgetc(fp)) != EOF)
printf("%d ", ch);
/* ekran kts
10 10 10 10 10
*/
fclose(fp);
/* simdi '\x1A' karakterinin text modunda dosyay sonlandrmas zellii
snanyor*/
fp = fopen("deneme", "w");
if (fp == NULL) {
printf("dosya alamyor\n");
exit(EXIT_FAILURE);
}
/* dosyaya 5 tane 'A' karakteri yazdrlyor */
for (k = 0; k < 5; ++k)
fputc('A', fp);
/* dosyaya '\x1A' karakteri yazdrlyor */
fputc('\x1a', fp);
/* dosyaya 10 tane 'A' karakteri yazdrlyor. */
for (k = 0; k < 5; ++k)
fputc('A', fp);
fclose(fp);
printf("\ndosya binary modda alarak yazdrlyor :\n");
fp = fopen("deneme", "rb");

465

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

if (fp == NULL) {
printf("dosya alamyor\n");
exit(EXIT_FAILURE);
}
while ((ch = fgetc(fp)) != EOF)
printf("%d ", ch);
/* ekran kts
65 65 65 65 65 26 65 65 65 65 65
*/
printf("\ndosya kapatld, imdi dosya text modunda alarak
yazdrlyor\n");
fp = fopen("deneme", "r");
if (fp == NULL) {
printf("dosya alamyor\n");
exit(EXIT_FAILURE);
}
while ((ch = fgetc(fp)) != EOF)
printf("%d ", ch);
/* ekran kts
65 65 65 65 65 26 65 65 65 65 65
*/
fclose(fp);
}

return 0;

EOF Durumu

Dosyann sonunda hibir zel karakter yoktur. letim sistemi dosyann sonuna gelinip
gelinmediini dosyann uzunluuna bakarak anlayabilir. EOF (end of file) durumu dosya
konum gstericisinin dosyada olmayan son karakteri gstermesi durumudur. EOF
durumunda dosya konum gstericisinin offset deeri dosya uzunluu ile ayn deerdedir.
EOF durumunda dosyadan okuma yaplmak istenirse dosyadan okuma yapan ilevler
baarsz olur. Ancak a modu uygunsa dosyaya yazlabilir ve bu durumda dosyaya
ekleme yaplr.
Daha nce belirtildii gibi C dilinde alan bir dosya ile ilgili bilgiler FILE trnden bir yap
nesnesi iinde tutulur. Bu yapnn elemanlar dosyann zellikleri hakknda bilgi verir. C
programcs bu yapnn elemanlarnn deerleri ile dorudan ilgilenmez, zira fopen
ilevinin geri dn deeri bu yap nesnesini gsteren FILE yaps trnden bir gstericidir
ve C dilinin dosyalarla ilgili ilem yapan ilevleri ounlukla bu adresi parametre olarak
alarak, istenilen dosya ile ilgili bilgilere ular.
Sz konusu FILE yapsnn elemanlarndan biri de, bayrak olarak kullanlan EOF
bayradr. Aslnda derleyicilerin ounda int trden bir bayran yalnzca belirli bir bitidir.
C dilinin dosyalarla ilgili ilem yapan baz ilevleri EOF bayrann deerini deitirir. Yani
EOF bayran birler ya da sfrlarlar. Okuma yapan ilevler okumadan nce bu bayran
deerine bakar. EOF bayra set edilmise okuma baarl olmaz. Baarl bir okuma
yaplabilmesi iin EOF bayrann yeniden sfrlanmas gerekir. Dosya aan ilevler FILE
yapsndaki EOF bayran sfrlar. Bu ilevler dnda dosya konum gstericisinin deerini
deitiren ilevler (fseek, rewind, fsetpos) ile clearerr ilevleri de EOF bitini sfrlar.

Formatl ve Formatsz Yazm

Bir dosyaya int trden deerlerin yazlacan dnelim. Dosyaya int trden bir deer
yazmak ne anlama gelir? rnein int trnn 4 byte olduu bir sistemde, dosyaya
yazlacak tamsay deeri 1234567890 olsun. Bu deer bir dosyaya yazlmak ve o
dosyadan daha sonra geri okunmak istensin.
Bu ilem fprintf ilevi ile yaplabilir, deil mi?

466

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

f yazma amacyla alm bir dosyann gstericisi olmak zere


fprintf(f, "%d", 1234567890);
Yukardaki aryla dosya konum gstericisinin gsterdii yerden balanarak dosyaya 10
byte eklenmi olur. Dosyaya yazlan byte'lar 1234567890 saysnn basamak deerlerini
gsteren rakamlarn sra numaralardr. Sistemde ASCII karakter kodlamasnn
kullanldn dnelim. Dosyaya aadaki byte'lar yazlmtr:
49 50 51 42 53 54 55 56 57 59 48
Oysa 32 bitlik bir sistemde 1234567890 gibi bir deer 4 byte'lk alanda ifade edilir deil
mi? rnein 1234567890 saysnn bellekteki grnts aadaki gibidir:
0100 1001 1001 0110 0000 0010 1101 0010
Bu 4 byte RAM'de olduu gibi dosyaya yazlamaz m? te dosyaya bu ekilde yazm
formatsz yazmdr. C'nin iki nemli standart ilevi RAM'den dosyaya dosyadan RAM'e
belirli sayda byte' formatsz biimde aktarr. imdi bu ilevleri inceleyeceiz:

fread ve fwrite levleri

Bu iki ilev C'de en ok kullanlan ilevlerdir. Genel olarak dosya ile RAM arasnda aktarm
(transfer) yaparlar. Her iki ilevin de bildirimi ayndr:
size_t fread(void *adr, size_t block_size, size_t n_blocks, FILE *);
size_t fwrite(const void *adr, size_t block_size, size_t n_blocks, FILE *);
size_t trnn sistemlerin hemen hemen hepsinde unsigned int ya da unsigned long
trnn typedef edilmi yeni ismi olduunu anmsayn.
fread ilevi dosya konum gstericisinin gsterdii yerden, ikinci ve nc parametresine
kopyalanan deerlerin arpm kadar byte' , bellekte birinci parametresinin gsterdii
adresten balayarak kopyalar. Genellikle ilevin ikinci parametresi veri yapsnn bir
elemannn uzunluunu, nc parametresi ile para says biiminde girilir. levin geri
dn deeri bellee yazlan ya da bellekten dosyaya yazlan para saysdr.
Bu ilevler sayesinde diziler ve yap nesneleri tek bir ar ile bir dosyaya aktarlabilirler.
rnein 10 elemanl int trden bir dizi aadaki gibi tek bir aryla dosyaya yazlabilir.
int a[5] = {3, 4, 5, 7, 8};
fwrite (a, sizeof(int), 5, f);
Yukardaki rnekte, dizi ismi olan a int trden bir adres bilgisi olduu iin, fwrite ilevine
1. argman olarak gnderilebilir. FILE trnden f gstericisi ile ilikilendirilen dosyaya
bellekteki a adresinden toplam sizeof(int) * 5 byte yazlr.
Aadaki kod parasnda bir yap nesnesi bellekten dosyaya aktarlyor:

467

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

typedef struct {
char name[20];
char fname[20];
int no;
}Person;
int main()
{
FILE *f;
Person per = {"Necati", "Ergin", 325);

f = fopen("person.dat", "wb");
/*********************************/
fwrite(&per, sizeof(Person), 1, f);
/****/

fwrite ilevi saylar bellekteki grnts ile dosyaya yazar. Yani fprintf ilevi gibi formatl
yazmaz. rnein DOS iletim sisteminde:
int i = 1535;
fwrite(&i, sizeof(int), 1, f);
Burada dosya yazdrlrsa 2 byte uzunluunda rastgele karakterler grnr. nk DOS
iletim sisteminde int tr 2 byte uzunluundadr. Bizim grdmz ise 1525'in rastgele
olan byte'lardr. Bilgileri ASCII karlklar ile dosyaya yazmak iin fprintf ilevi
kullanlabilir.
fread ve fwrite ilevleri bellekteki bilgileri aktardna gre dosyalarn da binary modda
alm olmas uygun olur.
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *f;
int i;
int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int b[10];
if ((f = fopen("data", w+b")) == NULL) {
printf("cannot open file...\n");
exit(EXIT_FAILURE);
}
fwrite (a, sizeof(int), 10, f);
fseek(f, 0, SEEK_SET);
fread(b, sizeof(int), 10, f);
for (i = 0; i < 10; ++i)
printf("%d\n", b[i]);
fclose(f);
return 0;
}
fread ve fwrite ilevlerinin geri dn deerleri nc parametresi ile belirtilen okunan
ya da yazlan para saysdr. rnein
n = fread(a, sizeof(int), 10, f);

468

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

ars ile f ile gsterilen dosyadan sizeof(int) * 10 kadar byte okunarak RAM'da a
adresine yazlmak istenmitir. Yani dosya konum gstericisinin gsterdii yerden itibaren
btn saylar okunabildiyse ilev 10 deerine geri dner. Eer dosyadaki kalan byte
says okunmak istenen saydan az ise ilev btn byte'lar okur ve geri dn deeri
okunan byte says 2. parametresi ile belirtilen deer olur. rnein DOS iletim sistemi
altnda alyor olalm. Dosyada 10 byte bilgi kalm olsun.
n = fread(a, sizeof(int), 10, f);
ile ilev 5 deerine geri dner.
Aadaki iki ary inceleyelim:
fread(str, 100, 1, f);
fread(str, 1, 100, f);
Her iki ilev ars da RAM'deki str adresine FILE trnden f gstericisi ile ilikilendirilen
dosyadan 100 byte okumak amacyla kullanlabilir. Ancak birinci arda geri dn
deeri ya 0 ya 1 olabilecekken, ikinci ilev arsnda geri dn deeri 0 100(dahil)
aralnda herhangi bir deer olabilir.

fread ve fwrite levleriyle Blok Blok Kopyalama

Aadaki rnekte bir grup byte fread ilevi ile bir dosyadan okunuyor, fwrite ilevi ile
dier bir dosyaya yazlyor:

469

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

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

BLOCK_SIZE
MAX_NAME_LEN

1024
80

int main()
{
FILE *fs, *fd;
char source_file_name[MAX_NAME_LEN];
char dest_file_name[MAX_NAME_LEN];
unsigned int n;
unsigned char buf[BLOCK_SIZE];
printf("kaynak dosya ismini giriniz : ");
gets(source_file_name);
printf("yeni dosya ismini giriniz : ");
gets(dest_file_name);
if ((fs = fopen(source_file_name, "rb")) == NULL) {
printf("%s dosyas alamyor!\n", source_file_name);
exit(EXIT_FAILURE);
}
printf("%s dosyas ald!\n", source_file_name);
if ((fd = fopen(dest_file_name, "wb")) == NULL) {
printf("%s dosyas yaratlamyor!\n", source_file_name);
fclose(fs);
exit(EXIT_FAILURE);
}
printf("%s dosyas yaratlamyor!\n", dest_file_name);
while ((n = fread(buf, 1, BLOCK_SIZE, fs)) != 0)
fwrite(buf, 1, n, fd);
fclose(fs);
printf("%s dosyas kapatld!\n", source_file_name);
fclose(fd);
printf("%s dosyas kapatld!\n", dest_file_name);
printf("kopyalama baaryla tamamland\n");
}

return 0;

Yukar program inceleyin. Kopyalama aadaki dng deyimiyle yaplyor:


while ((n = fread(buf, 1, BLOCK_SIZE, fs))
fwrite(buf, 1, n, fd);

!= 0)

fread ilevi ile fs ile gsterilen dosyadan, 1 byte'lk bloklardan BLOCK_SIZE kadar
okunmaya allyor. fread ilevinin geri dn deeri n isimli deikende saklanyor. n
deikenine atanan deer 0 olmad srece dngnn devam salanyor. Baka bir
deyile while dngs dosyadan en az 1 byte okuma yaplabildii srece dnyor. while
dngsnn gvdesinde yer alan fwrite ilevi ars ile kaynak dosyadan okunan n byte
hedef dosyaya yazlyor.
imdi de aadaki program inceleyin. Bu programda komut satrndan girilen iki deer
arasndaki tm asal saylar, ismi komut satrndan ismi girilen dosyaya formatsz olarak
yazlyor. Program komut satrndan aadaki gibi altrlabilir:
<asalyaz> <deger1> <deger2> <dosya ismi>
#include <stdio.h>
#include <stdlib.h>

470

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <string.h>
int isprime(int val);
int main(int argc, char *argv[])
{
int lower_bound, upper_bound;
int k, temp;
int prime_counter = 0;
FILE *f;
if (argc != 4) {
printf("<asalyaz> <deger1> <deger2> <dosya ismi>\n");
exit(EXIT_FAILURE);
}
lower_bound = atoi(argv[1]);
upper_bound = atoi(argv[2]);
if (lower_bound > upper_bound) {
temp = lower_bound;
lower_bound = upper_bound;
upper_bound = temp;
}
f = fopen(argv[3], "wb");
if (f == NULL) {
printf("%s dosyasi yaratilamiyor!\n", argv[3]);
exit(EXIT_FAILURE);
}
printf("%s dosyasi yaratildi!\n", argv[3]);
for (k = lower_bound; k <= upper_bound; ++k)
if (isprime(k)) {
fwrite(&k, sizeof(int), 1, f);
prime_counter++;
}
printf("%s dosyasina %d adet asal sayi yazildi!\n", argv[3],
prime_counter);
fclose(f);
printf("%s dosyasi kapatildi!\n", argv[3]);
}

return 0;

Dosya Konum Gstericisi le lgili levler

Okuma ya da yazma yapan ilevler, okuma ya da yazma ilemini dosya konum


gstericisinin deeri olan konumdan yapar. Bir dosyann istenilen bir konumundan okuma
ya da yazma yapabilmek iin nce dosya konum gstericisi konumlandrlmaldr. Dosya
konum gstericisi standart C ilevleri ile konumlandrlabilir:

fseek levi

Bu ilev dosya konum gstericisini istenilen bir offset deerine konumlandrmak amacyla
arlr. Bu ilevin arlmasyla, alm bir dosyann istenilen bir yerinden okuma
yapmak ya da istenilen bir yerine yazmak mmkn hale gelir. levin bildirimi aadaki
gibidir:
int fseek(FILE *f, long offset, int origin);

471

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

levin birinci parametresi hangi dosyann dosya konum gstericisinin


konumlandrlacan belirler. levin ikinci parametresi konumlandrma ileminin
yaplaca offset deeridir. levin nc parametresi konumlandrmann hangi
noktadan itibaren yaplacan belirler. Bu parametreye stdio.h iinde bildirilen SEEK_SET,
SEEK_CUR, SEEK_END simgesel deimezlerden biri geilmelidir. Derleyiciler bu simgesel
deimezleri aadaki gibi tanmlar:
#define SEEK_SET
#define SEEK_CUR
#define SEEK_END

0
1
2

Son parametreye SEEK_SET deeri geilirse, konumlandrma dosya bandan itibaren


yaplr. Bu durumda ikinci parametre >= 0 olmaldr. rnein:
fseek(f, 10L,

SEEK_SET);

ile dosya gstericisi 10. offsete konumlandrlr. Ya da


fseek(f, 0L, SEEK_SET);
levin nc parametre deikenine geilen deer SEEK_CUR ise, konumlandrma
dosya gstericisinin en son bulunduu yere gre yaplr. Bu durumda ikinci parametre
pozitif ya da negatif deere sahip olabilir. Pozitif bir deer ileri, negatif bir deer geri
anlamna gelir. rnein dosya gstericisi 10. byte' gsteriyor olsun.
fseek(f, -1, SEEK_CUR);
ars ile dosya gstericisi 9. offset e konumlandrlr.
levin nc parametre deikenine geilen deer SEEK_END ise konumlandrma EOF
durumundan itibaren yani dosya sonundan itibaren yaplr. Bu durumda ikinci
parametreye geilen deer <= 0 olmaldr. rnein dosya gstericisini dosyann sonuna
konumlandrmak iin
fseek(f, 0, SEEK_END);
arsn yapmak gerekir.
fseek(f, -1, SEEK_END);
ars ile dosya konum gstericisi son karakterin bulunduu yere ekilir. levin geri
dn deeri ilemin baars hakknda bilgi verir. Geri dn deeri 0 ise ilem baarl, 0
d bir deer ise ilem baarszdr. Yalnzca sorunlu durumlarda geri dn deerinin
snanmas salk verilir.
Yazma ve okuma ilemleri arasnda dosya gstericisinin bir konumlandrma ilevi ile
konumlandrlmas gerekir. Ya da fflush ilevine yaplan ar ile dosya tampon alan
boaltlmaldr. Gerekirse bo bir fseek ars ile, konumlandrma bulunulan yere
yaplabilir:
fseek(0, 0L, SEEK_CUR).
rnein dosyadan bir karakter okunup, bir sonraki karaktere okunmu karakterin 1
fazlas yazlacak olsun:
ch = fgetc(f);
fputc(ch + 1, f);

472

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

ilemi hataldr. Durum alma zamanna ilikin tanmlanmam bir davran (undefined
behaviour) zellii gsterir. Yani alma zamannda herey olabilir. Yazmadan okumaya,
okumadan yazmaya geite dosya gstericisi konumlandrlmaldr. Bu durumun tek
istisnas, son yaplan okuma ile dosyann sonuna gelinmesi durumudur. Bu durumda
konumlandrma yaplmadan dosyann sonuna yazlabilecei gvence altndadr.

rewind levi

Bu ilev ile dosya konum gstericisi dosyann bana konumlandrlr. levin bildirimi
aadaki gibidir:
void rewind(FILE *fp);
rewind(f);
ars ile
(void) fseek(f, 0L, SEEK_SET);
ars ayn anlamdadr.

ftell levi

Bu ilev dosya konum gstericisinin deerini elde etmek iin arlr. levin bildirimi
aadaki gibidir:
long ftell(FILE *);
levin geri dn deeri dosya konum gstericisinin deeridir. Bu deer dosyann
bandan itibaren kanc byte olduu bilgisi olarak verilir. Bir hata durumunda ilev -1L
deerine geri dner.
kili (binary) bir dosyann uzunluu fseek ve ftell ilevlerine yaplan arlarla elde
edilebilir:
fseek(f, 0, SEEK_END);
length = ftell(f);

fgetpos ve fsetpos levleri

Bu ilevler, dosya konum gstericisinin deerini elde etmek ya da deerini deitirmek


iin, birbirleriyle ilikili olarak kullanlr. Bu ilevlerle dosya iindeki bir nokta
iaretlenerek, daha sonra okuma ya da yazma amacyla dosya konum gstericisi ayn
noktaya konumlandrlabilir. fgetpos ilevi ile dosya konum gstericisinin deeri elde
edilir, daha sonra bu konuma geri dnebilmek iin fsetpos ilevi kullanlr.
int fgetpos(FILE *, fpos_t *pos);
lev birinci parametresine geilen adresle ilikilendirilen dosyann dosya konum
gstericisinin deerini elde ederek ikinci parametresine geilen adrese yazar. fpos_t tr
stdio.h balk dosyas iinde bildirilen standart bir typedef trdr. Bu tr yalnzca
fgetpos ile fsetpos ilevlerinde kullanlr. levin geri dn deeri ilemin baarsn
gsterir. lev, baar durumunda 0 deerine, baarszlk durumunda sfrdan farkl bir
deere geri dner.
int fsetpos(FILE *, const fpos_t *pos);
lev, birinci parametresine geilen adresle ilikilendirilen dosyann dosya konum
gstericisini ikinci parametresine geilen adresten okunan deere konumlandrr. levin
ikinci parametresine fgetpos ilevinden elde edilen bir deeri tayan nesnenin adresi
geilmelidir.

473

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

zellikle byk dosyalar sz konusu olduunda fsetpos/fgetpos ilevleri fseek ilevine


tercih edilmelidir. nk fseek ilevinin ikinci parametresi long trden iken,
fgetpos/fsetpos ilevlerinde kullanlan fpos_t tr ok byk dosyalarn konum bilgilerini
tutabilecek byklkte olan, isel olarak tanmlanm bir yap tr olabilir.

Dosyalarla lgili lem Yapan Dier Standart levler


remove levi

Bu ilev bir dosyay siler. levin bildirimi


int remove (const char *filename);
biimindedir. leve argman olarak silinecek dosyann ismi gnderilir. levin geri dn
deeri, dosyann baarl bir ekilde silinebilmesi durumunda 0, aksi halde yani dosya
silinememise sfr d bir deerdir. Ak olan bir dosyann silinebilmesi sisteme bal
olduundan, yazlan kodun tanabilirlii asndan, silinecek bir dosya ak ise nce
kapatlmaldr.

rename levi

Bu ilev bir dosyann ismini deitirmek iin kullanlr. levin bildirimi:


int rename (const char *old, const char *new);
biimindedir.
leve birinci argman olarak dosyann eski ismi ikinci argman olarak ise dosyann yeni
ismi gnderilmelidir. levin geri dn deeri, isim deitirmen ileminin baarl olmas
durumunda 0, aksi halde yani dosyann ismi deitirilemmesi durumunda 0 d bir
deerdir. Sistemlerin ounda ak olan bir dosyann isminin deitirilmeye allmas
durumunda ilev baarsz olur ve 0 d bir deere geri dner.

tmpfile levi

lev geici bir dosya amak amacyla kullanlr. levin bildirimi :


FILE * tmpfile(void);
tmpfile ilevi at geici dosyay "wb" modunda aar. Alan dosya fclose ilevi ile
kapatldnda ya da dosya kapatlmazsa program sona erdiinde otomatik olarak silinir.
levin geri dn deeri, alan geici dosya ile iliki kurulmasna yarayacak, FILE yaps
trnden bir adrestir. Herhangi bir nedenle dosya geici dosya alamyorsa ilev NULL
adresine geri dner.
stdio.h balk dosyas iinde tanmlanan TMP_MAX simgesel deimezi tmpfile ileviyle
yaratlabilecek maksimum geici dosya saysn gsterir. Yazlan bir kaynak kodda, ayn
anda alm olan geici dosyalarn says TMP_MAX deerinden daha byk olmamaldr.

tmpnam levi

Geici olarak kullanlacak bir dosya iin bir isim retilmesi amacyla kullanlr. levin
stdio.h balk dosyas iindeki bildirimi:
char *tmpnam(char *s);
biimindedir. lev, rettii dosya ismini kendisine gnderilen char trden adrese yazar.
lev, ayn zamanda ayn dosya ismini statik mrl bir dizinin iine yazarak, bu dizinin
balang adresini geri dndrr. Eer ileve argman olarak NULL adresi gnderilirse,
ilev yalnzca statik mrl dizinin adresinin dndrr. leve char trden bir dizinin

474

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

adresi gnderildiinde bu dizinin boyutu ne olmaldr? Baka bir deyile tmpnam ilevi ka
karakter uzunluunda bir dosya ismi retir? te bu deer stdio.h dosyas iinde
tanmlanan L_tmpnam simgesel deimeziyle belirtilir.
tmpnam ilevinin rettii dosya isminin allan dizin iinde daha nce kullanlmayan bir
dosya ismi olmas gvence altna alnmtr. Yani retilen dosya ismi bulunulan dizin
iinde tektir. Bir programda daha sonra silmek zere bir dosya alacan ve bu dosyaya
birtakm bilgilerin yazlmasndan sonra dosyann silineceini ya da dosyaya baka bir
isim verileceini dnelim. Bu durumda ilgili dosya yazma modunda alacana gre, bu
dosyaya var olan bir dosyann ismi verilmemelidir. Eer var olan bir dosyann ismi
verilirse, var olan dosya sfrlanaca iin dosya kaybedilir. Bu riske girmemek iin, geici
olarak kullanlacak dosya tmpfile ilevi kullanlarak almaldr. Ancak tmpfile ilevinin
kullanlmas durumunda, alan dosya kalc hale getirilemez. Yani herhangi bir nedenden
dolay geici dosyann silinmemesi istenirse, dosya kalc hale getirilmek istenirse dosya
fopen ileviyle almaldr. te bu durumda geici dosya baka bir dosyay riske etmemek
iin tmpnam ilevinin rettii isim ile almaldr.
Peki tmpnam ileviyle en fazla ka tane gvenilir dosya ismi retilebilir? te bu deer
stdio.h iinde tanmlanan TMP_MAX simgesel deimezi ile belirlenmitir.

Akmlar

C dilinde baz giri ve k birimleri (klavye, ekran gibi) dorudan bir dosya gibi ele alnr.
Herhangi bir giri k birimini akm (stream) olarak isimlendirir. Bir akm, bir dosya
olabilecei gibi, dosya olarak ele alnan bir giri k birimi de olabilir. rnein kk
programlar genellikle girdilerini genellikle tek bir akmdan alp (rnein klavyeden)
ktlarn da tek bir aka (rnein ekrana) iletir.

stdout stdin ve stderr Akmlar

Bir programa yaplan girdilerin programa doru akan bir byte akmndan (input stream)
geldii kabul edilir. Yine bir programn kts da programdan darya doru akan byte lar
olarak (output stream) dnlr. Dosyalarla ilgili okuma yazma yapan ilevler dorudan
giri akmndan okuma yapp, k akmna yazabilirler.
Bir C program altrldnda 3 akm gsteren dosyann otomatik olarak ald kabul
edilir. Bu akmlar birer dosya olarak kullanlabilirler ve nceden tanmlanm FILE *
trnden deerlerle ilikilendirilmilerdir:
stdin : Standart giri birimini temsil eder. Bu akm normal olarak klavyeye balanmtr.
stdout : Standart k akmn temsil eder. Bu akm normal olarak ekrana balanmtr.
stderr : Standart hata akmn temsil eder. Bu akm da normal olarak ekrana
balanmtr.
Daha nce klavyeden girdi alan ilevler (getchar, gets, scanf) olarak rendiimiz ilevler
aslnda stdin akmndan okuma yapan ilevlerdir.
Daha nce ekrana yazan ilevler (putchar, puts, printf) olarak rendiimiz ilevler
aslnda stdout akmna yazan ilevlerdir.
Dosyadan okuma yapan ilevlere stdin, yazma yapan ilevlere ise stdout ve stderr FILE *
trnden deerler olarak geilebilir. rnein
fprintf(stdout, "Necati Ergin");
ars ekrana Necati Ergin yazsn yazdrr. Benzer biimde
fputc('A', stdout);
Ekrana 'A' karakteri bastrr.
fscanf(stdin, "%d", &val);

475

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

ars klavyeden alnan deeri val deikenine atar.

Akmlarn Ynlendirilmesi

letim sistemlerinin ou giri ve k akmlarnn baka dosyalara ynlendirilmesine izin


verir. rnein ismi asalyaz olan bir programn altrldnda ekrana 1 - 1000 aralnda
asal saylar yazdrdn dnelim. Programn kaynak kodunda yazdrma ilemi iin
printf ilevi arlm olsun. Bu program DOS / WINDOWS iletim sistemlerinde komut
satrndan bu program
asalyaz
biiminde altrldnda
ktsn ekrana yazar.
Komut satrndan asalyaz program,
asalyaz > asal.txt
biiminde altrlrsa axsalyaz programnn stdout akmna yani ekrana gnderdii her
ey asal.txt dosyasna yazlr. Burada kullanlan '>' simgesine "ynlendirme"
(redirection) simgesi denir.
Benzer biimde '<' ynlendirme simgesi de stdin akm iin kullanlr. rnein, ismi
process olan bir program
process < numbers.txt
biiminde altrlrsa, normal olarak klavyeden alnacak her bilgi numbers.txt
dosyasndan alnr.
Her iki ynlendirme simgesi de bir arada kullanlabilir:
process < numbers.txt > prime.txt
process ilevi yukardaki gibi altrldnda girdisini numbers.txt dosyasndan alacak
ktsn ise prime.txt dosyasna yazar.
Bunlarn dnda UNIX iletim sisteminde '|' biiminde baka bir ynlendirme simgesi
daha vardr.
x | y
gibi bir ilemde x ve y iki program olmak zere, bu iki program ayn anda altrlr, x
programnn ekrana yazd her ey y programnda klavyeden giriliyormu gibi ilem
grr. Bu ynlendirme ilemine pipe ad verilir.
stderr dosyas da normal olarak ekrana ynlendirilir. Yani standart fprintf ilevi ile stderr
dosyasna bir yazma ilemi yaplrsa, yazlanlar yine ekrana kar. Ancak stdout akm
baka bir dosyaya ynlendirilirse, stderr akm ynlendirme ileminden etkilenmez, halen
ekrana bal kalr. Yani komut satrndan ynlendirme yaplm olsa bile
fprintf(stderr, "hata!\n");
gibi bir ar sonucunda "Hata" yazs, dosyaya deil ekrana yazlr. Hata iletileri printf
ilevi ile ekrana yazdrlmak yerine fprintf ilevi ile stderr akmna yazdrlmaldr.

fgets levinin stdin Deeri le arlmas:

fgets ilevinin nc parametresin FILE * trnden bir deer istediini biliyorsunuz:

476

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

fgets(char *str, int n, FILE *f);


levin bu parametresine stdin deeri geildiinde, diziye yerletirilecek satr klavyeden
alnr. Byle bir ar gets ilevine yaplan bir arya tercih edilmelidir, nk gsterici
hatas riski ortadan kaldrlm olur.
char str[20];
gets(s);
Yukarda gets ilevine yaplan arda, klavyeden 20 ya da daha fazla karakter girilmesi
bir gsterici hatas olumasna neden olur. Ancak ar
fgets(str, 20, stdin);
biiminde yapldnda diziye en fazla 19 karakter yazlr. Yani gsterici hatas olumas
riski yoktur. Yalnz burada dikkat edilmesi gereken nokta fgets ileviyle diziye '\n'
karakterinin de yazlmas olasldr. Aadaki kodu inceleyin:
#include <stdio.h>
#include <string.h>
int main()
{
char str[20];
printf("bir isim giriniz : ");
fgets(str, 20, stdin);
if (!strcmp(str, "NECATI"))
printf("esit\n");
else
printf("esit degil\n");
}

return 0;

Yukardaki program altrldnda klavyeden NECATI ismi girildiinde ekrana "eit degil"
yazs yazdrlr. Zira fgets ilevi NECATI girii yapldktan sonra girilen newline karakterini
de diziye yerletirir. Yani aslnda strcmp ilevi
N E C A T I
N E C A T I \n
yazlarn karlatrr.
Karlatrma ileminden nce aadaki gibi bir if deyimi kullanlabilirdi:
if ((ptr = strchr(str, '\n')) != NULL)
*ptr = '\0';
Yukardaki deyimde strchr ileviyle str adresindeki yaznn iinde '\n' karakteri aranyor.
Yaznn iinde '\n' karakteri bulunursa, bu karakterin yerine sonlandrc karakter
yazlyor. Yani yaznn sonunda '\n' karakteri varsa yazdan siliniyor.

freopen levi

Bu ilev daha nce alm bir dosyay, kendi at dosyaya ynlendirir. levin bildirimi:

477

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

FILE *freopen(const char *filename, const char *mode, FILE *stream);


biimindedir.
Uygulamalarda daha ok standart dosyalarn (stdin, stdout, stderr) baka dosyalara
ynlendirilmesinde kullanlr. rnein bir programn ktlarnn data.dat isimli dosyaya
yazlmas istenirse :
if (freopen("data.dat", "w", stdout) == NULL) {
printf("data.dat dosyas alamyor\n");
exit(EXIT_FAILURE);
}
Yukardaki ilev arsyla stdout dosyasnn ynlendirildii dosya kapatlarak stdout
dosyasnn data.dat dosyasna ynlendirilmesi salanr. Bu ynlendirme ilemi komut
satrndan yaplm olabilecei gibi, freopen ilevine daha nce yaplan bir ar ile de
gerekletirilmi olabilir.
freopen ilevinin geri dn deeri ileve gnderilen nc argman olan FILE yaps
trnden gstericidir. freopen dosyas ynlendirmenin yaplaca dosyay aamazsa NULL
adresine geri dner. Eer ynlendirmenin yapld eski dosya kapatlamyorsa, freopen
ilevi bu durumda bir iaret vermez.

feof levi

Dosya konum gstericisi dosyann sonunu gsterdiinde bir dosyadan okuma yaplrsa
okuma ilemi baarl olmaz. Bu durumda isel olarak tutulan bir bayrak set edilir.
Dosyadan okuma yapan ilevler nce bu bayran deerine bakar. Bayrak set edilmise
okuma yapmazlar. feof ilevi bu bayran deerini alr:
int feof(FILE *);
Dosya konum gstericisi dosya sonunu gsterirken dosyadan okuma yaplmsa ilev sfr
d bir deere dner. Aksi halde ilev 0 deerine geri dner.
feof ileviye ilgili yaplan tipik bir hata, ilevin dosya konum gstericisinin dosyann
sonunu gsterip gstermediini snadn sanmaktr:
if (feof(f))
/*****/
deyimi ile byle bir snama yaplamaz. nk feof ilevi dosya konum gstericisi dosya
sonunu gstermesine karn bu konumdan daha hi okuma giriiminde bulunulmamsa 0
deerine geri dner. Bir metin dosyasnn ieriini ekrana yazdrmak isteyen aadaki C
kodu hataldr. Neden hatal olduunu bulmaya aln:

478

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
#include <stdlib.h>
#define FILE_NAME_LEN
#define BUFFER_SIZE

256
20

int main()
{
char source_file_name[FILE_NAME_LEN];
char buffer [BUFFER_SIZE];
FILE *fs;
printf("yazdirilacak dosya ismi: ");
gets(source_file_name);
fs = fopen(source_file_name, "r");
if (fs == NULL) {
printf("%s dosyasi acilamiyor!\n", source_file_name);
exit(EXIT_FAILURE);
}
while (!feof(fs)) {
fgets(buffer, BUFFER_SIZE, fs);
printf("%s", buffer);
}
fclose(fs);
}

return 0;

ferror levi

Okuma ya da yazma yapan ilevler, okuma ya da yazma ileminde bir hata olduunda
isel olarak ounlukla bitsel bir alanda tutulan bir bayra birlerler. Okuma ya da yazma
yapan ilevler nce bu bayran deerine bakar. Bayrak set edilmise yeni bir
okuma/yazma ilemi yaplamaz. nce bayran tekrar sfrlanmas gerekir. ferror ilevi
hata bayrann birlenip birlenmediini snar:
int ferror(FILE *);
hata bayra set edilmise ilev sfr d bir deere geri dner. Hata bayra set
edilmemise ilev 0 deerine geri dner.

clearerr levi
void clearerr(FILE *stream );
Okuma ya da yazma ileminde bir hata olduunda hata bayrann set edildiini, dosya
sonundan okuma yapma giriiminde de EOF bayrann set edildiini sylemitik. Bu
bayraklar set edilmi durumdayken bir okuma ya da yazma ilemi gerekletirilemez.
Yeniden bir okuma ya da yazma ileminin yaplabilmesi iin nce bayraklarn sfrlanmas
gerekir. Bu sfrlama ilemi iin clearerr ilevi arlabilir.
lev ilgili dosyaya ilikin FILE * trnden deeri alr ve bu dosyann EOF ve Error
bayraklarn sfrlar.

ungetc levi

Bu ilev dosyadan okunan karakteri, dosyann tampon alanna geri koyar.


int ungetc(int c, FILE *f);

479

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

ungetc ilevi iin dosyann okuma modunda alm olmas gerekir. levin arlmasndan
sonra yaplan ilk okumada c deeri okunur. lev baarl olursa, c deerine geri dner.
Baarszlk durumunda dosyann tampon alannda bir deiiklik olmaz ve EOF deeri
dndrlr. lev, karakteri tampon alanna yerletirdikten sonra EOF bayran da
sfrlar. Dosya konum gstericisi yeniden konumlandrlmadan ungetc ilevi arka arkaya
arlmamaldr.

Dosya Tamponlama levleri

kincil belleklerle (disket, hard disk vs.) yaplan ilemler bellekte yaplan ilemlere gre
ok yavatr. Bu yzden bir dosyadan bir karakterin okunmas ya da bir dosyaya bir
karakterin yazlmas durumunda her defasnda dosyaya dorudan ulamak verimli bir
yntem deildir.
lemin verimi tamponlama (buffering) yoluyla artrlr. Bir dosyaya yazlacak veri ilk nce
bellekteki bir tampon alannda saklanr. Bu tampon alan dolduunda ya da yazma
ileminin yaplaca dosya kapatldnda tampondaki alanda ne veri varsa dosyaya
yazlr. Buna tampon alannn boaltlmas (flushing) denir.
Giri dosyalar da benzer ekilde tamponlanabilir. Giri aygtndan rnein klavyeden
alnan byte'lar nce tampona yazlr.
Dosyalarn tamponlanmas verimlilikte ok byk bir arta neden olur. nk tampondan
yani bellekten bir karakter okunmas ya da tampona bir karakter yazlmas ihmal edilecek
kadar kk bir zaman iinde yaplr. Tampon ile dosya arasndaki transfer, phesiz yine
zaman alr ama bir defalk blok aktarm , kk kk aktarmlarn toplamndan ok daha
ksa zaman alr.
stdio.h balk dosyas iinde bildirimi yaplan ve dosyalarla ilgili ilem yapan ilevler
tamponlamay otomatik olarak gerekletirir. Yani dosyalarn tamponlanmas iin
programcnn birey yapmasna gerek kalmadan bu i geri planda programcya
sezdirilmeden yaplr. Ama baz durumlarda tamponlama konusunda programc belirleyici
durumda olmak isteyebilir. te bu durumlarda programc dosya tamponlama ilevlerini
(fflush, setbuf, setvbuf) kullanr:

fflush levi

Dosyalar zerindeki giri k ilemleri, ounlukla tamponlama yoluyla yaplr. Dosyaya


yazma ilemi gerekletiren bir ilev arldnda, eer tamponlama yaplyorsa, ilev
yazma ilemini bellekteki bir tampon alanna yapar. Dosya kapatldnda ya da
tamponlama alan dolduunda, tamponlama alan boaltlarak dosyaya yazlr.
fflush ilevinin arlmasyla, dosyann kapatlmas ya da tamponlama alannn dolmas
beklenmeksizin, tamponlama alan boatlarak dosyaya yazlr. Bu ilem istenilen sklkta
yaplabilir. levin bildirimi:
int fflush (FILE *stream);
biimindedir.
fflush(fp);
ars ile FILE yaps trnden fp gstericisi ile ilikilendirilen dosyann tamponlama alan
(buffer) boaltlr. Eer fflush ilevine NULL adresi gnderilirse, ak olan btn dosyalarn
tamponlama alanlar boaltlr.
Tamponlama alannn boaltlmas ilemi baarl olursa fflush ilevi 0 deerine geri
dner, aksi halde EOF deerine geri dner.

setvbuf levi

setvbuf ilevi bir dosyann tamponlanma biiminin deitirilmesi ve tampon alannn


yerinin ve boyutunun deitirilmesi amacyla kullanlr. levin bildirimi aadaki
ekildedir:

480

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

int setvbuf(FILE *stream, char *buf, int mode, size_t size);


leve gnderilen nc argman tamponlama eklini belirler. nc argmann deeri
stdio.h balk dosyas iinde tanmlanan simgesel deimezlerle belirlenir.
_IOFBF (full buffering - tam tamponlama)
Veri dosyaya tamponlama alan dolduunda yazlr. Ya da giri tamponlamas sz konusu
ise dosyadan okuma tamponlama alan bo olduu zaman yaplr.
_IOLBF (line buffering - satr tamponlamas)
Tamponlama alan ile dosya arasndaki okuma ya da yazma ilemi satr satr yaplr.
_IONBF (no buffering - tamponlama yok)
Dosyadan okuma ya da soyaya yazma tamponlama olmadan dorudan yaplr.
setvbuf ilevine gnderilen ikinci argman RAM'de tamponlamann yaplaca bloun
balang adresidir. Tamponlamann yaplaca alan statik ya da dinamik mrl
olabilecei gibi, dinamik bellek ilevleriyle de elde edilebilir.
leve gnderilen son argman tamponlama alannda tutulacak byte'larn saysdr.
setvbuf ilevi dosya aldktan sonra, fakat dosya zerinde herhangi biri ilem yaplmadan
nce arlmaldr. levin baarl olmas durumunda ilev 0 deerine geri dner. leve
gnderilen nc argmann geersiz olmas durumunda ya da ilevin ilgili
tamponlamay yapamamas durumunda, geri dn deeri sfrdan farkl bir deer olur.
leve gnderilen tampon alannn geerliliinin bitmesinden nce, yani mrnn
tamamlanmasndan nce dosya kapatlmamaldr.

Dosyalarla lgili lem Yapan levlerin Yazm

Bir dosya ile ilgili ilem yapan bir ilev iki ayr biimde tasarlanabilir:
1. lev arldnda dosya aktr. Bu durumda ilevin bir parametresi FILE * trnden
olur. lev arlmadan nce, en son okuma ilemi mi yazma ilemi mi yapld
bilinemeyeceinden, byle bir ilev ilk ilem olarak dosya konum gstericisini
konumlandrmaldr. Aadaki ilevleri inceleyin:

481

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

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

SORTED
NOT_SORTED

1
0

void swap(int *p1, int *p2)


{
int temp = *p1;
*p1 = *p2;
*p2 = temp;
}
void add_ints_to_file(FILE *f)
{
int k, val, number;

fseek(f, 0L, SEEK_END);


number = rand() % 100 + 300;
for (k = 0; k < number; ++k) {
val = rand();
fwrite(&val, sizeof(int), 1, f);
}

void print_file(FILE *f)


{
int val;
int counter = 0;

rewind(f);
while (fread(&val, sizeof(int), 1, f)) {
if (counter && counter % 10 == 0)
printf("\n");
printf("%5d ", val);
counter++;
}
printf("\n********************************************************\n");

void sort_file(FILE *f)


{
int a[2];
int k, temp, sort_flag, number_of_ints;
fseek(f, 0L, SEEK_END);
number_of_ints = ftell(f) / sizeof(int);
do {
sort_flag = SORTED;
for (k = 0; k < number_of_ints - 1; ++k) {
fseek(f, sizeof(int) * k, SEEK_SET);
fread(a, sizeof(int), 2, f);
if (a[0] > a[1]) {
swap(a, a + 1);
fseek(f, sizeof(int) * k, SEEK_SET);
fwrite(a, sizeof(int), 2, f);
sort_flag = NOT_SORTED;
}
}

482

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

} while (sort_flag == NOT_SORTED);

int main()
{
FILE *f;
f = fopen("sayilar.dat", "w+b");
if (f == NULL) {
printf("dosya yaratilamiyor!\n");
exit(EXIT_FAILURE);
}
srand((unsigned int)(time(0)));
add_ints_to_file(f);
print_file(f);
sort_file(f);
print_file(f);
fclose(f);
}

return 0;

main ilevi iinde arlan ilevlerden add_ints_to_file ilevi ald binary dosyann sonuna
rastgele tamsaylar formatsz olarak yazyor. Daha sonra arlan print_file ilevi, binary
dosyaya yazlan tm saylar ekrana yazyor. sort_file ilevi ile dosyadaki tamsaylar
kkten bye doru sralandktan sonra print_file ileviyle yeniden yazdrlyor.
2. lev arldnda dosya kapaldr. lev, aran kod parasndan dosya ismini ister.
Bu durumda ilev iini gerekletirmek iin nce dosyay aar. ini gerekletirdikten
sonra dosyay kapatr. Aada bir metin dosyasnn ieriini ekrana yazdran bir ilev
tanmlanyor:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void ftype(const char *file_name)
{
int ch;

FILE *f = fopen(file_name, "r");


if (f == NULL) {
printf("cannot open %s\n", file_name);
exit(EXIT_FAILURE);
}
while ((ch = fgetc(f)) != EOF)
putchar(ch);
fclose(f);

483

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

MAKROLAR
Yapsal programlama alt programlamaya dayanr. Bir problem zm daha kolay
admlara ayrlr, bu admlar iin ilevler tanmlanr. Programn kullanaca veri ilevler
tarafndan ilenir. Tanmlanan ilevlerden bazlarnn kaynak kodu ok ksa olabilir.
Aadaki gibi bir ilev tanmlandn dnelim:
int get_max(int a, int b)
{
return a > b ? a : b;
}
get_max ilevi kendisine gnderilen iki saydan daha byk olanna geri dnyor. imdi
de u soruyu soralm: Bu kadar ksa kaynak koda sahip bir ilev tanmlanmal mdr? lev
tanmlamak yerine ilevin kodunu, dorudan ilev arsnn bulunduu yere yerletirmek
daha iyi olmaz m?
Yazlan bir kod parasnda iki saydan bynn bulunmas gerektiini dnelim:
x = get_max(y, z);
gibi bir deyim yerine
x = y > z ? y : z;
gibi bir deyim yazlamaz m?
Bir ilev tanmlayp tanmlanan ilev mi arlmal yoksa ilevin kodu dorudan m
yazlmaldr?
nce, ilev tanmlamay destekleyen argmanlar zerinde duralm:
1. lev ars, zellikle ilevin ismi iyi seilmi ise, ou zaman okunabilirlii daha
yksek bir kod oluturur. Aadaki rnei inceleyin:
a = get_max(ptr->no, per.no);
a = ptr->no > per.no ? ptr->no : per.no;
lk deyimde get_max isimli bir ilev arlm ikinci satrda iki ifadeden deeri daha
byk olan, bir ilev arlmadan bulunmutur. Hangi deyimin okunabilirlii daha iyidir?
2. lev ars ou durumda kaynak kodu kltr. zellikle, ileve konu ilem kaynak
kod iinde sk yineleniyorsa, bir ilevin tanmlanarak eitli yerlerde arlmas kaynak
kodu kltr.
3. lev ars kaynak kodda deiiklik yapmay daha kolay hale getirir:
Kaynak kod iinde bir ok yerde, iki deerden daha bynn bulunarak kullanldn
dnelim. Daha sonra kaynak kodun bu noktalarnda deiiklik yaplarak, ayn
noktalarda iki deerden daha knn bulunarak kullanlmas gerektiini dnelim.
Eer ilev ars yerine kod ak bir ekilde yazlmsa, deiiklik yapmak ok daha zor
olur.
4. lev ars, debug etme olanan artrr. Debugger programlar genel olarak ilev
arlar iin, kodun ak olarak yazlmasna gre daha iyi destek verir.
5. lev ars derleyiciye baz snamalar yapma olanan verir. leve gnderilen
argmanlarn toplam saysnn ilevin parametre deikenlerinin toplam saysna eit olup

485

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

olmad derleyici tarafndan snanr. Ayrca ileve gnderilen argmanlarn tr ile ilevin
ilgili parametre deikeninin trlerinin uyumlu olup olmad da derleyici tarafndan
snanr.
imdi de ilev ars yapmak yerine ilevin kodunu dorudan yazmak durumunda elde
edilebilecek avantajlarn ne olabileceine bakalm:
Bir ileve yaplan arnn ilemci zaman ve bellek kullanm asndan ek bir maliyeti
vardr. leve giri ve ilevden k kodlarnn yrtlmesi iin ek makina komutlarnn
yrtlmesi gerekir. Varsa ilevin parametre deikenleri de, ilev arldnda bellekte
yer kaplar. zellikle kaynak kodu ok ksa, kaynak dosya iinde ok arlan ilevler iin,
ou durumda bu maliyetin denmesi istenmez.
lev ars yapmak yerine kod ak bir biimde yazlrsa, derleyici kodun bulunduu yere
bal olarak daha verimli bir eniyileme (optimizasyon) gerekletirebilir.

Makro Nedir

Makro, ilev tanmlamadan ilev arsnn getirdii baz avantajlardan yararlanlmasn


salayan bir aratr. Ortada gerek bir ilev tanm sz konusu olmadndan, ilev iin
denen bir ek gider de sz konusu deildir.
Makrolar, nilemci programn #define komutu ile tanmlanr. Bir makro tanm, nilemci
programa verilen parametrik bir yer deitirme komutudur.
#define MAX(X, Y)

((x )> (y) ? (x) :(y))

MAX, tanmlanan makronun ismidir. Bu ismi "alan ayra" karakteri izlemelidir.


Makro ismini izleyen ayra iinde, virgllerle ayrlarak bildirilen isimlere "makro
parametreleri" denir. Kapanan ayrac izleyen boluktan sonra gelen atomlar "makro yer
deitirme listesi"dir. Yer deitirme listesinde, makro parametreleri istenildii kadar
istenildii sra ile kullanlabilir.
nilemci program kaynak kodun izleyen kesiminde MAX ismi ile karlatnda, ayra
iindeki ifadeleri makro argman olarak kabul eder. Makro tanmnda bulunan yer
deitirme listesinde makro parametreleri nasl kullanlmsa, makro arsnn bulunduu
yerlerde benzer bir yer deitirme ilemi yaplr. Aadaki kodu inceleyin:
#include <stdio.h>
#define
#define

ISEVEN(a)
MAX(a, b)

(!((a) & 1))


((a) > (b) ? (a) : (b))

int main()
{
int x, y;
printf("iki sayi giriniz :");
scanf("%d%d", &x, &y);
if (ISEVEN(x))
printf("%d cift sayi!\n", x);
else
printf("%d tek sayi!\n", x);
printf("%d ve %d sayilarindan buyugu = %d\n", x, y, MAX(x, y));
}

return 0;

Yukardaki main ilevinde, ismi ISEVEN ve MAX olan iki makro tanmlanyor. nilemci
makro tanmnn zerinden getikten sonra
if (ISEVEN(x))

486

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

satr ile karlatnda, ISEVEN isminin daha nce tanmlanan makroya ait olduunu ve
makro argman olarak x atomunun kullanldn anlar. nilemci program ilgili yer
deitirme ilemini yaptnda bu satr aadaki biime dnr:
if ((!((x) & 1)))
Benzer ekilde
printf("%d ve %d sayilarindan buyugu = %d\n", x, y, MAX(x, y));
satr da MAX isimli makronun nilemci program tarafndan almas sonucu
printf("%d ve %d sayilarindan buyugu = %d\n", x, y, ((x) > (y) ? (x) :
(y)));
haline getirilir.

Gvenli Makro Yazmak


Aadaki makroyu inceleyin:
#define Kare(x)

x * x

Kaynak kod iinde bu makro aadaki gibi kullanlm olsun:


void func()
{
int a = 10;
int b;
b = Kare(a + 5);
/***/
}
Kare eer bir ilev olsayd, ileve gnderilen argman olan a + 5 ifadesinin nce deeri
hesaplanrd. Argman olan ifadenin deeri 15 olduu iin arlan ilev 225 deerine geri
dnerdi. Ancak nilemci program aadaki gibi bir yer deitirme ilemi yapar:
b = a + 5 * a + 5;
arpma ileci toplama ilecine gre daha yksek ncelikli olduu iin burada b
deikenine atanacak deer 65 olur, deil mi? Bu tr ncelik sorunlarn zmek amacyla
makro parametreleri, alm listesinde ayra iine alnmaldr:
#define Kare(x)

(x) * (x)

Bu kez ayn ifade nilemci tarafndan aadaki gibi alr:


b = (a + 5) * (a + 5);
b deikenine atanan deer 225 olur. Ancak imdi de makronun aadaki gibi
kullanldn dnn:
b = 100 / Kare(a);
Kare ilev olsad b deikenine 1 deeri atanrd deil mi? Ancak yukardaki makro
nilemci tarafndan
b = 100 / (a) *( a);

487

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Burada b deikenine atanan deer 100 olur.


Bu tr ncelik sorunlarn zmek amacyla makro alm listesi dtan ncelik ayrac iine
alnmaldr.
#define Kare(x)

((x) *(x))

Bu kez ayn ifade nilemci tarafndan aadaki gibi alr:


b = 100 / ((a) * (a));
Bu kez b deikenine atanan deer 1 olur.
Makro alm listesini dtan ayra iine almak ve alm listesinde yer alan makro
parametrelerinin her birini ayra iine almak makrolar gvenilir klmaya yetmez. Zaten
makrolarla ilgili en byk sorun gvenilirlik sorunudur. Aadaki kodu inceleyin:
#include <stdio.h>
#define Kare(x)

((x) * (x))

int func(int val);


int main()
{
int x = 10;
int y = Kare(x++);
int z = Kare(func(y));
/*********/
return 0;
}
y = Kare(x++);
deyiminde eer Kare bir ilev olsayd bu ilev 10 deeri ile arlm olurdu. Sonek
konumundaki ++ ilecinin yan etkisi nedeniyle, x nesnesinin deeri 11 olurdu. Ancak
makro nilemci tarafndan aldnda derleyicinin grecei kod
y = ((x++) * (x++));
biiminde olur ki, bu durum "tanmsz davrantr" (undefined behaviour).
z = Kare(func(y));
deyimini de nilemci aadaki gibi aar:
z = ((func(y)) * (func(y)));
Derlenen kod, func ilevinin iki kez arlmasna neden olur. Oysa Kare bir ilev olsayd,
arlan func ilevinin retecei geri dn deeri, bu kez Kare ilevine argman olarak
gnderilmi olurdu.

rnek Makrolar

Aada baz faydal makro tanmlamalarna rnekler verilmitir. rnekleri inceleyin:


#define
#define
#define
#define

GETRANDOM(min,
ISLEAP(y)
SWAPINT(x, y)
XOR(x, y)

max)
((rand()%(int)(((max) + 1)-(min)))+ (min))
((y) % 4 == 0 && (y) % 100 != 0 || (y) % 400 == 0)
((x) ^= (y) ^= (x) ^= (y))
(!(x) ^ !(y))

488

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yukarda tanmlanan getrandom isimli makro min ve max deerleri arasnda bir rastgele
tamsaynn retilmesine neden olur.
isleap makrosu nilemci tarafndan aldnda makro argman olan ifadenin deerinin
artk yl olmas durumunda 1 deeri aksi halde 0 deeri retilir. Bu durumda makro bir
snama ilevi gibi kullanlr.
swap_int makrosu argman olan tamsay deikenlerin deerlerini takas eden bir ifadeye
alr.
Bir makronun parametreye sahip olmas gerekmez. Aada tanmlanan randomize
makrosunu inceleyin:
#define randomize()

srand((unsigned int)time(NULL))

nilemci Dizge Yapma leci

Bir makro tanmnn alm listesinde yer alan # atomu nilemci programn bir ilecidir.
# ileci nek konumunda tek terimli bir iletir. Bu ilemcinin terimi makro
parametrelerinden biri olmaldr. Parametresiz makrolarda bu ile kullanlamaz.
nilemci makroyu atnda makro parametresine karlk gelen makro argmann ift
trnak iine alr:
Aadaki kodu inceleyin:
#include <stdio.h>
#define

printint(x)

printf(#x " = %d\n", x);

int main()
{
int a = 10;
int b = 20;
printint(a);
printint(a + b);
}

return 0;

Yukardaki rnekte, printint makrosu alm listesinde, makro parametresi olan x, dizge
yapma ilecinin terimi yaplyor. nilemci program, main ilevinin kodunu aadaki
biime dntrr.
int main()
{
int a = 10;
int b = 20;
printf("a" " = %d\n", a);
printint("a + b" " = %d\n", a + b);
return 0;
}
Boluk karakterleriyle birbirinden ayrlan dizgelerin, derleyici tarafndan otomatik olarak
birletirilerek tek dizge haline getirildiini anmsayn. Program derlenerek altrldnda
ekran kts aadaki gibi olur:
a = 10
a + b = 30

489

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Makro argman olarak bir dizge verilirse dizgenin banda ve sonunda yer alan ift
trnak (") karakterleri ve dizgenin iinde yer alan ters bl (\) ve ift trnak (")
karakterinin nne makro almnda otomatik olarak ters bl karakteri yerletirilir.
Aadaki kodu inceleyin:
#include <stdio.h>
#define print(x)

printf(#x)

int main()
{
print(Ekranda bu yazi gorulecek\n);
print("Ekranda bu yazi cift tirnak icinde gorunecek"\n);
print("\""\n);
return 0;
}
Program derlenip altrldnda ekran kts aadaki gibi olur:
Ekranda bu yazi gorulecek
"Ekranda bu yazi cift tirnak icinde gorunecek"
"\""

nilemci Atom Birletirme leci

nilemci programn ikinci ileci "##" atom birletirme ielecidir (tokenpasting operator).
Atom birletirme ileci iki terimlidir araek konumundadr. Parametreli ya da parametresiz
makrolarda kullanlabilir. Terimlerinin, makro parametrelerinden biri olmas zorunlu
deildir. nilemci, atom birletirme ilecinin terimlerini birletirerek, terimlerinden tek
bir atom yapar. Aadaki rnei inceleyin:
#include <stdio.h>
#define

paste(x, y)

x##y

int main()
{
int paste(a,1);
a1 = 10;
printf("a1 = %d\n", a1);
}

return 0;

Yukardaki rnekte, nilemci program tarafndan paste isimli makronun almas sonucu
a ve 1 makro argmanlar birletirilerek a1 atomu elde edilir.

Bir Makro le Bir levin Ayn smi Paylamas

Baz ktphanelerde belirli ilevler ayn isimle hem makro hem de ilev olarak
tanmlanrlar. Bundan amalanan, programcnn istee bal olarak makro kullanmn ya
da ilev arsn semesine olanak vermektir. Hem kare isimli bir makro tanmlanm
hem de kare isimli bir ilev bildirilmi olsun:
int kare(int);
#define

kare(a)

((a) * (a))

Kaynak kodda aadaki gibi bir deyim olsun:

490

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

x = kare(y);
phesiz, byle bir deyimde makro kullanlm olur. nk nilemci, program kodunu
derleyici programdan daha nce ele alr. Derleyiciye sra geldiinde, nilemci zaten ilgili
makro iin yer deitirme ilemini tamamlam olur. Ancak makro yerine ilev arsn
semek iin iki yntem kullanlabilir.
1. #undef nilemci komutu kullanlarak makro tanm ortadan kaldrlabilir:
#undef kare
x = kare(y);
nilemci program #undef konutuyla karlatnda makro tanmn ortadan kaldrr ve
izleyen satrlarda kare ismini grdnde bir yer deitirme ilemi yapmaz.
2. kare ismi ayra iine alnarak makro devre d braklabilir
x = (kare)(y);
Bu durumda kare ismini izleyen ilk atom, alan ayra "(" karakteri olmadndan,
nilemci program yer deitirme ilemi yapmaz. Ancak ilev arsn engelleyen bir
durum sz konusu deildir. lev isminin bir adres belirttiini biliyorsunuz. Yukardaki
ifade ile ilev adresine dntrlecek olan kare ismi ncelik ayrac iine alnmtr.
3. Bir ilev, bir ilev gstericisi kullanlarak arlabilir:
int kare(int);
void func()
{
int (*fp)(int) = &kare;
fp();
}
Derleyiciler, standart ktphaneye ilikin ilevleri ayn zamanda makro olarak da
tanmlayabilirler. rnein derleyicilerin ou cytpe.h balk dosyasnda bildirilen karakter
test ilevlerini ayn zamanda makro olarak tanmlar.

Makrolar ile levler Arasndaki Farklar

1. Makrolar ou zaman ayn ii yapan ileve gre daha hzl alan bir kodun
retilmesine neden olurlar. Zaten makrolarn kullanld durumlarda hedeflenen de
budur.
2. Makrolar, her kullanld yerde nilemci tarafndan ald iin, ounlukla kaynak
kodu bytr. Kaynak kodun byd durumlarn ounda, altrlabilir dosyann
boyutu da byr. Ancak bir ilev ka kez arlrsa arlsn, o ilevin tanm kaynak kod
iinde bir kez yer alr.
3. Makro paremetreleri makro alm iinde birden fazla kullanlyor ise makro alm
sonucu istenmeyen durumlar oluabilir. Makro argman olarak kullanlan ifadenin bir yan
etkiye sahip olmas durmunda bu yan etki birden fazla kez oluur. Ancak ilevler sz
konusu olduunda byle bir risk sz konusu deildir.
4. Bir ilevin adresi ilev gstericilerinde tutularak baz ilemler gerekletirilebilir. Ancak
bir makronun adresi olmaz.
5. Bir makro sz konusu olduunda nilemci program, makroya verilen argmanlarn
says ile makro parametrelerinin saysnn uyumunu kontrol edebilir. Ancak nilemci
491

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

program makro argmanlaryla makro parametrelerinin tr asndan uyumunu kontrol


edemez, makrolar trden bamszdr. Ancak ilevler trlere ilikin yazldndan
derleyicinin yapaca tr kontrollerine tabidir. Derleyici ileve gnderilen argmanlarla
ilev parametrelerinin trlerinin uyumsuz olmas durumunda hata ya da uyar iletisi
retebilir.

Makro Almlarnn Alt Satrdan Devam Etmesi

Bir makro alm listesinin yazm makronun tanmland satrda sonlanmak zorunda
deildir. Makro alm listesinin yazm alt satrdan devam edebilir. Bunun iin alt satra
gemeden nce ters bl karakteri '\' kullanlr.

Makrolar ile lev Kalb Oluturulmas

Makrolar kullanlarak ilev kalb hazrlanabilir. Aadaki rnekte bir dizinin en byk
elemann bulan bir ilev kalb hazrlanyor:
#include <stdio.h>
#define generic_max(T)

T getmax_##T(const T *ptr, size_t size) {\


int k; T max = *ptr; for (k = 1; k < size; ++k)\
if (ptr[k] > max) max = ptr[k]; return max;}

generic_max(int)
generic_max(double)
int main()
{
int a[10] = {1, 4, 5, 7, 8, 9, 10, 2, 3, 6};
double b[10] = {1.2, 3.5, 7.8, 2.4, 4.4, .7, 3.2, 4.8, 2.9, 1.};
printf("a dizisinin en buyuk elemani = %d\n", getmax_int(a, 10));
printf("b dizisinin en buyuk elemani = %lf\n", getmax_double(b, 10));
return 0;
}
generic_max isimli makronun tanmnda makro parametresi olarak T isminin kullanldn
gryorsunuz. Bu isim bir tr bilgisi olarak kullanlyor. nilemci atom birletirme
ileciyle, makro alm sonucunda farkl ilev isimleri elde edilir.

Makro Almnda Makro sminin Kullanlmas

Bir makro ismi ya da bir simgesel deimez, deitirme listesinde yer alabilir. Bu duruma
ngilizcede "self referential macro" denmektedir. Eer alm listesinde makronun kendi
ismi yer alrsa nilemci zyinelemeli bir yer deitirme ilemi yapmaz.
Aadaki rnei inceleyin:
#define max

(4 + max)

max isminin programn iinde kullanlan bir baka deikenin ismi olduunu dnelim.
x = max;
nilemci program yukardaki deyimin zerinden getiinde bu deyimi
x = 4 + max;
biimine dntrr. Ve daha sonra artk max ismini yine yer deitirme ilemine
sokmaz.

492

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Standart offsetof Makrosu

Bu makro stddef.h balk dosyas iinde tanmlanmtr. Makronun iki parametresi vardr.
Birinci parametreye bir yap tr ismi, ikinci parametreye yapnn bir eleman verilir.
Makronun almas sonucu oluan deimez ifadesinin deeri, bir yap elemannn yap
nesnesi iindeki konumunu gsteren offset deeridir. Yapnn ilk eleman iin bu deer
0'dr.
Aadaki rnei inceleyin:
#include <stdio.h>
#include <stddef.h>
struct Date {
int day, mon, year;
};
int main()
{
printf("%d\n", offsetof(struct Date, day));
printf("%d\n", offsetof(struct Date, mon));
printf("%d\n", offsetof(struct Date, year));
}

return 0;

offsetof makrosu derleyicilerin ounda aadaki gibi tanmlanr:


#define offsetof(type, member)

((size_t)&((type *)0)member)

493

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

NLEMC KOMUTLARI (2)


Koullu Derleme Nedir?

Koullu derleme, derleme ileminin bir koula ya da baz koullara gre yaplmasdr.
Yazlan kaynak kodun belirli ksmlar nilemci program tarafndan derleyiciye verilirken
baz ksmlar derleyiciye verilmez. Derleyiciye verilecek kaynak kod nilemci program
tarafndan seilir.

Koulu Derleme nilemci Komutlar

Koullu derlemede amacyla kullanlan nilemci komutlar


#if, #else, #elif, #ifdef, #ifndef, #endif
komutlardr.

#if ve #endif nilemci Komutlar

#if nilemci komutunun argman tamsay trnden bir deimez ifadesi olmaldr. if
szcn izleyen ifadenin deeri sfr d bir deer ise #if komutu ile #elif ya da #else
yada #endif komutlar arasnda kalan ksm derleyiciye verilir. Eer #if ifadesi yanl ise
yani ifadenin deeri sfr ise #if komutu ile #else arasnda kalan ksm derleyiciye
verilmez. Aadaki program derleyerek altrn:
int main()
{
#if 1
printf("bu yazi ekranda gorunecek\n");
#endif
#if 0
printf("bu yazi ekranda gorunmeyecek\n");
#endif
return 0;
}
#if komutunda kullanlacak ifade tamsay trnden olmaldr. Bu ifade iinde
Tamsay deimezleri kullanlabilir. nilemci program kullanlan tm say deimezlerini
iaretli long ya da iaretsiz long trnden varsayar.
Karakter deimezleri kullanlabilir.
Aritmetik ileler (+, -, *, /, %), karlatrma ileleri (<, <=, >, >=, ==, !=) , bitsel
ileler(~, &, ^, |) ve mantksal ileler (!, && ve || )kullanlabilir. && ve || ilelerinin
kullanmnda ksa devre davran geerlidir.
#if ifadesinin deerinin hesap edilmesinden nce simgesel deimezlerle ve makro
tanmlarna ilikin btn yer deitirme ilemleri yaplr.
Simgesel deimez ve makro ismi olmayan tm isimler 0 deerine sahip kabul edilirler.
#if ifadesinde sizeof ileci yer alamaz. Numaralandrma trlerinden deimezler temsil
ettikleri deerler olarak ele alnmaz. #if ifadesinde bir numaralandrma deimezi
kullanlrsa, bu deimez makro ismi olmayan tm isimler gibi 0 deeri olarak ele alnr.
#if komutu ile #endif komutu aralndaki alanda baka nilemci komutlar yer alabilir.
Bu alanda yer alan nilemci komutlar ancak #if ifadesi doru ise yerine getirilir.
#if komutunu izleyen ifade bu #if komutuyla ilikilendirilen #endif komutunu izleyen bir
yorum satr iinde yinelenirse, kodun okunabilirlii artar. Bu durum zellikle #if
komutlarnn i ie bulunmas durumunda fayda salar. Aadaki rnei inceleyin:

495

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#if MAX > 100


#if MIN < 20
#define LIMIT 100
#endif /* MIN < 20 */
#define UPPER_BOUND 2000
#endif /* MAX > 100 */

#else nilemci Komutu

# if komutunu bir #else komutu izleyebilir. Bu durumda #if ifadesinin deeri 0 d bir
deer ise yani ifade doru ise #if ve #else komutlar arasnda kalan kaynak kod paras
derleyiciye verilir. Eer bu ifade yanl ise #else ve #endif komutlar arasndaki ksm
derleyici programa verilir. Bylece bir tamsay deimez ifadesinin doru veya yanl
olmasna gre derleyiciye farkl kod paralar verilebilir. Aadaki program derleyerek
altrn:
#include <stdio.h>
#define

MAX

100

int main()
{
#if
MAX > 10
printf("%d\n", MAX);
#else
printf("**********\n");
#endif /*MAX > 100 */
return 0;
}

#elif nilemci Komutu

elif szc else if szcklerinin birletirilerek ksaltlmasndan elde edilmitir.


Tpk C dilinin if deyimi gibi bir #if komutunun doru ya da yanl ksmnda baka bir #if
komutu yer alabilir. #if ve #else komutlaryla bir merdiven oluturulabilir.
Bu amala kullanlabilecek bir komut #elif komutudur.
#elif komutunu yine bir tamsay deimez ifadesi izler. Eer bu tamsay deimez ifadesi
0 d bir deere sahipse doru olarak yorumlanr ve #elif komutu ile bunu izleyen bir
baka #elif ya da #endif komutu arasndaki ksm derleyiciye verilir. Aadaki rnei
derleyerek altrn:
#include <stdio.h>
#define

MAX

60

int main()
{
#if MAX > 10 && MAX <= 20
printf("(if)%d\n", MAX);
#elif MAX > 20 && MAX <= 50
printf("(elif1)%d\n", MAX);
#elif MAX > 50 && MAX < 100
printf("(elif2)%d\n", MAX);
#else
printf("(else)%d\n", MAX);
#endif
return 0;
}

496

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

defined nilemci leci

Makrolar konusunda nce nilemci programn dizge yapma (#) ve atom birletirme
(##) ilelerini grmtk. nilemci programn 3. ve son ilei defined ilecidir. defined
nilemci ilecini bir isim izler. Bu isim ayra iine de alnabilir:
defined MAX
defined (MAX)
Eer defined ilecinin terimi olan isimli daha nce tanmlanm bir simgesel var ise,
defined ileci 1 deeri retir. Bu isimli bir simgesel deimez yoksa defined ileci 0 deeri
retir.
Aadaki rnei inceleyin:
#include <stdio.h>
#define

MAX

100

int main()
{
#if defined MAX && !defined
MIN
printf("max = %d\n", MAX);
#endif
return 0;
}

#ifdef ve ifndef nilemci Komutlar

#if nilemci komutunun kullanld her yerde #ifdef ve #ifndef nilemci komutlar
kullanlabilir:
#ifdef nilemci komutunu bir isim(identifier) izler. Eer bu isim daha nce tanmlanm
bir simgesel deimeze ilikinse ilk #else, #elif ya da #endif neilemci komutlarna
kadar olan ksm derleyiciye verilir. Eer #ifdef nilemci komutunu izleyen isimde bir
simgesel deimez tanml deil ise ilk #else #elif #endif komutuna kadar olan ksm
derleyiciye verilmez. Bu komut ile yaplan i #if nilemci komutu ile defined ilecinin
birlikte kullanlmasyla da yaplabilir:
#ifdef ISIM
gibi bir nilemci komutu kullanm ile
#if defined (ISIM)
gibi bir nilemci komutu ayn anlamdadr.
#ifndef nilemci komutunu da bir isim(identifier) izler. Eer bu isimde bir isim daha
nce #define nilemci komutuyla tanmlanmam ise, ilk #else, #elif ya da #endif
neilemci komutuna kadar olan ksm derleyiciye verilir.
#ifndef nilemci komutunu izleyen isimde bir simgesel deimez tanmlanm ise #else
#elif #endif komutlarna kadar olan ksm derleyiciye verilmez.
#ifndef

SYSTEM

gibi bir nilemci komutu ile


#if !defined (SYSTEM)
gibi bir nilemci komutu ayn anlamdadr.
Aadaki program derleyerek altrn:

497

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
#define ISIM1
int main()
{
#ifdef ISIM1
printf("bu yazi ekranda cikacak!\n");
#endif
#ifndef ISIM1
printf("bu yazi ekranda cikmayacak!\n");
#endif
return 0;
}

#error nilemci Komutu

#error nilemci komutu koullu derlemede kullanlr.


nilemci program bu komut ile karlatnda derleme ilemini daha nileme
aamasnda sonlandrr. Kullanm aadaki gibidir:
#error yaz
error nilemci komutunun yannda -boluk karakteri ile ayrlm- bir hata iletisi yer alr.
nilemci #error komutunu grnce bu hata iletisini ekrana yazarak derleme ilemine
son verir. Hata yazsnn ekranda nasl gsterilecei derleyiciye gre deiebilir.
#ifndef __STDC__
#error Bu program yalnzca C derleyicisinde derlenir.
#endif
Yukardaki rnekte #ifndef komutu ile, derleme ilemini yapacak derleyicinin standart C
derleyicisi olup olmad snanyor, derleyici eer standart C derleyicisi deil ise derleme
ilemi nilemci aamasnda sonlandrlyor. Derleme ilemi sonlandrldnda ekrana:
Bu program yalnzca C derleyicisinde derlenir.
yazs yazdrlr.
#if UINT_MAX < 65535
#error unsigned int turu yeterli buyuklukte degil
#endif
Yazlan programn int trnn 2 byte dan daha kk olan bir sistem iin derlenmeye
allmas durumunda ekrana
Error directive: unsigned int turu yeterli buyuklukte degil
Biiminde bir yaz yazdrlarak derleme ilemine son verilir.

#undef nilemci Komutu

Bir simgesel deimezin ilki ile zde olmayan bir biimde ikinci kez tanmlanmas
tanmsz davrantr (undefined behaviour).
rnein aadaki gibi bir tanmlama ilemi yanltr:
#define
#define

MAX 100
MAX 200

498

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Bir simgesel deimezin ilki ile zde olarak tanmlanmasnda herhangi bir sorun kmaz.
Bir simgesel deimez ikinci kez tanmlanmak istenirse nce eski tanmlamay ortadan
kaldrmak gerekir. Bu ilem #undef nilemci komutuyla yaplr.
#undef nilemci komutunun yanna geerlilii ortadan kaldrlacak simgesel deimezin
ya da makronun ismi yazlmaldr:
#undef
#define

MAX
MAX

20

Yukardaki nilemci komutlatyla nce MAX simgesel deimezinin tanm ortadan


kaldrlyor, sonra MAX simgesel deimezi 200 olarak tanmlanyor. #undef ile
tanmlanmas kaldrlmak istenen simgesel deimez, daha nce tanmlanm olmasa bile
bu durum bir soruna yol amaz. Yukardaki rnekte, MAX simgesel deimezi daha nce
tanmlanmam olsayd, bu durum bir hataya yol amazd.

nceden Tanmlanm Simgesel Deimezler

Standart C dilinde 5 tane simgesel deimez nceden tanmlanm kabul edilir. Herhangi
bir balk dosyas iinde bu simgesel deimezler #define nilemci komutuyla
tanmlanm olmamasna karn kaynak kodun derleyici tarafndan ele alnmasndan nce
bir yer deitirme ilemine sokulurlar. Bu simgesel deimezler ounlukla hata arama
amacyla yazlan kodlarda kullanlrlar:
__LINE__ ntanml simgesel deimezi
Bu simgesel deimez kaynak kodun kanc satrnda kullanlm ise, o satrn numarasn
gsteren bir tamsay deimezi ile yer deitirilir.
__FILE__ ntanml simgesel deimezi
Bu simgesel deimez hangi kaynak dosya iinde kullanlm ise, o kaynak dosyann
ismini gsteren bir dizge ifadesiyle yer deitirilir.
__DATE__ ntanml simgesel deimezi
Bu simgesel derleme tarihini gsteren bir dizge ifadesiyle yer deitirilir. Tarih bilgisini
ieren yaznn format aadaki gibidir:
Aaa gg yyyy (ay, gn, yl)
__TIME__ ntanml simgesel deimezi
Bu simgesel deimez derleme zamann gsteren bir dizge ifadesiyle yer deitirilir.
Zaman bilgisini ieren yaznn format aadaki gibidir:
sa:dd:ss (saat, dakika, saniye)
__STDC__ ntanml simgesel deimezi
Eer derleyici standart C derleyicisi ise bu simgesel deimez tanml kabul edilir.
Derleyici standart C derleyicisi deil ise bu simgesel deimez tanmlanmam kabul
edilir.
Aadaki program derleyerek altrn:
# include <stdio.h>
int main()
{
printf("kaynak dosya ismi : %s\n", __FILE__);
printf("derleme tarihi = %s\n", __DATE__);
printf("derleme zamani = %s\n", __TIME__);
printf("bu satirin numarasi = %d\n", __LINE__);
#ifdef __STDC__
printf("standart C derleyicisi\n");

499

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#else
printf("standart C derleyicisi degil\n");
#endif
return 0;
}
[C++ derleyiclerinde de __cplusplus ntanml simgesel deimezi, tanmlanm kabul edilir.]

#line nilemci Komutu

Bu nilemci komutuyla derleyicinin kaynak koda ilikin tuttuu satr numaras ve dosya
ismi deitirilebilir. Bu komut iki ayr argman alabilir.
Komutun alabilecei birinci argman bir tamsay olarak satr numarasdr. Komutun
seimlik olarak alabilecei ikinci argman dosya ismini gsteren dizgedir.
Bu nilemci komutu kaynak kod reten programlar tarafndan kullanlabilir.
#line nilemci komutu size anlamsz gelebilir. Neden derleyicinin verecei hata iletisi
rnein 20. satr deil de 25. satr gstersin? Neden derleyici hata iletisinde derledii
kaynak dosyann ismini deil de bir baka dosyann ismini yazdrsn?
#line komutu programclardan ok, kt olarak C kaynak kodu reten programalar
tarafndan kullanlr. Aadaki program derleyerek altrn:
#include <stdio.h>
int main()
{
printf("%s dosyasnn %d. satr\n", __FILE__, __LINE__);
#line
100
"aaaaa.c"
printf("%s dosyasnn %d. satr\n", __FILE__, __LINE__);
}

return 0;

Bir Balk Dosyasnn Birden Fazla Kez Kaynak Dosyaya Eklenmesi

Projeler ounlukla farkl kaynak dosyalardan ve balk dosyalarndan oluur. Hizmet alan
kodlar (client codes) hizmet veren kodlarn (server codes) balk dosyalarn eklerler.
Balk dosyasn eklemenin #include nilemci komutuyla yapldn biliyorsunuz. Bir
kodlama dosyasnda iki ayr balk dosyasnn eklendiini dnelim:
/*** file1.c *****/
#include "header1.h"
#include "header2.h"
Balk dosyalar iinde baka balk dosyalarnn eklenmesine sk rastlanr. rnein
header1 ve header2 isimli balk dosyalarnn her ikisinde de header3.h isimli bir balk
dosyasnn eklendiini dnelim:
/*** header1.h *****/
#include "header3.h"
/*** header2.h *****/
#include "header3.h"
Bu durumda file1.c isimli kaynak dosya iine header3.h isimli balk dosyas iki kez
eklenmi olur. Bu duruma ngilizcede "multiple inclusion" denir. Peki bu durumun bir
sakncas var mdr?
Balk dosyalar iinde bildirimler bulunur. Bir balk dosyas iki kez eklenirse bu balk
dosyas iindeki bildirimler iki kez yaplm olur. Baz bildirimlerin zde olarak
yinelenmesinin bir sakncas yoktur. rnein bir ilev bildirimi daha nceki bir bildirimle
elimemek kaydyla yinelenebilir. Benzer durum extern bildirimleri ve typedef bildirimleri
500

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

iin de geerlidir. Ancak programc tarafndan yaplan bir tr bildiriminin yinelenmesi,


bildirimler zde olsa bile geersizdir:
struct A {
/****/
};
struct A {
/****/
};
Yukardaki rnekte struct A isimli yapnn bildirimi ikinci kez yapldnda derleyici
program bir hata iletisi verir. Bir rnek de standart ktphaneden verelim:
time.h isimli standart balk dosyasnda struct tm isimli bir yapnn bildirildiini
biliyorsunuz. Eer bir kodlama dosyas iine time.h balk dosyasnn ierii iki kez
boaltlrsa, kodlama dosyasnn derlenmesi aamasnda hata oluur. nk struct tm
yaps iki kez bildirilmi olur.
Proje gelitirilmesi sresinde byle hatalarn giderilmesi fazladan zaman kaybna yol
aar. nilemci koullu derleme komutlaryle bu konuda bir nlem alnabilir. C ve C++
dillerinde balk dosyalar ounlukla aadaki biimde hazrlanr:
//header1.h
#ifndef _HEADER1_H_
#define _HEADER1_H_
#endif
Bu balk dosyas bir kaynak dosya tarafndan ilk kez eklendiinde _HEADER1_H_
simgesel deimezi henz tanmlanm olmadndan #endif nilemci komutuna kadar
olan ksm derleyiciye verilir. Ancak daha sonra bu balk dosyas bir kez daha kaynak
koda eklenmek istenirse artk _HEADER1_H simgesel deimezi tanmlanm olduundan
#endif nilemci komutuna kadar olan ksm artk kaynak koda verilmez.

Koullu Derlemeye likin nilemci Komutlar Nerelerde


Kullanlr?

1. Koullu derleme komutlar sklkla debug amacyla kullanlr.


Program yazlrken debug amacyla programa baz kodlar eklenir. Ancak programn son
srmnde hata aramaya ynelik kodlarn bulunmas istenmez. nk bu kodlarn
programn alma zamannda getirecei ek maliyet istenmez.
Program iindeki belirli kod paralAr yalnzca debug srmde derlenir:
#if DEBUG
/***/
#endif
2. Baz programlarn birden fazla iletim sisteminde almas istenebilir. Kaynak kodun
belirli ksmlar nilemci program tarafndan iletim sistemine gre seilerek derleyiciye
verilir:
#if defined(WINDOWS)
/***/
#elif
defined (DOS)
/***/
#elif
defined(OS2)
/***/
#endif

501

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

3. Bazen de ayn program farkl derleyiciler ile derlenir.


#ifdef __STDC__
/***/
#else
/***/
#endif
Koullu derlemeye ilikin nilemci komutlarnn kullanlmasna ilikin bir program paras
rnei aada veriliyor:
#if DLEVEL > 5
#define SIGNAL 1
#if STACKUSE == 1
#define STACK
#else
#define STACK
#endif
#else
#define SIGNAL 0
#if STACKUSE == 0
#define STACK
#else
#define STACK
#endif
#endif
#if DLEVEL == 0
#define STACK
#elif DLEVEL == 1
#define STACK
#elif DLEVEL > 5
display(debugptr);
#else
#define STACK 200
#endif

200
50

200
50

0
100

Yukardaki rnekte birinci #if blounun altnda iki ayr #if #else yaps bulunur. DLEVEL
simgesel deimezinin 5'den byk olup olmamasna gre deerine gre nilemci
tarafndan dor ksm ya da yanl ksm ele alnr.
#elif nilemci komutunun da yer ald ikinci #if blounda ise DLEVEL simgesel
deimezinin deerine gre 4 seenekten biri ele alnr. DLEVEL simgesel deimezinin
deerine bal olarak STACK simgesel deimezi 0, 100 ya da 200 olarak tanmlanr.
DLEVEL simgesel deimezinin deerinin 5'den byk olmas durumunda ise
display(debugptr);
deyimi derleyiciye verilir. Bu durumda STACK simgesel deimezi tanmlanmaz.

502

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

assert Makrosu

assert, program gelitirirken programcnn gelitirme sreci iinde bir takm olas
bcekleri farketmesi iin kullanlan bir makrodur. C'nin standart balk dosyalarndan
assert.h iinde tanmlanmtr. assert makrosu, makroya argman olarak bir ifadenin
verilmesiyle kullanlr. rnein:
assert(p != NULL);
Ayra iindeki ifade, doru olduu ya da doru olmas gerektii dnlen bir durum
belirtir. assert makrosuna verilen ifadenin saysal deeri sfr d bir deerse, yani
snanan nerme doruysa, assert makrosu hibir ey yapmaz. Ancak makro ifadesinin
deeri sfrsa, yani ifadeye konu nerme mantksal olarak yanl ise assert makrosu
standart abort() ilevini ararak program sonlandrr.
abort ilevi tpk standart exit() ilevi gibi arld zaman program sonlandrr. Ancak
exit ilevinin yapt bir takm geri alma ilemlerini abort ilevi yapmaz. abort ilevi
program sonlandrdnda stdout akmna "Abnormal program termination" yazsn
basar. assert makrosu baarsz olduunda abort ilevini armadan nce doruluu
snanan ifadeyi ve assert ileminin hangi dosyada ve satrda olduu bilgisini ekrana
yazar:
#include <stdio.h>
#include <assert.h>
int main()
{
int x, y;
printf("iki sayi giriniz : ");
scanf("%d%d", &x, &y);
assert(y != 0);
printf("%d / %d = %d\n", x, y, x / y);
}

return 0;

Yukardaki program inceleyin. Klavyeden y deikenine girilen deer 0 ise, assert


makrosuna verilen ifade yanl olduundan, program abort ilevinin arlmasyla
sonlandrlr. Program altrarak, program sonlandrldnda ekrana baslan yazy
inceleyin.
assert, assert.h dosyas iinde aadakine benzer biimde tanmlanm bir makrodur.
#ifndef NDEBUG
#define
assert(exp) if(!(exp)){fprintf(stderr,"Assertion failed: %s,file
%s, line %d\n",\
#exp, __FILE__, __LINE__);abort();}
#else
#define assert(exp)
#endif
Bu makro unlar yapar:
Eer programc assert.h dosyasnn ieriinin boaltld yerden daha yukarda olan
kaynak kod alan iinde NDEBUG simgesel deimezini tanmlamamsa btn assert
makrolar yerine kontrol kodlar yerletirilir. Kontrol kodu grld gibi ifadenin saysal
deeri sfr ise abort ilevi ile program sonlandrlr. Eer programc assert.h dosyasnn
eklenmesinden nce NDEBUG simgesel deimezini tanmlam ise grld gibi btn

503

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

assert makrolar kaynak koddan silinir. Btn assert makrolarn kaynak koddan silmek
iin programn kaynak kodun tepesine
#define NDEBUG
komutu yerletirilmelidir.

assert Makrosu Neden Kullanlr?

assert makrosu programn gelitirilme aamasnda olas hatalar yakalamak iin


programc tarafndan kaynak koda eklenen bir makrodur. Programc kodunu yazarken bir
bcek karsnda oluabilecek durumlar iin assert mokrolarn yerletirir. Programn
gelitirilme srecinde denemeler srasnda assert mokrosu tarafndan program
sonlandrlrsa programc olmamas gereken bir durumun olduunu anlar ve bu durumun
bir bcek nedeni ile olutuunu dnr. phesiz bcek tam olarak assert mokrosunun
bulunduu yerde olmayabilir. Baka yerde yaplan hatalar dolays ile bcek olumu
olabilir. Bu durum assert makrosu tarafndan bir ipucu olarak ele geirilir. assert
makrosuna yakalanldnda programc kodunu aka gre incelemeli ve bcein nereden
kaynaklandn saptamaya alr. assert makrosu ile yaplan kontroller aslnda dzgn
alan bir program iin gereksiz olan kontrollerdir. te programn assert makrolarnn
kontrol kodlar yerletirdii (yani NDEBUG simgesel deimezinin tammlanmad)
versiyonuna "hata arama srm" (debug versiyonu) denir. Hata arama srm assert
makrolar ile kaynak kodun imi olduu srmdr. Programc kodunda hibir bcek
olmadndan emin ise program teslim etmeden nce NDEBUG simgesel deimezini
tanmlayarak program son kez derler. Buna programn "srm biimi" (release version)
denir. Byk programlar debug versiyonunda oluturulmal, son aamada release
versiyonu elde edilmelidir.

assert Makrosu Nerelerde Kullanlr?

assert makrolar programn ticari srmlerinde ya da kodda kalmas gereken durumlar


iin kullanlmamaldr. rnein malloc ve fopen ilevlerinin geri dn deerleri programn
hem debug srmnde hem de release srmnde kontrol edilmelidir. assert makrolar
u durumlarda kullanlabilir:
lev parametrelerinin olmamas gereken anormal deerleri almas durumu assert
makrosu ile kontrol edilebilir. zellikle ilev parametresi olan gstericilerin hemen ana
bloun giriinde NULL adresi olma durumu kontrol edilebilir, nk bceklerden dolay
gstericilerin NULL deerine dmesi sk rastlanlan bir durumdur.
rnein sralama ilemi yapan bir ilevin tanm iinde assert makrosu yle kullanlabilir:
void sort_array(int *pArray, size_t size)
{
int i, k, temp;
/**/
assert(pArray != NULL);
/**/
}
Program iinde programn dzenlenme sistemine gre asla olmamas gereken bir durum
oluuyorsa, bir bcekten phelenilmesi gerektii durumlarda assert makrosu
kullanlmaldr.
assert ifadeleri ok uzun tutulmamaldr.
nk bu durumda assert ifadesinin baarszl durumunda neden anlalamayabilir.
rnein:
assert(row1 < 25 && col1 < 80 && row2 < 25 && col2 < 80);
yerine aadaki kodun kullanlmas daha anlamldr:

504

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

assert(row1 < 25 && col1 < 80);


assert(row2 < 25 && col2 < 80);

505

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

LEV GSTERCLER
altrlabilen bir programn diskteki grntsne program denir. Bir program
altrlmak zere bellee yklendiinde, yani alr duruma getirildiinde process ya da
task biiminde isimlendirilir. Yani program diskteki durumu, process ise almakta olan
bir program anlatr.
altrlabilen bir program ierik olarak ksmdan oluur:

altrlabilen bir dosyann iletim sistemi tarafndan altrlabilmesi iin, nce diskten
RAM'e yklenmesi gerekir. letim sisteminin program diskten alp bellee ykleyip
altran ksmna ykleyici (loader) denir. Normal olarak bir programn bellee
yklenmesi iin, programn toplam byklnn bellekteki bo alandan kk olmas
gerekir. Ancak UNIX, Windows gibi sistemlerde programlar kk bir bellek altnda
altrlabilir.
Bu zellie "sanal bellek" (virtual memory) zellii denir. Sanal bellek kullanm ile nce
programn kk bir ksm RAM'e yklenir. letim sistemi, program alrken programn
aknn kod ya da data bakmndan RAM'de olmayan bir ksma getiini anlar. Programn
RAM'deki ksmn boaltarak bu kez gereken ksmn RAM'e ykler. Yani program paral
olarak altrlr. DOS iletim sistemi sanal bellek kullanm yoktur. DOS sisteminin
program altrmaktaki bellek miktar en fazla 640KB kadardr.
C'deki tm statik mrl varlklar, yani global deikenler, statik yerel deikenler,
dizgeler altrlabilir dosyann "veri" (data) blmne yerletirilir. Statik mrl
deikenler bu blme ilkdeerleriyle yerletirilir. Yerel deikenler ile parametre
deikenleri altrlabilir dosyann "yn" (stack) blmnde geici olarak yaratlrlar.
Programn tm ilevleri derlenmi olarak "kod" (code) blmnde bulunur.
Nesnelerin nasl adresleri varsa ilevlerin de adresleri vardr. Bir ilevin adresi, o ilevin
makine kodlarnn bellekteki balang adresidir. levlerin balang adresleri ilev
gstericileri denilen zel gstericilere yerletirilebilir. Bir ilev gstericisine geri dn
deeri ve parametreleri belirtilen trden olan bir ilevin adresi atanabilir.

lev Gstericisi Deikenlerin Tanmlanmas

Bir ilev gstericisi zel bir szdizimi ile tanmlanr:


int (*fp)(void);

Yukardaki deyim ile ismi fp olan bir ilev gsterici deikeni tanmlanyor. fp gsterici
deikeni, geri dn deeri int trden olan, parametre deikeni olmayan bir ilevi
gsterebilir. Bir baka deyile, fp gsterici deikenine geri dn deeri int trden olan,
parametre deikeni olmayan bir ilevin adresi atanabilir.
Tanmlamada '*' atomu ve bunu izleyen gsterici isminin ayra iine alndn
gryorsunuz. Bu ayracn soluna ilev gstericisinin gsterecei ilevin geri dn
deerinin tr yazlr. Ayracn sandaki ayra iinde, ilev gstericisinin gsterecei
ilevin parametre deikenlerinin tr yazlr.
Bir baka rnek:
int (*fptr) (int, int);

507

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yukarda tanmlanan fptr isimli gsterici deikene geri dn deeri int trden olan,
parametreleri (int, int) olan bir ilevin adresi atanabilir.
Tanmlamada gsterici deikenin ismi eer ayra iine alnmazsa, bir ilev gstericisi
tanmlanm olmaz. Bir adres trne geri dnen bir ilev bildirilmi olur:
int *f(int, int);
Yukarda, ismi f olan geri dn deeri (int *) tr olan parametreleri (int, int) olan bir
ilev bildirilmitir.

lev simleri

Bir dizi isminin, bir ileme sokulduunda, otomatik olarak dizinin ilk elemannn adresine
dntrldn biliyorsunuz. Benzer ekilde bir ilev ismi de, bir ileme sokulduunda
derleyici tarafndan otomatik olarak ilgili ilevin adresine dntrlr. lev isimlerine,
yazlmsal olarak ilevlerin adresleri gzyle baklabilir.
Bir ilev ismi adres ilecinin de terimi olabilir. Bu durumda yine ilevin adresi elde edilir.
Yani func bir ilev ismi olmak zere
func
ile
&func
edeer ifadeler olarak dnlebilir. Her iki ifade de func ilevinin adresi olarak
kullanlabilir.

lev ar leci

ilev ar ileci tek terimli sonek konumunda bir iletir. le ncelik tablosunun en st
dzeyindedir. Bu ilein terimi bir ilev adresidir. le, programn akn o adrese
yneltir, yani o adresteki kodu altrr. rnein:
func()
Burada ilev ar ilecinin terimi func adresidir. le, func adresinde bulunan kodu, yani
func ilevini altrr. lev ar ilecinin rettii deer, arlan ilevin geri dn
deeridir. rnein:
a = add(10, 20);
Burada add ifadesinin tr geri dn deeri int parametresi (int, int) olan bir ilev
adresidir. Yani add ifadesinin
int (*)(int, int)
trne dntrlr.
add(10, 20)
gibi bir ilev arsnn oluturduu ifade ise int trdendir.

levlerin lev Gstericileri ile arlmas

Bir ilev gstericisinin gsterdii ilev iki ayr biimde arlabilir. pf bir ilev gstericisi
deiken olmak zere, bu gstericinin gsterdii ilev
pf()

508

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

biiminde, ya da
(*pf)()
biiminde arlabilir.
Birinci biim daha doal grnmekle birlikte, pf isminin bir gsterici deikenin ismi mi,
yoksa bir ilevin ismi mi olduu ok ak deildir.
kinci biimde, *pf ifadesinin ncelik ayrac iine alnmas zorunludur. nk ilev ar
ilecinin ncelik seviyesi, ierik ilecinin ncelik seviyesinden daha yksektir.
Aadaki program derleyerek altrn:
#include <stdio.h>
void func()
{
printf("func()\n");
}
int main()
{
void (*pf)(void) = func;
pf();
(*pf)();
}

return 0;

main ilevi iinde tanmlanan pf isimli ilev gstericisi deikene func isimli ilevin adresi
atanyor. Daha sonra pf'nin gsterdii ilev, yani func ilevi iki ayr biimle arlyor.

lev Gstericileri ve Gsterici Aritmetii

Bir ilev gstericisi gsterici aritmetii kurallarna uymaz. lev adresleri dier adresler
gibi tamsaylarla toplanamaz. lev gstericileri ++ ya da -- ilecinin terimi olamaz.
Zaten gsterici aritmetiinin ilev adresleri iin bir anlam da olamazd. Bir ilev adresine
bir tamsay toplayp bellekte bir sonraki ilevin adresine ulamak nasl mmkn olurdu?
lev adresleri ierik ilecinin terimi olabilir. Byle ifadeler ile, yalnzca ilev ars
yaplabilir. Bu gstericiler karlatrma ilelerinin de terimi olabilir. rnein, iki ilev
gstericisinin ayn ilevi gsterip gstermedii == ya da != ileleriyle karlatrlabilir.

lev Gstericilerinin lev Parametreleri Olarak Kullanlmas

Bir ilevin parametre deikeni ilev gstericisi olabilir. Aadaki rnei inceleyin:
#include <stdio.h>
void func(void (*pf)(void))
{
pf();
}
void f1()
{
printf("f1()\n");
}
void f2()
{
printf("f2()\n");
}

509

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

int main()
{
func(f1);
func(f2);
return 0;
}
Yukardaki programda, func isimli ilevin parametre deikeni bir ilev gstericisidir. func
ilevinin parametre deikeni olan gsterici, geri dn deeri ve parametre deikeni
olmayan bir ilevi gsterebilir. levlerin parametre deikenleri, deerlerini ilev
arlarndaki argmanlardan aldna gre func ilevine argman olarak, geri dn
deeri ve parametre deikeni olmayan bir ilev adresi gnderilmelidir. func ilevi iinde,
ilevin parametresi olan fp isimli gstericinin gsterdii ilev arlr.
f1 ve f2 geri dn deeri ve parametre deikeni olmayan ilevlerdir. main ilevi iinde
func ilevinin nce f1 ilevin adresi ile daha sonra da f2 ilevinin adresi ile arldn
gryorsunuz. Bu durumda
func(f1);
arsyla nce func ilevi arlr. func ilevi iinde de f1 ilevin arlmas salanr.

lev Gstericileri Niin Kullanlr

lev gstericileri, bir ilevin belirli bir ksmnn dardan deitirilmesine olanak salar.
Yani ilev, bir amac gerekletirecek belirli ilemleri yapmak iin, dardan adresini ald
bir ilevi arabilir. Bylece ilevi aran kod paras, ard ilevin iinin belirli bir
ksmnn, kendi istedii gibi yaplmasn salayabilir.
Bylece yazlan kaynak kod miktar da azalabilir. Kaynak kodlarnn byk bir ksm ayn
olan ok sayda ilev yazmak yerine, ilev gstericisiyle arlan tek bir ilev yazmak
mmkn olabilir. lev gstericileri ile arlan ilevler, genelletirilmi ilevlerdir.
Dardan adreslerini aldklar ilevlerin arlmalaryla ilevleri daha zel hale getirilmi
olur.

Trden Bamsz lem Yapan levler

Baz ilevler, zellikle gsterici parametresi alan ilevler, belirli bir tre dayal olarak
alr. rnein, elemanlar int trden olan bir diziyi sralayan bir ilev, elemanlar double
trden olan bir diziyi sralayamaz. Bu tr durumlarda ayn kodu, farkl trlere gre
yeniden yazmak gerekir. Trden bamsz olarak tek bir ilevin yazlabilmesi mmkn
olabilir. Trden bamsz ilem yapan ilevlerin gsterici parametreleri void * trnden
olmaldr. Ancak parametrelerin void * trnden olmas yalnzca ar asndan kolaylk
salar. levi yazacak olan programc, yine de ileve geirilen adresin trn saptamak
zorundadr. Bunun iin ileve bir tr parametresi geirilebilir. rnein herhangi bir trden
diziyi sralayacak ilevin bildirimi aadaki gibi olsun:
void *gsort(void *parray, size_t size, int type);
imdi ilevi yazacak kii type isimli parametreyi bir switch deyiminin ayrac iine alarak,
dardan adresi alnan dizinin trn saptayabilir. Bu yntem C'nin doal trleri iin
alsa da programcnn kendi oluturduu trden diziler iin doru almaz. Byle genel
ilevler ancak ilev gstericileri kullanlarak yazlabilir.
imdi bir dizinin en byk elemann adresiyle geri dnen bir ilevi trden bamsz olarak
yazmaya alalm. Dizi trnden bamsz olarak ilem yapan ilevlerin, genel parametrik
yaps genellikle aadaki gibi olur:
Dizinin balang adresini almak iin, void trden bir gsterici.
Dizinin eleman saysn alan, size_t trnden bir parametre.

510

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Dizinin bir elemann byte uzunluunu yani sizeof deerini alan size_t trnden bir
parametre.
Dizinin elemanlarn karlatrma amacyla kullanlacak bir ilevin balang adresini alan,
ilev gstericisi parametre.
Bir dizinin en byk elemannn adresini bulan genel ilevin parametrik yaps yle
olabilir:
void *get_max(const void *pArray, size_t size, size_t width, int
(*cmp)(const void *, const void *));
Bu tr ilevlerin tasarmndaki genel yaklam udur:
lev herbir dizi elemannn adresini, gsterici aritmetiinden faydalanarak bulabilir.
Ancak dizi elemanlarnn tr bilinmediinden, ilev dizinin elemanlarnn karlatrma
ilemini yapamaz. Bu karlatrmay, ilev gstericisi kullanarak ilevi aran kod
parasna yaptrr. levi aracak programc, karlatrma ilevinin dizinin herhangi iki
elemannn adresiyle arlacan gznne alarak, karlatrma ilevini yle yazar:
Karlatrma ilevi, karlatrlacak iki nesnenin adresini alr. levin birinci
parametresine adresi alnan nesne, ikinci parametreye adresi alnan nesneden daha
bykse, ilev pozitif herhangi bir deere, kkse negatif herhangi bir deere, bu iki
deer eitse sfr deerine geri dner. Bu, standart strcmp ilevinin sunduu anlamadr.
Aadaki program inceleyin:
#include <stdio.h>
#include <string.h>
#define

MAX_NAME_LEN

20

typedef struct tag_Person {


char name[MAX_NAME_LEN];
int no;
}Person;
typedef unsigned char Byte;
void *get_max(const void *parray, size_t size, size_t width, int
(*fp)(const void *, const void *))
{
Byte *pb = (Byte *)parray;
void *pmax = (void *)parray;
size_t k;

for (k = 1; k < size; k++)


if (fp(pb + k * width, pmax) > 0)
pmax = pb + k * width;
return pmax;

int cmp_int(const void *vp1, const void *vp2)


{
return *(const int *)vp1 - *(const int *)vp2;
}
int cmp_person_name(const void *vp1, const void *vp2)
{
return strcmp(((const Person *)vp1)->name, ((const Person *)vp2)>name);
}

511

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

int cmp_person_no(const void *vp1, const void *vp2)


{
return ((const Person *)vp1)->no - ((const Person *)vp2)->no;
}
int main()
{
int a[10] = {3, 8, 4, 7, 6, 9, 12, 1, 9, 10};
Person per[10] = { {"Ali Serce", 123}, {"Kaan Aslan", 563}, {"Ahmet
Adlori", 312},{"Necati Ergin", 197}, {"Guray Sonmez", 297}, {"Erdem
Eker", 144}, {"Nuri Yilmaz", 765}, {"Tayfun Tan", 117}, {"Demir Kerim",
222},{"Can Mercan", 12}};
Person *p_person;
int *iptr;
iptr = (int *)get_max(a, 10, sizeof(int), cmp_int);
printf("int dizinin en buyuk elemani %d\n", *iptr);
p_person = (Person *) get_max(per, 10,
cmp_person_name);
printf("per dizisinin en buyuk elemani
p_person->name, p_person->no);
p_person = (Person *) get_max(per, 10,
printf("per dizisinin en buyuk elemani
p_person->name,
p_person->no);

sizeof(Person),
(isme gore) %s %d\n",
sizeof(Person), cmp_person_no);
(numaraya gore) %s %d\n",

return 0;
}
Yukardaki programda get_max isimli ilev bir dizinin balang adresini, boyutunu,
dizinin bir elemannn uzunluu ile dizinin elemanlarn karlatrma ileminde
kullanlacak ilevin adresini alyor. lev arsyla dizi adresi void trden bir gstericiye
alnyor. Ancak ilev iinde gsterici aritmetiinden faydalanmak amacyla bu adres char
trden bir gstericiye aktarlyor. Bir elemann boyutu bilindiine gre bu deer dizinin
balang adresine eklenerek dizinin bir sonraki elemannn adresi bulunabilir deil mi?
Karlatrma ilevi, karlatrma ilemini yapabilmek iin iki nesnenin adresini alyor.
Bylece get_max ilevi iinde, karlatrma ilevi, parametre olan ilev gstericisi ile
doru argmanlarla arlabiliyor. Dizinin en byk elemannn adresini bulmak iin yine
bilinen algoritma kullanlyor. Ancak dizinin iki elemannn deerini karlatrmak iin
dardan adresi alnan ilev arlyor.
Daha sonra ayr karlatrma ilevinin tanmlanm olduunu gryorsunuz. Tm
karlatrma ilevlerinin parametre deikenleri (const void *, const void *) dr. Bylece,
bu karlatrma ilevlerine get_max ilevi iki adres gnderdiinde bir tr uyumsuzluu
sorunu ortaya kmaz.
main ilevi iinde bir int trden bir de Person trnden dizi tanmlanyor. Bu dizilere
ilkdeer verilmi olduunu gryorsunuz. Daha sonra get_max ilevi arlarak dizilerin
en byk elemanlarnn adresleri bulunuyor. cmp_person_name ilevi Person trnden iki
nesneyi isimlerine gre karlatrrken, cmp_person_no ilevi ise Person trnden iki
nesneyi, numaralarna gre karlatryor.

Trden Bamsz Sralama

Her trl sralama algoritmasnda karlatrma ve deer takas etme sz konusudur. Bir
dizinin tr bilinmese bile dizinin iki eleman takas edilebilir. Karlatrma ileminini
yapacak ilevin adresi aran kod parasndan alnrsa, trden bamsz sralama ilemi
gerekletirilebilir. Aadaki rnei inceleyin:

512

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

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

SIZE

10

typedef unsigned char BYTE;


void gswap(void *vp1, void *vp2, size_t nbytes)
{
unsigned char *p1 = (unsigned char *)vp1;
unsigned char *p2 = (unsigned char *)vp2;
unsigned char temp;

while (nbytes--) {
temp = *p1;
*p1++ = *p2;
*p2++ = temp;
}

void bsort(void *vparray, size_t nelem, size_t width, int (*compare)(const


void *, const void *))
{
size_t i, j;
BYTE *base = (BYTE *)vparray;

for (i = 0; i < nelem - 1; i++)


for (j = 0; j < nelem - 1 - i; j++)
if (compare(base + j * width, base + (j + 1) * width) > 0)
gswap(base + j * width, base + (j + 1) * width, width);

int cmp_int(const void *vp1, const void *vp2)


{
return *(const int *)vp1 - *(const int *)vp2;
}
int cmp_double(const void *vp1, const void *vp2)
{
const double *dp1 = (const double *) vp1;
const double *dp2 = (const double *) vp2;
if (*dp1 < *dp2)
return -1;
return *dp1 > *dp2;
}
int main()
{
int k;
double ad[SIZE] = {4.3, 7.4, 2.7, 8.88, 66.99, 4.8, 90.67, 23.87, 7.89,
10.87};
int ai[SIZE] = {12, 4, 56, 45, 23, 60, 17, 56, 29, 1};
bsort(ad, SIZE, sizeof(double), cmp_double);
bsort(ai, SIZE, sizeof(int), cmp_int);
for (k = 0; k < SIZE; ++k)
printf("%.2lf ", ad[k]);

513

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

printf("\n");
for (k = 0; k < SIZE; ++k)
printf("%d ", ai[k]);
}

return 0;

g_swap isimli ilev, balang adreslerini ald belirli uzunlukta iki bellek blounun
ieriini takas ediyor. Bu ilev, trden bamsz sralama ilemini gerekletiren bsort
isimli ilev tarafndan arlyor. bsort ilevinin parametrik yapsnn, daha nce yazlan
get_max isimli ileve benzer olduunu gryorsunuz. levin birinci parametresi
sralanacak dizinin adresi, ikinci parametresi dizinin eleman says, nc parametresi
dizinin bir elemannn uzunluu ve drdnc parametresi ise dizinin elemanlarn
karlatrma ilemini gerekletirecek ilevin adresidir.
bsort ilevi iinde "kabarck sralamas" algoritmas kullanlyor. Dizinin ardk iki
elemannn byklk-kklk iliikisi dardan adresi alnan ilevin, parametre deikeni
olan gsterici ile arlmasyla elde ediliyor. Eer dizinin bu iki eleman doru yerde
deilse bu elemanlar daha nce tanmlanan gswap ilevinin arlmasyla takas ediliyor.
Byle bir ilevle her trden dizi sraya sokulabilir. bsort ilevi yalnzca karlatrma
ilemini gerekletirecek uygun bir ilevin adresine gereksinim duyar. nk bu ilev
dardan adresi gelen dizinin elemanlarnn trn bilemez.
lev gstericileri tanmlarken parametre ayracnn iinin bo braklmas ile parametre
ayracnn ierisine void yazlmas farkl anlamlardadr. Parametre ayracnn ii bo
braklrsa, byle tanmlanan ilev gstericisi deikenlere, geri dn deeri uygun
herhangi bir parametre yapsna sahip olan ilevin adresi yerletirilebilir. Oysa void
yazlmas, parametresi olmayan ilevlerin adreslerinin yerletirilebilecei anlamna gelir.
Parametre ayracnn ii bo braklarak, arlacak ilevlerin parametrik yaps dardan
istendii gibi dzenlenebilir.
[C++ dilinde parametre ayracnn iinin bo braklmas, ilev gstericisi deikenin, gsterecei ilevin parametreye sahip
olmad bilgisini iletir. C++'da ayracn iine void yazlmasyla, burann bo braklmas arasnda bir anlam fark yoktur.]

Standart qsort levi

Standart qsort ilevi, yukarda tanmlanan bsort ileviyle ayn parametrik yapya sahiptir.
Yazdmz bsort ilevi kabarck sralamas algoritmasn kullanyordu. Standart qsort ilevi
ise "quick sort " algoritmasn kullanr.
qsort ilevinin stdlib.h balk dosyas iindeki bildirimi aadaki gibidir:
void qsort(void *vp, size_t size, size_t width, int (*cmp)(const void *,
const void *));
levin birinci parametresi sraya dizilecek dizinin balang adresi, ikinci parametresi
dizinin eleman says, nc parametresi dizinin bir elemann uzunluu ve son
parametresi de karlatrma ilevinin adresidir. Karlatrma ilevi, birinci parametresine
adresi gnderilen elemann deeri, ikinci parametresine adresi gnderilen elemandan
bykse pozitif herhangi bir deere, kkse negatif herhangi bir deere, eitse sfra
geri dnecek biimde yazlrsa kkten bye sraya dizme, ters yazlrsa bykten
ke sraya dizme gerekleir.
Standartlar ncesi C derleyicilerinde qsort ilevinin bildiriminde karlatrma ilevinin
adresini alacak gstericinin parametre ayracnn ii bo braklmtr. Bu durum
karlatrma ilevini yazmay kolaylatrr. stenirse qsort levinda byle bir kolaylk elde
etmek iin stdlib.h balk dosyas iinde bulunan bildirimde ilev gsterici ayrac
boaltlabilir:
void qsort(void *parray, size_t size, size_t width, void(*fp)());

514

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

qsort ilevi ile bir gsterici dizisinin sralanmasna dikkat edilmelidir.


Aadaki program inceleyin ve sralama ileminin neden yaplamadn anlamaya
alnz:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define

SIZE 20

int cmp(const void *vp1, const void *vp2)


{
const char *p1 = (const char *)vp1;
const char *p2 = (const char *)vp2;
return strcmp(p1, p2);
}
int main()
{
char *names[SIZE] = {"Ali", "Veli", "Hasan", "Necati", "Burcu", "Kaan",
"Selami", "Salah", "Nejla", "Huseyin", "Derya", "Funda", "Kemal",
"Burak", "Ozlem", "Deniz", "Nuri","Metin", "Guray", "Anil"};
int k;
qsort(names, SIZE, sizeof(char *), cmp);
for (k = 0; k < SIZE; ++k)
printf("%s ", names[k]);
}

return 0;

Hatay grebildiniz mi? Karlatrma ilemini gerekletirecek cmp isimli ilev yanl
yazlm. Bu ileve char * trnden iki nesnenin adresi gnderileceine gre, ilev iinde
yaplan tr dntrme ileminde, hedef tr char* tr deil char** tr olmalyd. (char
*) trnden bir nesnenin adresi olan bilgi (char **) trndendir.
lev aadaki gibi yazlmalyd:
int cmp(const void *vp1, const void *vp2)
{
const char * const *p1 = (const char * const *)vp1;
const char * const *p2 = (const char * const *)vp2;
}

return strcmp(*p1, *p2);

lev Gstericisi Dizileri

Elemanlar ilev gstericileri olan diziler de tanmlanabilir:


void (*fparray[10])(void);
Yukardaki tanmlama ile fparray, her bir eleman, geri dn deeri ve parametre
deikeni olmayan bir ilevi gsteren 10 elemanl bir dizidir.
fparray[2]
ifadesiyle bu dizinin nc elemanna ulalr ki bu ifadenin tr

515

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

void(*)(void)
trdr. Bu gstericinin gsterdii ilev
fparray[2]();
biiminde ya da
(*fparray[2])() ;
biiminde arlabilir. Byle bir dizinin elemanlarna da ilkdeer verilebilir:
void (*fparray[5])(void) = {f1, f2, f3, f4, f5};
Bylece, dizinin her bir elemannn bir ilevi gstermesi salanabilir.
Artk bir dng deyimi yardmyla gsterici dizisinin elemanlarna ulalarak dizinin
elemanlarnn gsterdii ilevler arlabilir. Aadaki kodu derleyerek altrn:
#include <stdio.h>
void
void
void
void
void

f1()
f2()
f3()
f4()
f5()

{printf("f1()\n");}
{printf("f2()\n");}
{printf("f3()\n");}
{printf("f4()\n");}
{printf("f5()\n");}

int main()
{
void (*fparray[5])(void) = {f1, f2, f3, f4, f5};
int k;
for (k = 0; k < 5; ++k)
fparray[k]();
}

return 0;

Bir levin Bir lev Adresini Geri Dndrmesi

Bir ilevin geri dn deeri de bir ilev adresi olabilir. Aadaki rnei inceleyin:
#include <stdio.h>
void foo()
{
printf("foo()\n");
}
void (*func(void))(void)
{
void (*fp)(void) = foo;
}

return fp;

int main()
{
func()();
return 0;
}

516

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Yukardaki programda tanmlanan func isimli ilevin parametre deikeni yok. func
ilevinin geri dn deeri, -geri dn deeri ve parametre deikeni olmayan- bir ilev
adresidir. Yani func ilevi, kendisini aran kod parasna byle bir ilevin adresini
iletiyor. func ilevi iinde tanmlanan yerel fp gsterici deikeni, foo isimli ilevi
gsteriyor. main ilevi iinde yer alan
func()();
deyiminde nce func ilevi arlr. Bu ardan elde edilen geri dn deeri, foo ilevinin
adresi olur. kinci ilev ar ileci de foo ilevin arlmasn salar.

levler in Yaplan typedef Bildirimleri

Bir ilev tr iin typedef bildirimi yaplabilir:


typedef double FuncDouble(int);

Yukardaki bildirimden sonra FuncDouble, geri dn deeri double trden olan, tek
parametresi int trden olan bir ilev trdr.
FuncDouble *fptr, *fpa[10];
Yukardaki tanmlama ile fptr, geri dn deeri double ve parametresi int trden olan bir
ilevi gsteren gsterici deikendir. fpa ise fptr gibi gstericilerin oluturduu 10
elemanl bir dizidir. fpa dizisinin herbir eleman bir ilev gstericisidir.
Elemanlar FuncDouble trden olan bir deiken tanmlanamaz. C
FuncDouble func;

/* Geersiz */

Ancak bu trden bir ilevin bildiriminde bir sorun yoktur:


extern FuncDouble func;
Yukardaki deyimle, geri dn deeri double trden olan, parametre deikeni int
trden olan bir ilev bildiriliyor.
Uygulamalarda daha ok bir ilev adresi tr iin typedef bildirimi yaplr:
typedef int (*CmpFunc)(const void *, const void *);
Yukardaki bildirimden sonra CmpFunc, geri dn deeri int trden olan, iki parametresi
de const void * trnden olan bir ilev adresi trdr:
CmpFunc fcmp1, fcmp2, fcmpa[10];
Yukardaki tanmlama ile fcmp1 ve fcmp2, geri dn deeri int trden olan, iki
parametresi de const void * trnden olan bir ilevi gsterecek deikenlerdir. fcmp1 ve
fcmp2 ilev gstericisi deikenlerdir. fcmpa ise, her bir eleman fcmp deikeninin
trnden olan, 10 elemanl bir dizidir.
Bir ilev adresi trnn, bir ilevin parametre deikeninin tr ya da ilevin geri dn
deerinin tr olmas bildirimleri olduka kark hale getirir. Okuma ve yazma kolayl
asndan ilev adreslerine ilikin trlere typedef bildirimleriyle yeni isimler verilir.
Aadaki rnei inceleyin:

517

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
#include <string.h>
typedef char *(*FPTR)(const char *, int);
FPTR func(FPTR ptr)
{
return ptr;
}
int main()
{
char str[] = "Necati Ergin";
puts(func(strchr)(str, 'E'));
return 0;
}
Yukardaki programn altrlmasyla ekrana Ergin yazs yazdrlr.

518

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

ZYNELEMEL LEVLER
Bir ilev baka bir ilevi ard gibi kendisini de arabilir. Bu tr ilevlere zyinelemeli
ilev (recursive functions) denir. Algoritmalar bu zellie gre ayr gruba ayrlabilir:
123-

zyinelemeli olmayan ilevlerle yazlabilen algoritmalar.


Hem zyinelemeli olmayan hem de zyinelemeli ilevlerle yazlabilen algoritmalar.
Yalnzca zyinelemeli ilevlerle yazlan algoritmalar.

zyinelemeli ilevlerle yazlmas gereken tipik algoritmalar unlardr:


Dizin aacn dolaan algoritmalar
Parsing algoritmalar
Aa algoritmalar
zel amal pek ok algoritma
Bir algoritmann kendi kendisini aran ilevlerle yazlp yazlamayacann lt nedir?
Algoritmada ilerlendiinde yine ilk batakine benzer bir durumla karlalyorsa byk
olaslkla bu algoritma kendi kendini aran bir ilevle yazlabilir.
Bir ilev kendini ardnda ilevin btn yerel deikenleri yeniden yaratlr. Ayn
durum ilevin parametre deikeni iin de sz konusudur. Bu yzden zyinelemeli ilevler
genellikle yn alann dier ilevlerle karlatrldnda daha ok kullanr.
zyinelemeli ilevler ilemi gerekletirmek amacyla bir sre kendi kendini arr. Daha
sonra ilevlerden k ilemleri balar, yani arlan tm ilevlerden geri klmaya
balanr.

zyinelemeli levlere Tipik rnekler

Aada faktriyel hesaplayan dngsel (iterative) bir ilev yazlyor:


int fact(int n)
{
int result = 1;
while (n)
result *= n--;
return result;

Ayn ilev zyinelemeli olarak da yazlabilir:


int fact(int n)
{
if (n == 0 || n == 1)
return 1;
return n * factorial(n - 1);
}

levin ak yledir:
n
n
n
n
n

=
=
=
=
=

5
4
3
2
1

iin
iin
iin
iin
iin

val = 5 *
val = 4 *
val = 3 *
val = 2 *
return 1;

factorial(4);
factorial(3);
factorial(2);
factorial(1);

519

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Dngsel yapyla yazlan faktriyel ilevinin daha verimli olduu sylenebilir.


Aada bir tamsayy ikilik say sisteminde yazdran dngsel yapl bir ilev tanmlanyor:
#include <stdio.h>
void bitprint(int i)
{
int k;

for (k = sizeof(int) * 8 - 1; k >= 0; --k)


putchar((i >> k & 1) + '0');

lev zyinelemeli olarak aadaki biimde tanmlanabilir:


#include <stdio.h>
void bitprint(int i)
{
if (i == 0)
return;
bitprint(i >> 1);
putchar(i & 1 + '0');
}
Yine zyinelemeli olmayan biimin daha verimli olduu sylenebilir.
Aada bir yazy tersten yazdran dngsel yapl bir ilev tanmlanyor:
#include <stdio.h>
void putsrev(const char *str)
{
int i;
for (i = strlen(str) - 1; i >= 0; --i)
putchar(str[i]);
}

putchar('\n');

lev zyinelemeli olarak aadaki biimde tanmlanabilir:


#include <stdio.h>
void putsrev(const char *str)
{
if (*str == '\0')
return;
putsrev(str + 1);
putchar(*str);
}
Aada tanm verilen ters_yaz isimli ilev klavyeden girilen bir yazy tersten yazdryor:
#include <stdio.h>
void ters_yaz()
{
char ch;

520

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

if ((ch = getchar())!='\n')
ters_yaz();
putchar(ch);

Aada bir tamsayy yalnzca puthar ilevini kullanarak yazdran dngsel yapl bir ilev
tanmlanyor:
#include <stdio.h>
#define

SIZE

100

void printd(int i)
{
char s[SIZE];
int k = 0;
int fnegative = 0;
if (i < 0) {
fnegative = 1;
i = -i;
}
do {
s[k++] = i % 10 + '0';
i /= 10;
} while(i);
if(fnegative)
s[k++] = '-';
for (k--; k >= 0; --k)
putchar(s[k]);
}
lev zyinelemeli olarak aadaki biimde tanmlanabilir:
#include <stdio.h>
void print(int n)
{
if (n < 0) {
putchar('-');
n = -n;
}
if (n / 10)
print(n / 10);
putchar(n % 10 + '0');
}
Aada bir tamsaynn belirli bir tamsay ssne geri donen power isimli ilev
zyinelemeli olarak yazlyor:
int power(int base, int exp)
{
if (exp == 0 )
return 1;
}

return base * power(base, exp - 1);

521

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Aada iki tamsaynn ortak blenlerinden en byne geri dnen get_gcd isimli ilev
zyinelemeli olarak tanmlanyor:
int get_gcd(int a, int b)
{
if (a >= b && a % b == 0)
return b;
if (a < b)
return(get_gcd(b, a));
return get_gcd(b, a % b);
}
Aada tanmlanan fibonacci isimli ilev fibonacci serisinin n. terimine geri dnyor:
int fibonacci(int n)
{
if (n == 1 || n == 2)
return 1;
return fibonacci(n - 1) + fibonacci(n - 2);
}
Ayn ii yapan dngsel yapda bir ilev ok daha verimli olurdu:
int fibonacci(int n)
{
int x = 1;
int y = 1;
int k, result;

for (k = 2; k < n; ++ k) {
result = x + y;
x = y;
y = result;
}
return y;

Aada zyinelemeli olarak tanmlanan rakam_yaz ilevi bir tamsaynn her bir
basaman ekrana yaz olarak basyor:
#include <stdio.h>
void rakam_yaz(int n)
{
static const char *rakamlar[ ] = { "Sifir", "Bir", "Iki", "Uc", "Dort",
"Bes", "Alti", "Yedi", "Sekiz", "Dokuz" };

if (n > 9)
rakam_yaz(n / 10);
printf("%s ", rakamlar[n % 10]);

Aada bir tamsayy ekrana onaltlk say sisteminde yazdran to_hex isimli zyinelemeli
bir ilev tanmlanyor:
void to_hex(int n)

522

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

static const char *htab[ ] = { "0", "1", "2", "3", "4", "5", "6", "7",
"8", "9", "A", "B", "C", "D", "E", "F" };
if (n > 15)
to_hex(n / 16);
printf("%s", htab[n % 16]);
}
Aada bir yazy ters eviren strrev_r isimli bir ilev tanmlanyor.
#include <stdio.h>
#include <stdlib.h>
#define SIZE

100

void swapstr(char *str, int l, int r)


{
char temp;
if (l >= r)
return;
temp = str[l];
str[l] = str[r];
str[r] = temp;
}

swapstr(str, l + 1, r - 1);

char *strrev_r(char *str)


{
swapstr(str, 0, strlen(str) - 1);
}

return str;

int main()
{
char str[SIZE];
printf("bir yazi girin : ");
gets(str);
printf("yazi = (%s)\n", str);
strrev_r(str);
printf("yazi = (%s)\n", str);
}

return 0;

phesiz yaznn ters evrilmesi zyinelemesiz bir ilevle de gerekletirilebilir.


zyinelemeli yazlan strrev_r ilevinin parametresi olduunu gryorsunuz: Yaznn
balang adresi, takas edilecek ilk ve son elemann indis deerleri.
levin strrev ilevinde olduu gibi yaznn yalnzca balang adresini almas bir sarma
ilev yazlarak salanyor. Sarma ilev (wrapper function) iin kendisini yapan ilev
deildir. Sarma ilev ii yapan ilevi aran kk ilevlere denir.
Aadaki programda tanmlanan revprint isimli ilev adresini ald bir yaznn
szcklerini ters srayla ekrana yazdryor:

523

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

#include <stdio.h>
#include <string.h>
#define MAX_WORD_LEN 100
#define ARRAY_SIZE 1000
void revprint(const char *str)
{
char s[MAX_WORD_LEN + 1] = "";
int index = 0;
static const char seps[] = " \n\t,.:;!?";
while (*str && strchr(seps, *str))
str++;
if (!*str)
return;
while (!strchr(seps, *str))
s[index++] = *str++;
s[index] = '\0';
if (*str == '\0') {
printf("%s ", s);
return;
}
revprint(str);
printf("%s ", s);
}
int main()
{
char str[ARRAY_SIZE];
printf("bir cumle girin : ");
gets(str);

revprint(str);
return 0;

524

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

DEKEN SAYIDA ARGMAN ALAN


LEVLER
Cde deiken sayda argman alan ilevler tanmlanabilir. Deiken sayda argman alan
bir ilevin bildirimi aadaki gibidir:
[levin geri dn deeri]ilev ismi(parametre bildirimleri, ...);
nokta "..." atomunun ismi ingilizce de "elipsis"tir. Bir ilevin deiken sayda argman
alabilmesi iin son parametresinin nokta atomuyla bildirilmesi zorunludur. Byle
ilevler istenen sayda argmanla arlabilir.
Byle ilevlerin soldan en az bir paramteresi bilinen bir trden olmaldr.
Aada baz deiken sayda argman alan ilevlerin bildirimleri grlyor:
int printf(const char *, ...);
int scanf(const char *, ...);
double get_mean(int, ...);
levlerin tanm da ayn biimde yaplmaldr. lev tanmlarnda ileve gnderilen
argmanlara baz standart makrolar kullanlarak ulalr. Bu makrolar stdarg.h isimli
standart balk dosyas iinde tanmlanmtr.
Deiken sayda argman alan ilev iinde, tr ve ismi belirtilmi parametre
deikenlerinin deerine dier ilevlerde olduu gibi isimleriyle ulalr. Seimlik olan
argmanlara, yani ka tane olduu bilinmeyen argmanlarn her birine ulam baz
standart makrolar kullanlmasyla gerekletirilir:
nce bu makrolar tanyalm:
va_start Makrosu
Bu makro kullanlarak vs_list trnden bir deikene ilkdeeri verilir.
va_list standart <stdarg.h> balk dosyas iinde bildirilen bir typedef ismidir. Seenee
bal argmanlar dolaacak gsterici bu trdendir. nce bu trden bir deiken
tanmlanmaldr. Bu gstericinin argman listesini dolama ilemini yapabilmesi iin, nce
bu deikene va_start makrosu ile ilkdeeri verilmelidir.
va_start makrosunun aadaki gibi bir ileve karlk geldiini dnebilirsiniz:
void va_start (va_list ap, belirli son parametre);
Bu makroya birinci argman olarak va_list trnden deiken gnderilir. Makroya
gnderilmesi gereken ikinci argman ilevin tr ve ismi belirli olan son parametre
deikeninin deeridir.
#include <stdarg.h>
int add_all(int val, )
{
va_list va;
va_start(va, val);
/***/
}
add_all isimli ilev kendisine gnderilen deiken sayda pozitif tamsaylarn toplam
deeriyle geri dnecek. levin ilk parametresinin int trden olduunu gryorsunuz. Bu
ileve en az bir argman gnderilmelidir. lev arsnda kullanlacak toplam argman
says istee bal olarak ayarlanabilir. Ancak son argmann deeri -1 olduunda, baka

525

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

bir argman gderilmedii anlalrt. Yani ileve gnderilen son deerin -1 olmas
gerektii ilevin arayznn bir paras oluyor.
lev tanm iinde nce va_list trnden va isimli bir deikenin tanmlandn
gryorsunuz. va_start makrosuna va deikeni ve ilevin parametre deikeni val
argman olarak gnderiliyor. Bu arya karlk gelen isel kodun almasyla, va
deikeni argman listesinde uygun argman gsterecek ekilde konumlandrldn
dnebilirsiniz. Bylece artk ileve gnderilen argmanlarn deeri elde edilebilir.

va_arg Makrosu

va_arg makrosu ileve gnderilen argmanlarn deerlerini elde etmek iin kullanlr.
Bu makro bir ilev gibi dnldnde aadaki gibi gsterilebilir:
tr va_arg (va_list ap, tr);
va_list trnden deikenimiz va_start makrosu ile ilkdeerini aldktan sonra bu makro
senee bal tm argmanlar elde etmek iin arlr. Bu makrodan elde edilen
seenee bal argmann deeridir. Makronun almas sonucu argman listesi
gstericisi de bir sonraki argman gsterecek biimde konumlandrlm olur.
Bu makroya yaplan bir sonraki ar ile bir sonraki seimlik argmann deeri elde edilir.
Makroya gnderilecek ikinci bilgi, deeri elde edilecek argmann trdr. rnein
seimlik argman int trdense makronun ikinci argmanna
int
geilmelidir. Yeniden add_all ilevine dnyoruz:
int add_all(int val, ...)
{
va_list va_p;
int sum = 0;
va_start(va_p, val);
while (val != -1) {
sum += val;
val = va_arg(va_p, int);
}
/***/
}
ilevin tanmnda val deikeni -1 olmad srece dnen bir dng oluturuluyor.
Dngnn her turunda val deikeninin deeri sum deikenine katlyor ve val
deikenine seimlik argmanlardan bir sonrakinin deeri aktarlyor.
val = va_arg(va_p, int);
va_arg makrosunun ilk defa kullanlmasyla seimlik ilk argman, 2. kez kullanlmasyla
seimlik 2. argman vs. elde edilir. Eer belirli bir argmandan sonras elde edilmek
istenmiyorsa va_arg arlar sonuna kadar yaplmak zorunda deildir.
leve ar ile gnderilen argman saysndan daha fazla sayda argman elde etmeye
allrsa, yani va_arg makrosu olmas gerekeneden daha fazla arlmaya allrsa p
deerler elde edilir.

va_end Makrosu

Argman listesi gstericisinin ii bittiinde va_end makrosu arlr.


void va_end (va_list ap)

526

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Bu makro va_list trnden deikenle ilgili son ilemleri yapar.


int add_all(int val, ...)
{
va_list va_p;
int sum = 0;
va_start(va_p, val);

while (val != -1) {


sum += val;
val = va_arg(va_p, int);
}
va_end(va_p);
return sum;

Sistemlerin ounda va_end makrosu karlnda bir ey yaplmaz. Yani uygulamalarda


bu makro arlmasa da yaplan ilemde deiiklik olmaz.
Bu durum GNU derleyicisinde her zaman dorudur.
Yine de okunabilirlik, gvenlik ve tanabilirlik alarndan bu makronun arlmas doru
tekniktir.
stenirse birden fazla argman listesi gstericisi kullanlabilir. Bu durumda argman
gstericilerinin her birine va_start makrosu ile ayr ayr ilkdeerleri verilmelidir.
Gstericilerden herhangi biri ile ileve gnderilen argmanlar elde edilebilir.

Deiken Sayda Argman Alan levlere Yaplan arlar

Deiken sayda argman alan ilevlere yaplan arlar derleyici tarafndan zel biimde
deerlendirilir. int alt trlerden olan argmanlar otomatik olarak int trne ykseltilir.
float trnden olan argmanlar double trne ykseltilir:
#include <stdio.h>
int add_all(int val, ...);
int main()
{
short sh = 5;
printf("toplam1 = %d\n", add_all(23, 12, 30, 14, -1));
printf("toplam2 = %d\n", add_all('A', 10, sh, 20, 30, 40, -1));
return 0;
}
imdi kendisine adresleri gnderilen yazlar birletirecek ve deiken sayda argmanla
arlabilecek bir ilev tanmlanyor:
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#define

BUFFER_SIZE

1000

char *con_strings(const char *ptr, ...)


{
va_list ap;

527

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

char *pd;
int k;
char buffer[BUFFER_SIZE] = {'\0'};
va_start (ap, ptr);
while (ptr){
strcat(buffer, ptr);
ptr = va_arg(ap, const char *);
}
pd = (char *)malloc(strlen(buffer) + 1);
if (pd == NULL) {
printf("bellek yetersiz!\n");
exit(EXIT_FAILURE);
}
va_end(ap);
return strcpy(pd, buffer);
}
int main ()
{
char *pstr = con_strings("C ", "ve ", "Sistem ", "Programcilari ",
"Dernegi", NULL);
puts(pstr);
free(pstr);
}

return 0;

con_strings ilevinin tanmn inceleyin:


va_list trnden ap deikeni va_start makrosuyla ilkdeerini alyor.
va_start (ap, ptr);
Parametre deikeni olan ptr nin deeri NULL adresi olmad srece dnen bir while
dngs oluturulduunu gryorsunuz. Dngnn her turunda ileve gnderilen
argmanlardan her birinin deeri va_arg makrosuyla elde ediliyor ve bu deer ptr
gstericisine atanyor. ptr gstericisinin gsterdii yaz nce yerel buffer isimli dizideki
yaznn sonuna standart strcat ileviyle ekleniyor. leve ar ile gnderilen son
argmann NULL adresi olmas gerekiyor. ptr gstericisinin deeri NULL adresi olduunda
buffer dizisindeki yaz dinamik bir bellek blouna kopyalanyor. lev iinde va_end
makrosu arldktan sonra ilev dinamik bloun adresiyle geri dnyor.

528

C ve Sistem Programclar Dernei - C Ders Notlar - Necati Ergin

Kaynaklar
1.American National Standard for Programming Languages - C
ANSI/ISO 9989-1990
2. C - A Reference Manual.
Samuel P. Harbison III - Guy L. Steele Jr.
Prentice-Hall, Inc 2002
ISBN 0-13-089592x
3. The Standard C Library
P. J. Plaguer
Prentice Hall P T R
ISBN 0-13-131509-9
4. C Programming FAQ's
Steve Summit
Addison Wesley

529

You might also like