Professional Documents
Culture Documents
1 . BLM : PROGRAMLAMA VE C
Yazlm Nedir
Yazlm (software) programlama ve programlamayla ilgili konularn geneline verilen isimdir.
Yazlm denince ilk olarak aklmza programlama dilleri, bu diller kullanlarak yazlm kaynak
programlar ve eitli amalar iin oluturulmu dosyalar gelir.
Donanm Nedir
Donanm (hardware) : Bilgisayarn elektronik ksm, yapsna verilen isimdir.
Yazlmn Snflandrlmas
Yazlm uygulama alanlarna gre 5 gruba ayrabiliriz :
1. Bilimsel ve mhendislik yazlmlar (scientific & engineering software).
Bilimsel ve mhendislik konularndaki problemlerin zlmesinde kullanlan programlardr.
Bu tr programlarda veri miktar greli olarak dktr ancak matematiksel ve istatistiksel
algoritmalar youn olarak kullanlabilir.Tamamen hesaplama arlkl ilemler ierir. Bu tr
programlar arlkl olarak bilgisayarn Merkezi lem Birimini (CPU) kullanrlar. Elektronik
devrelerin zmn yapan programlar, istatistik analiz paketlerini bu tr programlara
rnek olarak verebiliriz.
2. Mesleki yazlmlar (Business software).
Veri taban arlkl yazlmlardr. Genel olarak verilerin yaratlmas, ilenmesi ve dosyalarda
saklanmas ile ilgilidir. Bu tr programlara rnek olarak stok kontrol programlar, mteri
takip programlar, muhasebe programlarn verebiliriz.
3. Yapay zeka yazlmlar (artificial intelligence software).
nsan davranlarn taklit etmeyi amalayan 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 animasyon yazlmlarn verebiliriz. Bu yazlmlar arlkl olarak bilgisayarn
grafik arabirimini kullanrlar.
5. Sistem yazlmlar (system software):
Bilgisayarn elektronik yapsn yneten yazlmlardr. Derleyiciler, haberleme programlar,
iletim sistemi birer sistem yazlmdr. rnein text editr de bir sistem yazlmdr.
Uygulama programlarna gre daha dk seviyeli ilem yaparlar.
Bir bilgisayar yalnzca kendi makine dilini dorudan anlayabilir. Makine dili bilgisayarn doal
dilidir ve bilgisayarn donanmsal tasarmna baldr. Bilgisayarlarn gelitirilmesiyle birlikte
onlara i yaptrmak iin kullanlan ilk diller de makine dilleri olmutur. Bu yzden makine
dillerine 1. kuak diller de diyebiliriz.
Makine dilinin programlarda kullanlmasnda karlalan iki temel problem vardr. Makine
dilinde yazlan kodlar dorudan makinann ilemcisine, donanm paralarna verilen
komutlardr. Deiik bir CPU kullanldnda ya da bellek organizasyonu farkl bir ekilde
yapldnda artk program almayacak ve programn tekrar yazlmas gerekecektir. nk
makine dili yalnzca belirli bir CPU ya da CPU serisine uygulanabilir. Makine dili tanabilir
(portable) deildir. Dier nemli bir problem 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 dili
programlarn gelitirmek, daha 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 ierisinde makine dilinden, insan
alglamasna ok yakn yksek seviyeli dillere (4. kuak diller) kadar uzanan bir sre sz
konusudur. Bu tarihsel sreci ana hatlaryla inceleyelim :
1950 li yllarn hemen balarnda makine dili kullanmn getirdii problemleri ortadan
kaldrmaya ynelik almalar younlat. Bu yllarda makine dilleri bilgisayarn ok snrl olan
belleine ykleniyor ve programlar byle altrlyordu. lk nce makine dilinin alglanma ve
anlalma zorluunu ksmen de olsa ortadan kaldran bir adm atld. Sembolik makine dilleri
gelitirildi. Sembolik makine dilleri (Assembly languages) yalnzca 1 ve 0 dan oluan makine
dilleri yerine ngilizce baz ksaltma szcklerden oluuyordu. Sembolik makine dillerinin
kullanm ksa srede yaygnlat. Ancak sembolik 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 sembolik dilin komutlar, bilgisayar tarafndan
komut komut makine diline evriliyor ve oluan makine kodu altrlyordu. Yani bilgisayar,
program alma aamasnda nce yorumluyarak makine diline eviriyor daha sonra makine
diline evrilmi komutlar icra ediyordu. Bu ekilde altrlan programlarn hz 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 yazlanlarn gerek
program deneceini sylyorlard.
Bu sorunun da stesinden gelindi. O zamanlar iin ok parlak kabul edilebilecek fikir uydu:
Her defasnda yazlan kod, kodun altrlmas srasnda makine diline evireceine,
gelitirilecek bir baka program sembolik dilinde yazlan kodu bir kez makine diline evirsin ve
artk program ne zaman altrlmak istense, bilgisayar yorumlama olmakszn yalnzca
makine kodunu altrsn. Bu fikiri gelitiren Grace Hopper isimli bir bayand. Grace Hopper'n
buluuna "compiler" derleyici ismi verildi. (Grace Hopper ayn zamanda Cobol dilini gelitiren
ekipten biridir, bug(bcek) szcn ilk olarak Grace Hopper kullanmtr.) Artk programclar
sembolik szcklerden oluan Assembly programlarn kullanyor. Yazdklar programlar
derleyici tarafndan makine koduna dntrlyor ve makine kodu eski hzndan birey
kaybetmeksizin 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 bir ok komut gerekmesi, programlama prosesini
daha hzl bir hale getirmek iin araylar balatm, bunun sonucunda da daha yksek seviyeli
programlama dilleri gelitirilmeye balanmtr.
PROGRAMLAMA VE C
Tarihsel sre iinde Assembly dillerinden daha sonra gelitirilmi ve daha yksek seviyeli diller
3. kuak diller saylmaktadr. Bu dillerin hepsi algoritmik dillerdir. Bugne kadar gelitirilmi
olan yzlerce yksek seviyeli programlama dilinden yalnzca pek az bugne kadar varlklarn
srdrebilmitir:
FORTRAN dili (FORmula TRANslator) kompleks matematiksel hesaplamalar gerektiren
mhendislik ve bilimsel uygulamalarda kullanlmak zere 1954 - 1957 yllar arasnda IBM
firmas iin John Backus tarafndan gelitirilmitir. FORTRAN dili, youn matematik
hesaplamalarn gerektii bilimsel uygulamalarda halen yaygn olarak kullanlmaktadr.
FORTRAN dilinin FORTRAN IV ve FORTRAN 77 olmak zere iki nemli versiyonu bulunmaktadr.
Doksanl yllarn balarnda FORTRAN - 90 isimli bir versiyon iin ISO ve ANSI standartlar kabul
edilmitir. FORTRAN dili 3. seviye dillerin en eskisi kabul edilmektedir.
COBOL (COmmon Business Oriented Language) 1959 ylnda, Amerika'daki bilgisayar
reticileri, zel sektr ve devlet sektrndeki bilgisayar kullanclarndan oluan bir grup
tarafndan gelitirilmitir. COBOL'un gelitirilme amac veri ynetimi ve ilemenin gerektii
ticari uygulamalarda kullanlacak tanabilir bir programlama dili kullanmaktr. COBOL dili de
halen yaygn olarak kullanlmaktadr.
ALGOL (The ALGOritmick Language) 1958 ylnda Avrupa'da bir konsorsiyum tarafndan
gelitirilmeye balanmtr. IBM Firmas FORTRAN dilini kendi donanmlarnda kullanlacak ortak
programlama dili olarak benimsediinden, Avrupa'llar da alternatif bir dil gelitirmek
istemilerdi. ALGOL dilinde gelitirilen bir ok prensip modern programlama dillerinin hepsinde
kullanlmaktadr.
60'l yllarn balarnda programlama dilleri zerinde yaplan almalar yapsal programlama
kavramn gndeme getirmitir. Bu dillerden bazlarna ksaca gz atalm:
PASCAL dili 1971 ylnda akademik evrelere yapsal programlama kavramn tantmak iin
Profesr Niclaus Wirth tarafndan gelitirilmi (Dilin yaratcs, dile matematiki ve filozof Blaise
Pascal'n ismini vermitir.) ve bu dil ksa zaman iinde niversitelerde kullanlan programlama
dili haline gelmitir.
Pascal dilinin ticari ve endstriyel uygulamalar desteklemek iin sahip olmas gereken bir
takm zelliklerden yoksun olmas bu dilin bu uygulamalarda fazla kullanlmamasna yol
amtr. Modula ve Modula-2 dilleri Pascal dili baz alnarak gelitirilmitir.
BASIC dili 1960'l yllarn ortalarnda John Kemeney ve Thomas Kurtz tarafndan gelitirilmitir.
Her ne kadar BASIC isminin "Beginner's All_purpose Symbolic Instruction Code" szcklerinin
ba harflerinden oluturulduu sylense de, bu szcklerin daha sonradan uydurulduu aktr.
Yksek seviyeli dillerin en eski ve en basit olanlarndan biridir.Tm basitliine karn, bir ok
ticari uygulamada kullanlmtr. BASIC dili de ANSI tarafndan standartlatrlmtr. Ancak
BASIC dilinin ilave zellikler ieren bir sr versiyonu sz konusudur. rnein Microsoft
firmasnn kartt Visual Basic diline Nesne Ynelimli Programlamaya ilikin birok zellik
eklenmitir. Ayrca BASIC dilinin baz versiyonlar uygulama programlarnda (rnein MS Excel
ve MS Word'de) kullancnn zelletirme ve otomatikletirme amacyla yazaca makrolarn
yazlmasnda kullanlan programlama dili olarak da genel kabul grmtr.
ADA dili ise Amerikan Savunma Departman (Department of Defence -DoD) destei ile 70 li
yllar ve 80'li yllarn balarnda gelitirilmitir. 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 (CIIHoneywell Bull of France) Pascal dilini baz olarak alan almalar sonucunda Ada dilini
gelitirdi. Ada dilinin dkmanlar 1983 ylnda yaymlanmtr.(Ada ismi, air Lord Byron'un kz
olan Lady Ada Lovelace'n isminden alntdr. Ada Lovelace delikli kartlar hesap makinalarnda
ilk olarak kullanlan Charles Babbage'in yardmcsyd. Charles Babbage hayat boyunca "Fark
makinas" (Difference Engine) ve "Analitik Makine" (Analytical Engine) isimli makinalarn yapm
zerinde alt ama bu projelerini gerekletiremeden ld. Yine de gelitirdii tasarmlar
modern bilgisayarlarn atas kabul edilmektedir. Ada Lovelace Charles Babbage'n makinas iin
1
delikli kartlar ve kullanlacak algoritmalar hazrlyordu. Bu bayann 1800'l yllarn banda ilk
bilgisayar programn yazd kabul edilmektedir.) Ada dili genel amal bir dildir, ticari
uygulamalardan roketlerin ynlendirilmesine kadar birok farkl alanda kullanlmaktdr. Dilin
nemli zelliklerinden bir tanesi gerek zaman uygulamalarna (real-time applications /
embedded systems) destek vermesidir. Baka bir zellii de yksek modlaritesi nedeniyle
byk programlarn yazmn kolaylatrmasdr. Ancak byk ve karmak derleyicilere ihtiya
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 olarak ksaltlrlar.
(fourth generation language). nsan algsna en yakn dillerdir. RPG dili 4. kuak dillerin ilki
olarak kabul edilebilir.zellikle kk IBM makinalarnn kullanclar olan irketlerin, rapor
retimi iin basit bir dil istemeleri zerine IBM firmas tarafndan gelitirilmitir.
Programlama dillerini seviyelerine gre 5 ana gruba ayrabiliriz:
1. ok yksek seviyeli diller ya da grsel diller (visual languages):
Access, Foxpro, Paradox, Xbase, Visual Basic, Oracle Forms.
2. Yksek seviyeli diller (Bunlara algoritmik diller de denir):
Fortran, Pascal, Basic, Cobol.
3. Orta seviyeli programlama dilleri:
Ada, C. Orta seviyeli diller daha az kaypla makine diline evrilebildiinden daha hzl alr.
4. Alak seviyeli programlama dilleri:
Sembolik makine dili (Assembly language).
5. Makine dili:
En aa seviyeli programlama dili. (Saf makine dili tamamen 1 ve 0 lardan oluuyor.)
PROGRAMLAMA VE C
C bilimsel ve mhendislik alanlarna kullanlabilen genel amal bir sistem programlama dilidir.
Verimlilik (efficiency)
Bu zellie programn hzl alma zellii diyebiliriz. Programn alma hz pek ok faktre
baldr. Algoritmann da hz zerinde etkisi vardr. almann yapld bilgisayarn da doal
olarak hz zerinde etkisi vardr. Verimlilii bir programlama dilinde yazlm bir programn hzl
almas ile ilgili bir kavram olarak dnebiliriz. Bu adan bakldnda C verimli bir dildir.
1
Yapsal programlama tekniinde, programn dier paralarndan ulalamayan, yalnzca belli
bir faaliyet alan olan, yani kodun yalnzca belli bir ksmnda faaliyet gsterecek deikenler
tanmlanabilir. Bu tr deikenler genel olarak "yerel deikenler" (local variables) olarak
isimlendirilirler. Deikenlerin faaliyet alanlarnn kstlanabilmesi hata yapma riskini
azaltt gibi, programlarn daha kolay deitirilebilmesini ve program paralarnn baka
programlarda tekrar kullanabilmesini de salar. Alt programlarn, ve daha geni ekliyle
modllerin, bir ii nasl yapt bilgisi, o alt programn ya da modln kullancsndan
gizlenir. Kullanc iin (client) 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 mekanizma programn yukardan aa
olarak ak ile uyum halindedir. Program paralarna ancak tek bir noktadan girilebilir.
4. Dngler ve dier kontrol yaplar.
Artk hemen hemen kullanmda olan btn programlama dilleri az ya da ok Yapsal
Programlama tekniini desteklemektedir. Zira bu teknik 60'l yllar iin devrim
niteliindeydi.
Esneklik (flexibility)
Esneklik programlama dilinin programcy kstlamamas anlamna gelir.Esnek dillerde birok
ilem, hata yapma riski artmasna karn ramen kullanc iin serbest braklmtr. Programc
bu serbestlikten ancak yetkin bir programcysa bir fayda salayabilir. Fakat programc
deneyimsiz ise bu esneklikten zarar grebilir.
Genellik (generality)
Programlama dillerinin ok eitli uygulamalarda etkin olarak kullanlabilmesidir. rnein
COBOL mhendislik uygulamalarnda tercih edilmez zaten ticari uygulamalar iin tasarlanmtr,
Clipper ya da FOXPRO veri taban dilleridir. Oysa PASCAL, BASIC daha genel amal dillerdir. C
dili de bir sistem programlama dili olarak domasna karn, gl yapsndan dolay, ksa bir
sre iinde, genel amal bir dil haline gelmitir.
Okunabilirlik (readability)
Okunabilirlik, kaynak kodun abuk ve iyi bir biimde alglanabilmesi anlamna gelen bir
terimdir. Kaynak kodun okunabilirliinde sorumluluk byk lde program yazan kiidedir.
Fakat yine verimlilik de olduu gibi dillerin bir ksmnda okunabilirlii glendiren yap ve
mekanizmalar bulunduu iin bu zellik bir lde dilin tasarmna da baldr. En iyi program
kodu, sanld gibi "en zekice yazlm fakat kimsenin anlayamayaca" kod deildir.
Birok durumda iyi programclar okunabilirlii hibireye feda etmek istemezler. nk
okunabilir bir program kolay alglanabilme zelliinden dolay seneler sonra bile
PROGRAMLAMA VE C
gncelletirmeye olanak salar. Birok kiinin ortak kodlar zerinde alt geni kapsaml
projelerde okunabilirlik daha da nem kazanmaktadr.
C de okunabilirlik en fazla vurgulanan kavramlardan biridir. Biz de kursumuz boyunca
okunabilirlik konusuna sk sk deineceiz ve C programlarnn okunabilirlii konusunda baz
temel prensipleri benimseyeceiz.
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. 1989 ylnda standartlatrma almalar biten C Dili, dier programlama dillerinden
daha tanabilir bir programlama dilidir.
gelmiken,
Nesne
Ynelimli
C algoritmik bir dildir. C'de program yazmak iin yalnzca dilin sentaks ve sementik 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. fade gc yksek , okunabilirlik zellii gl
bir dildir.
C ok esnektir. Dier dillerde olduu gibi programcya kstlamalar getirmez.
Gl bir dildir. ok iyi bir biimde tasarlanmtr. C'ye ilikin operatrlerin ve yaplarn bir ou
daha sonra baka programlama dilleri tarafndan da benimsenmitir.
C verimli bir dildir. Seviyesinden dolay hzl alr. Verimlilik konusunda assembly diller ile
rekabet edebilir.
C doal bir dildir. C bilgisayar sisteminin biimiyle uyum iindedir.
C kk bir dildir. Yeni sistemler iin derleyici yazmak zor deildir.
C'nin eitimi dier bilgisayar dillerine gre daha zordur.
Algol 68
Algol W
Simula 67
BCPL
C
Pascal
C++
Java
Modula-2
Ada
Delphi
Oberon
PROGRAMLAMA VE C
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 teknoloji olan PDP-11
bilgisayarlarda alyordu. Thompson UNIX iletim sisteminin bir ksmn B dilinde tekrar yazd.
Artk 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 versiyonunu 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 tekrar yazld.
Ken Thompson ve Dennis Ritchie Unix
letim Sistemi zerinde alrken (Yl:
1972)
C'nin evrimi ve gelimesi 70'li yllarda
da devam etti. 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'nin standardize
edilmesine kadar olan dnemde bu kitap ounluun benimsedii genel kabul gren gayriresmi
bir standard vazifesi de grmtr.
1970'li yllarda C programclarnn says azd ve bunlardan ou
UNIX kullanclaryd. Ama artk 80'li yllar gelince C nin kullanm
UNIX snrlarn at, ve farkl iletim sistemlerinde alan
derleyiciler piyasaya kt, C dili de IBM PC'lerde youn olarak
kullanlmaya balad.
C'nin artan poplaritesi problemleri de beraberinde getirdi.
Derleyici yazan kiiler, referans olarak Ritchie ve Kernighan'n
kitabn esas alyorlard ama sz konusu kitapta baz noktalar
ok da detayl bir biime 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.
Artk C dilinin standardizasyonu neredeyse zorunlu bir hale gelmiti! C'nin standardizasyon
almalar 1983 ylnda ANSI (American National Standards Institute ) gzetiminde ve
desteinde balad. Yaplan birok deiiklikten sonra standart almalar 1988 ylnda sona
erdi ve 1989 ylnn Aralk aynda ANSI C standard Jim Brodie bakanlnda X3.159 - 1989
numarasyla resmi olarak onayland. 1990 ylnda ise ISO/IEC 9899 - 1990 numarasyla ISO
(International
Standards
Organization)
tarafndan
standardizasyonu
kabul
edildi.
Standardizasyonu tamamlandktan sonra C yksek oranda tanabilir bir sistem programlama
dili haline gelmitir. Gnmzde de sistem programlarnn (derleyiciler, editrler, iletim
sistemleri) ou C dili ile yazlmaktadr.
Fotoraflar
Dennis M. Ritchie
9
10
SAYI SSTEMLER
kilik say sisteminde yazlan bir saynn belirli bir basamandan (bitinden) sz ettiimizde, 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.
ii. 10luk sistemdeki bir saynn 2lik sistemde ifadesi :
Say srekli olarak 2 ye blnr. Her blmden kalan deer( yani 1 ya da 0) oluturulacak saynn 0. bitinden
balayarak, basamaklarn oluturacaktr. Bu ileme 0 says elde edilinceye kadar devam edilir. rnek:
87 saysn ikilik say sisteminde ifade etmek isteyelim:
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 10 luk sistemde ifade edilen saydan srekli olarak 2'nin en byk kuvvetini karmaktr.
2nin karlan her bir kuvveti iin ilgili basamaa 1 deeri yazlr. Bu ileme 0 says elde edilene kadar
devam edilir. rnek:
Yine 87 saysn ikilik say sisteminde ifade etmek isteyelim:
87'den karlabilecek, yani 87'den byk olmayan ikinin en byk kuvveti nedir? Cevap 64. O zaman 64 = 2 6
olduuna gre 6.bit 1 deerini alacak.
87 - 64 = 23. imdi 23'den karlabilecek ikinin en byk kuvvetini bulalm. Bu say1 16'dr. Yani 24 'dr. O
zaman saymzn 4. biti de 1 olacak.
23 - 16 = 7. 7'den karlabilecek ikinin en byk kuvveti 4'dr ve 4 = 22 'dir. Saymznj 2. biti de 1 olacak.
7 - 4 = 3.
3 - 2 = 1 (2 = 21 ) Saymzn 1. biti 1 olacak.
1 - 1 = 0 (1 = 20 ) Saymzn 0. biti 1 olacak.
1 deeri olmayan tm bitleri 0 bitiyle doldurarak saymz ikilik sistemde ifade edelim:
87 = 0101 0111
iii. kilik sistemde ifade edilen bir saynn 1e tmleyeni. Saynn tm bitlerinin tersinin
alnmasyla elde edilir. Yani saydaki 1ler 0 ve 0lar 1 yaplr.
Bir saynn 1e tmleyeninin 1e tmleyeni saynn yine kendisidir.
iv. kilik sistemde ifade edilen bir saynn 2ye tmleyeninin bulunmas:
nce saynn 1e tmleyeni yukardaki gibi bulunur. Daha sonra elde edilen sayya 1 eklenirse saynn 2ye
tmleyeni bulunmu olur. 2'ye tmleyeni bulmak iin daha daha pratik bir yol daha vardr : Saynn en
solundan balayarak ilk defa 1 biti grene kadar (ilk grlen 1 dahil) saynn ayns yazlr, daha sonraki tm
basamaklar iin basaman tersi yazlr. (Yani 1 iin 0 ve 0 iin 1) rnein :
1110 0100 saysnn ikiye tmleyeni 0001 1100 dr.
0101 1000 saysnn ikiye tmleyeni 1010 1000 dr.
Bir saynn ikiye tmleyeninin ikiye tmleyeni saynn kendisidir. (Deneyiniz)
8 bitlik bir alana yazlacak en byk tam say katr?
1111 1111 = 255 dir. (1 + 2 + 4 + 8 + 16 + 32 + 64 + 128 = 255)
8 bitlik bir alana yazlacak en kk tam say katr?
0000 0000 = 0dr.
Negatif bir tamsay ikilik sistemde nasl gsterilir?
12
SAYI SSTEMLER
Negatif tamsaylarn da ifade edildii ikilik say sistemine iaretli ikilik say sistemi (signed binary system)
denir. aretli ikilik say siteminde, negatif saylar gstermek iin hemen hemen tm bilgisayar sistemlerinde
aadaki yol izlenir:
Saynn en yksek anlaml biti iaret biti (sign bit) olarak kabul edilir. Ve bu bit 1 ise say negatif, bu bit 0 ise
say pozitif olarak deerlendirilir. kilik sistemde bir negatif say ayn deerdeki pozitif saynn ikiye
tmleyenidir. rnek olarak, ikilik sistemde yazacamz 27 says yine ikilik sistemde yazlan 27 saysnn
ikiye tmleyenidir.
Pozitif olan saylarn deerini tpk iaretsiz say sisteminde olduu gibi elde ederiz:
0001 1110 iaretli sistemde pozitif bir saydr. (Decimal olarak 29 saysna eittir.)
Ancak negatif olan saylarn deerini ancak bir dnmle elde edebiliriz:
1001 1101 iaretli sistemde negatif bir saydr. (nk iaret biti 1)
2lik sistemde ifade edilen negatif bir saynn 10luk sistemde hangi negatif sayya eit olduunu nasl
bulunur?
Saynn en yksek anlaml biti (MSD) iaret bitidir. Bu bit 1 ise say negatifdir. Saynn kaa eit olduunu
hesaplamak iin ilk nce saynn 2ye tmleyeni bulunur. Ve bu saynn hangi pozitif sayya karlk geldiini
hesap edilir. Elde etmek istenen say, bulunan pozitif say ile ayn deerdeki negatif say olacaktr.
rnein 1001 1101 saysnn 10luk sistemde hangi sayya karlk geldii bulunmak istenirse:
Saynn en soldaki biti 1 olduuna gre bu say negatif bir say olacaktr. Hangi negatif say olduunu bulmak
iin saynn 2ye tmleyenini alnr.
1001 1101 saysnn ikiye tmleyeni 0110 0011 saysdr.
Bu saynn 10'luk sistemde hangi sayya denk olduu hesaplanrsa :
(1 * 1 + 1 * 2 + 0 * 4 + 0 * 8 + 0 * 16 + 1 * 32 + 1 * 64 = 99)
ilk yazlan saynn -99 olduu anlalm olur.
10'luk sistemde ifade edilen negatif saylarn iaretli ikilik sistemde yazlmas :
nce saynn ayn deerli fakat pozitif olan ikilik sistemde ifade edilir : Daha sonra yazlan saynn ikiye
tmleyenini alnarak, yazmak istenilen say elde edilir.
rnek : kilik sistemde 17 yazmak istenirse;
nce 17 yazlr.
bu saynn 2'ye tmleyeni alnrsa
0001 0001
1110 1111 says elde edilir.
Say deeri ayn olan Negatif ve Pozitif saylar birbirlerinin ikiye tmleyenleridir.
kilik sistemde gsterilmi olsa da ayn saynn negatifiyle pozitifinin toplam 0 deerini verecektir.
(Deneyiniz!)
Bir bytelk (8 bitlik) bir alana yazabileceimiz (iaret bitini dikkate almadan) en byk say 255 (1111 1111)
ve en kk say ise 0dr.(0000 0000). Peki iaret biti dikkate alndnda 1 bytelk alana yazlabilecek en
byk ve en kk saylar ne olabilir?
En byk say kolayca hesaplanabilir. iaret biti 0 olacak (yani say pozitif olacak) ve say deerini en byk
hale getirmek iin dier btn bit deerleri 1 olacak, bu say 0111 1111 saysdr. Bu sayy desimal sisteme
dntrrsek 127 olduunu grrz. Peki ya en kk negatif say katr ve nasl ifade edilir?
0111 1111 saysnn ikiye tmleyenini alndnda 127 saysn elde edilir.
1000 0001 (127) Bu saydan hala 1 kartabilir.
1000 0000 (-128) 1 byte alana yazlabilecek en kk negatif saydr.
13
2
Burada dikkat edilmesi gereken iki nemli nokta vardr :
1 byte alana yazlabilecek en byk say snr aldnda negatif blgeye geilir.
0111 1111 (en byk pozitif tamsay)
1 (1 toplarsak)
1000 0000 (-128 yani en kk tamsay)
yani 1 byte alana yazlabilecek en byk tamsayya 1 eklendiinde 1 byte alana yazlabilecek en kk
tamsayy elde ederiz.
1 byte alana yazlabilecek en kk tamsaydan 1 kardmzda da 1 byte alana yazlabilecek en byk
tamsayy elde ederiz.
Yukarda anlattklarmza gre -1 saysnn iaretli ikilik say sisteminde 8 bitlik bir alanda aadaki ekilde
ifade edilecektir.
-1 = 1111 1111
Yani iaretli ikilik say sisteminde tm bitleri 1 olan say -1'dir. leride bu sayyla ok iimiz olacak!
= 10
= 11
= 12
= 13
= 14
= 15
16lk say sisteminde yazlm bir sayy 10luk sisteme evirmek iin, en sadan balayarak basamak
deerleri 16nn artan kuvvetleriyle arplr :
01AF = (15 * 1) + (10 * 16) + (1 * 256) + (0 * 4096) = 431
10luk sistemde yazlm bir sayy 16lk sisteme evirmek iin 10 luk sistemden 2lik sisteme yaplan
dnmlerdekine benzer ekilde say srekli 16 ya blnerek, kalanlar soldan saa doru yazlr.
Pratikte 16 lk say sistemlerinin getirdii nemli bir avantaj vardr. Bu avantaj 16 lk say sistemi ile 2lik say
sistemi arasndaki dnmlerin kolay bir ekilde yaplmasdr.
16lk sistemdeki her digit 2lik sistemdeki 4 bit (1 Nibble) alan ile ifade edilebilir :
0001
0010
0011
0100
0101
0110
0111
1
2
3
4
5
6
7
14
SAYI SSTEMLER
1000
1001
1010
1011
1100
1101
1110
1111
8
9
A
B
C
D
E
F
rnek : 2ADFH saysnn (en sondaki H saynn hexadecimal olarak gsterildiini anlatr yani sayya ilikin
bir sembol deildir) 16'lk sistemde ifadesi :
2
A
D
F
=
=
=
=
0010
1010
1101
1111
= AEB1H
= 2D3EH
soru : 16'lk say sisteminde 2 byte'lk bir alanda yazlm olan 81AC H says pozitif mi negatif midir?
cevap : Saynn yksek anlaml biti 1 olduu iin, iaretli say sistemlerinde say negatif olarak
deerlendirilecektir. (1001 0001 1010 1100)
16 bitlik bir alanda ve iaretli say sisteminde -1 saysn nasl ifade edebiliriz :
Cevap : FFFF
8lik say sistemi (octal numbering system)
Daha az kullanlan bir say sistemidir.
8 adet sembol vardr. (0 1 2 3 4 5 6 7)
8lik say sisteminin her bir digiti 2lik sistemde 3 bit ile ifade edilir.
001
010
011
100
101
110
111
1
2
3
4
5
6
7
8'lik say sisteminin de kullanlma nedeni, 2'lik say sistemine gre daha yogun bir ifade tarz olmas, ve ikilik
say sistemiyle, 8'lik say sistemi arasnda yaplacak dnmlerin ok kolay bir biimde yaplabilmesidir.
GEREK SAYILARIN BELLEKTE TUTULMASI
Sistemlerin ou gerek saylar IEEE 754 standardna gre tutarlar. (Institute of Electrical and
Electronics Engineers) Bu standarda gre gerek saylar iin iki ayr format belirlenmitir:
single precision format (tek hassasiyetli gerek say format)
Bu formatta gerek say 32 bit (8 byte) ile ifade edilir.
32 bit ayr ksma ayrlmtr.
1. aret biti (sign bit) (1 bit)
15
2
Aada S harfi ile gsterilmitir.
aret biti 1 ise say negatif, iaret biti 0 ise say pozitiftir.
2. stel ksm (exponent) (8 bit)
Aada E harfleriyle gsterilmitir.
3. Ondalk ksm (fraction) (23 bit)
Aada F harfleriyle gsterilmitir.
S
31
EEEEEEEE
30-----------23
FFFFFFFFFFFFFFFFFFFFFFF
22-------------------------------------0
= Say deil
= Say deil
SAYI SSTEMLER
= 2-149 (en kk pozitif deer)
E = 0 ve F = 0 ve S = 1 ise V = -0
E = 0 ve F = 0 ve S = 0 ise V = 0
double precision format (ift hassasiyetli gerek say format)
Bu formatta gerek say 64 bit (8 byte) ile ifade edilir.
64 bit ayr ksma ayrlmtr.
1. aret biti (sign bit) (1 bit)
Aada S harfi ile gsterilmitir.
aret biti 1 ise say negatif, iaret biti 0 ise say pozitiftir.
2. stel ksm (exponent) (11 bit)
Aada E harfleriyle gsterilmitir.
3. Ondalk ksm (fraction) (52 bit)
Aada F harfleriyle gsterilmitir.
S EEEEEEEEEEE FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
63 62------------------52 51-----------------------------------------------------------------------------0
Aadaki formle gre saynn deeri hesaplanabilir :
Aadaki formle gre saynn deeri hesaplanabilir :
V saynn deeri olmak zere:
E = 2047 ise ve F 0 d bir deer ise V = NaN (Not a number) bir gerek say olarak kabul edilmez.
E = 2047 ise ve F = 0 ise ve S = 1 ise V = -sonsuz
E = 2047 ise ve F = 0 ise ve S = 1 ise V = +sonsuz
0 < E < 2047 ise
V = (-1)S * 2(E -1023) * (1.F)
nce saynn fraction ksmnn bana 1. eklenir. Daha sonra bu say 2(E-1023) ile arplarak noktann yeri
ayarlanr. Noktadan sonraki ksm 2'nin artan negatif kuvvetleriyle arplarak elde edilecektir.
E = 0 ve F sfr d bir deer ise
V = (-1)S * 2(-126) * (0.F)
E = 0 ve F = 0 ve S = 1 ise V = -0
E = 0 ve F = 0 ve S = 0 ise V = 0
17
18
19
goto if
Baz programlama dillerinde anahtar szcklerin kk ya da byk harf olmas fark etmemektedir. Ama
Cde btn anahtar szckler kk harf olarak tanmlanmtr. C byk harf kk harf duyarl olan bir
dildir. (case sensitive) bir dildir. Ama dier programlama dillerinin ounda byk - kk harf duyarl
yoktur. (case insensitive)
rnein, programc olarak biz kullanacamz bir deikene register ismini vermeyiz. nk bu bir anahtar
szcktr. (C dili tarafndan rezerve edilmitir) Ama buna karn biz istediimiz bir deikene REGISTER,
Register, RegisTER vs. gibi isimler verebiliriz, nk bunlar artk anahtar szck saylmazlar. Anahtar
szck olan yalnzca tamamen kk harf ile yazlan "register" dir.
2. simlendirilenler (identifiers)
Deikenlere, fonksiyonlara, makrolara, yap ve birliklere vs. programlama dili tarafndan belirlenmi
kurallara uyulmak artyla, istediimiz gibi isim verebiliriz. Bu atomlar genellikle bellekte bir yer belirtirler.
C dilinde deikenlerin isimlendirilmesine ilikin kurallar vardr. Bunu ileride detayl olarak greceiz.
3. Operatrler (Operators)
Operatrler nceden tanmlanm birtakm ilemleri yapan atomlardr.
rnein +, -, *, / , >=, <= birer operatrdr.
Programlama dillerinde kullanlan operatr sembolleri birbirinden farkl olabilecei gibi, operatr
tanmlamalar da birbirinden farkl olabilir. rnein birok programlama dilinde s alma operatr
tanmlanmken C dilinde byle bir operatr yoktur. s alma ilemi operatr ile deil bir fonksiyon yardmyla
yaplabilir.
C dilinde baz operatrler iki karakterden olumaktadr bu iki karakter bitiik yazlmaldr aralarna space
karakteri koyarsak operatr anlamn yitirir.
4. Sabitler (Constants)
Dorudan ileme sokulan deiken bilgi iermeyen atomlardr.
rnein SAYAC = SON + 10 gibi bir ifadede 10 sabiti dorudan SON deikeni ile toplanmaktadr.
20
GENEL KAVRAMLAR
return
+=
stringler
("ltfen bir say giriniz\n"
"%d"
"toplam = %d\n"
NESNE (OBJECT)
Bellekte yer kaplayan ve ieriklerine eriilebilen alanlara nesne denir. Bir ifadenin nesne olabilmesi iin
bellekte bir yer belirtmesi gerekir. Programlama dillerinde nesnelere isimlerini kullanarak eriebiliriz.
a = b + k; rneinde a, b ve k birer nesnedir. Bu ifadede a nesnesine b ve k nesneleriine ait deerlerin
toplam atanmaktadr.
sonuc = 100; sonuc isimli nesneye 100 sabit deeri atanmaktadr.
nesnelerin baz zelliklerinden sz edilebilir :
simleri (name) :
21
3
Nesneyi temsil eden karakterlerdir. Nesnelere isimleri programc tarafndan verilir. Her dil iin nesne
isimlendirmede baz kurallar sz konusudur.
VERGI = 20000; (Burada VERGI bir nesne ismidir.)
Nesne ile Deiken kavramlar birbirine tam olarak edeer deildir. Her deiken bir nesnedir ama her
nesne bir deiken deildir. Deikenler, programcnn isimlendirdii nesnelerdir. Peki programcnn
isimlendirmedii de nesneler var mdr? Evet, gstericiler konusunda da greceimiz gibi, deiken olmayan
nesneler de vardr, nesne kavram deiken kavramn kapsamaktadr.
Deerleri (value) :
Nesnelerin ilerinde tuttukler bilgilerdir. Baka bir deyile nesneler iin bellekte ayrlan yerklerdeki 1 ve 0
larn yorumlan biimi ilgili nesnenin deeridir. Bu deerler programlama dillerinin kurallarna gre ,
istenildikleri zaman programc tarafndan deitirilebilirler. C dilinde baz nesneler ise bir kez deer
verildikten sonra bir daha deitirilemezler.
Trleri (Type) :
Nesnenin tr derleyiciye o nesnenin nasl yorumlanaca hakknda bilgi verir. Yine 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
yaplabilecii bilgisini de verir.
Tr nesnenin ayrlmaz bir zelliidir, trsz bir nesne kavram sz konusu deildir.
Trleri ikiye ayrabiliriz :
Balantlar (linkage)
Nesnelerin program oluturan dier modllerde tannabilme zelliidir. (leride detayl inceleyeceiz)
FADE (Expression)
Deiken, operatr ve sabitlerin kombinasyonlarna ifade denir.
a+b/2
c * 2, d = h + 34
var1
22
GENEL KAVRAMLAR
geerli ifadelerdir.
DEYM (statement)
Derleyicinin, bilgisayara bir i yaptracak ekilde kod retmesine (yani icra edilebilecek bir kod retmesine)
yol aan ifadelere deyim denir.
rnein C dilinde
; ile sonlandrlm ifadelere deyim diyoruz.
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 olacaktr.
Deyimleri leride detayl olarak inceleyeceiz.
23
24
VER TRLER
iaretli ve iaretsiz short veri 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 alan kaplayacaktr. iaretli short int veri trnden bir nesne -32768 - +32767
aralndaki tamsay deerlerini tutabilirken, iaretsiz short tr sz konusu olduundan tutulabilecek
deerler 0 - +65535 aralnda olabilir.
25
TAMSAYI TRLER
(INTEGER TYPES)
TR SM
UZUNLUK(byte)
(DOS / UNIX)
signed char
1
unsigned char
1
signed short int
2
unsigned short int
2
signed int
2
4
unsigned int
long int
unsigned long int
4
4
4
SINIR DEERLER
-128
0
-32.768
0
-32.768
-2.147.483.648
0
0
-2.147.483.648
0
127
255
32.767
65.535
32.767
2.147.483.647
65.535
4.294.967.296
2.147.483.647
4.294.967.296
UZUNLUK
(byte)
float
double
long double
10
SINIR DEERLER
en kk pozitif deer
en byk pozitif deer
1.17 x 10-38
3.40 x 1038
(6 basamak hassasiyet)
2.22 x 10-308
1.17 x 10-38
(15 basamak hassasiyet)
(15 basamak hassasiyet)
tanabilir deil
Yukarda verilen tablo sistemlerin ou iin geerli de olsa ANSI C standartlarna gre yalnzca aadaki
zellikler garanti altna alnmtr:
char tr 1 byte uzunluunda olmak zorundadr.
short veri trnn uzunluu int trnn uzunluuna eit ya da int tr uzunluundan kk olmaldr. Yani
short <= int
long veri trnn uzunluu int trne eit ya da int trnden byk olmak zorundadr. Yani
long >= int
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
26
VER TRLER
char tr 1 byte
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 tr iken gerek saylar iin double veri trdr. Peki
hangi durumlarda hangi veri trn kullanmak gerekir. Bu sorunun cevab olarak hazr bir reete vermek pek
mmkn deil, zira kullanacamz bir nesne iin tr seerken bir ok faktr sz konusu olabilir, ama genel
olarak u bilgileri verebiliriz :
Gerek saylarla yaplan ilemler tam saylarla yaplan ilemlere gre ok daha fazla 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 hznn belirli lde
yavalatlmas anlamna gelecektir. Bir tamsay trnn yeterli olmas durumunda gerek say trnn
kullanlmas programn okunabilirliininin de azalmasna neden olacaktr.
27
BLDRM VE TANIMLAMA
Progamlama dillerinin ounda nesneler kullanlmadan nceye derleyiciye tantlrlar.
Nesnelerin kullanlmalarndan nce, zellikleri hakknda derleyiciye bilgi verme ilemlerine
bildirim (declaration) denir. Bildirim ilemi yoluyla, derleyiciler nesnelerin hangi zelliklere
sahip olduklarn anlarlar ve bylece bu nesneler iin bellekte uygun bir yer tahsisat
yapabilirler. Yaratlacak nesne hakknda derleyiciye verilecek en nemli bilgi phesiz nesneye
ilikin tr (type) bilgisidir.
C dilinde eer yaplan bir bildirim ilemi, derleyicinin bellekte bir yer ayrmasna neden oluyorsa
bu ileme tanmlama (definition) denir. Tanmlama nesne yaratan bir bildirimdir.
Her tanmlama ilem ayn zamanda bir bildirim ilemidir ama her bildirim ilemi bir tanmlama
olmayabilir. Baka bir deyile, tanmlama nesne yaratan bir bildirim ilemidir.
C dilinde bir deikeni bildirimini yapmadan nce kullanmak derleme ileminde hata (error)
oluumuna yol aar.
Bir deikenin derleyiciye tantlmas deikenin trnn ve isminin derleyiciye bildirilmesidir
ki, 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.
char
unsigned char
short
[signed ] char
[signed] short
short [int]
28
BLDRM VE TANIMLAMA
4
5
6
7
8
9
10
11
unsigned short
int
unsigned int
long
unsigned long
float
double
long double
[signed] int
unsigned
[signed] long
unsigned long [int]
signed
long [int]
Yukarda ayn kolon zerindeki bildirimlerin hepsi ayn trden nesne yaratr.
Bildirim ileminde nesne ismi olarak, C dilinin isimlendirme kurallarna uygun olarak seilen
herhangi bir isim kullanlabilir.
C dilinde isimlendirilenler (identifiers) kavram 6 grubu ierir. Deikenler (variable) bunlardan
yalnzca bir tanesidir. Fonksiyonlar (functions), etiketler (labels), makrolar (macros), yap ve
birlik isimleri (structure and union tags), enum sabitleri (enum constants) isimlerini
programclardan alrlar.
29
var, Var, VAr, VAR, vAR, vaR deikelerinin hepsi ayr deikenler olarak ele alnacaktr.
Bu noktalarn hepsi C dilinin sentaks asndan, hata oluumunu engellemek iin zorunlu
durumlar belirtmek iin anlatlmtr.
simlendirme yazlan programlarn okunabilirlii asndan da ok nemlidir. Kullanlan isimlerin
legal olmalarnn dnda, anlaml olmalarna, kodu okuyacak kiiye bir fikir verecek ekilde
seilmelerine de dikkat edilmelidir.
Bildirim ilemi noktal virgl ile sonlandrlmaldr.
Bildirim rnekleri
Tr belirten anahtar szcklerin yazlmasndan sonra ayn tre ilikin birden fazla nesnenin
bildirimi, isimleri arasna virgl koyularak yaplabilir. Bildirim deyimi yine noktal virgl ile
sonlandrlmaldr.
Farkl trlere ilikin bildirimler virgllerle birbirinden ayrlamaz.
signed ve unsigned szckleri tr belirten anahtar szck(ler) olmadan yalnz balarna
kullanlabilirler. Bu durumda int trden bir deikenin bildiriminin yapld kabul edilir:
ile
tamamen ayn anlamdadr. Yine
ile
tamamen ayn anlamdadr. Ancak bu tr bir bildirimi tavsiye etmiyoruz, standartlar komitesi
ileride bu zelliin dilin kurallarndan kaldrlabileceini bildirmitir. (deprecated feature).
Bildirim ileminde, tr belirten anahtar szck birden fazla ise bunlarn yazm sras nemli
deildir, ama okunabilirlik asndan nce iaret belirten anahtar szcn sonra tip belirten
anahtar szcn kullanlmas gelenek haline gelmitir. rnein :
hepsi geerli bildirimlerdir. Ama yukardaki bildirimde, seimlik olan anahtar szckler zellikle
kullanlmak isteniyorsa 1. yazm biimi okunabilirlik asndan tercih edilmelidir.
30
BLDRM VE TANIMLAMA
Bildirimin mutlaka ana bloun banda yaplmas gibi bir zorunluluk yoktur. Eer iie bloklar
varsa iteki herhangi bir bloun banda da (o bloun ilk ilemi olacak ekilde) bildirim
yaplabilir. rnekler :
Yukardaki rnekte var1, var2, ch1, ch2, ch3 deikenlerinin tanmlanma yerleri dorudur.
Ancak f deikeni yanl yerde bildirilmitir. nk bildirim ileminden nce baka bir ilem
(deyim) yer almaktadr. Bu durum derleme aamasnda hata oluumuna neden olur.
Ayn program paras u ekilde yazlm olsayd bir hata sz konusu olmazd :
bu durumda artk f deikeni de kendi blounun banda (ilk ilem olarak) tanmlanmtr.
leride de greceimiz gibi C dilinde tek bana bir noktal virgl, bir deyim oluturur. C
sentaksna gre oluan bu deyim icra edilebilir bir deyimdir. Dolaysyla aadaki kod
parasnda y deikeninin tanmlamas derleme zamannda hata oluturacaktr.
Ayn ekilde bo bir blok da C dilinde bir deyim gibi ele alnr. Bu yazm tamamen noktal
virgln (sonlandrcnn) yalnz kullanlmasna edeerdir. Dolaysyla aadaki kod paras da
hataldr:
Bir ya da birden fazla deyimin de blok iine alnmas C dilinde bileik deyim (compound
statement) ismini alr ve bileik deyimler de icra edilebilir deyim kategorisine girerler.
Dolaysyla aadaki kod paras da hataldr.
(C++ dilinde blok iinde bildirimi yaplan deikenlerin, bloklarn ilk ilemleri olacak ekilde
bildirilmeleri zorunlu deildir. Yani C++ da deikenler bloklarn iinde herhangi bir yerde
bildirilebilirler.)
31
32
SABTLER
5 . BLM : SABTLER
Veriler ya nesnelerin ierisinde ya da dorudan sabit biiminde bulunurlar. Sabitler nesne
biiminde olmayan, programc tarafndan dorudan girilen
verilerdir. Sabitlerin saysal
deerleri derleme zamannda tam olarak bilinmektedir. rnein :
ifadesi bize a ve b iindeki saylarn toplanaca ve cye aktarlacan anlatr. Oysa
ifadesinde x deikeni iinde saklanan deer ile 10 says toplanmtr. Burada 10 says
herhangi bir deikenin iindeki deer deildir, dorudan say biiminde yazlmtr. Nesnelerin
trleri olduu gibi sabitlerin de trleri vardr. Nesnelerin trleri daha nce grdmz gibi
bildirim yaplrken belirlenir. Sabitlerin trlerini ise derleyici, belirli kurallar dahilinde sabitlerin
yazl biimlerinden tespit eder. Sabitlerin trlerini bilmek zorundayz, nk C dilinde
sabitler, deikenler ve operatrler bir araya getirilerek (kombine edilerek) ifadeler
(expressions) oluturulur. Daha sonra detayl greceimiz gibi C dilinde ifadelerin de bir tr
vardr ve ifadelerin trleri, ierdikleri sabit ve deikenlerin trlerinden elde edilir. O halde sabit
trlerini detayl olarak inceleyelim :
uzunluk
2 byte
4 byte
snr deerler
- 32768, + 32767
-2147483648,
+2147483647
rnein 425000 Dosta int sabiti deildir ama UNIXte int sabittir.
Uzun Tamsay Sabitleri(Long integer constants)
33
5
2. int trn say snrlarn aan fakat long int tr say snrlar iinde kalan her tamsay
dorudan long int trden sabit olarak ele alnr. Bu durum doal olarak, DOS gibi int ve
long trlerinin birbirinden farkl olduu sistemlerde anlamldr.
rnein DOSda
long trden sabitlerdir. Oysa 32 bitlik sistemlerde long trnn uzunluuyla int trn
uzunluu ayn (4 byte) olduu iin bu saylar int sabiti olarak ele alnacaktr. Bu sistemlerde
yukardaki saylar long sabit olarak ele almak istersek sonlarna l ya da L eklememiz
gerekmektedir.
'\0'
'\a'
'\b'
'\t'
'\n'
'\v'
'\f'
'\r'
'\"'
'\\'
'\x0'
'\x7'
'\x8'
'\x9'
'\xA'
'\xB'
'\xC'
'\xD'
'\x22'
'\x5C'
'\0'
'\07'
'\010'
'\011'
'\012'
'\013'
'\014'
'\015'
'\042'
'\134'
Tanm
NULL karakter
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)
ters bl (back slash)
ASCII No
0
7
8
9
10
11
12
13
34
92
34
SABTLER
Tek trnak iinde tersbl ve x karakterlerinden sonra bir hex say verilirse bu ASCII
tablosundaki o saysal deerin gsterdii sra numarasndaki karaktere iaret eden bir
karakter sabitidir.
'\x41'
'\xff'
'\x1C'
Kk "x" yerine byk harfle "X" yazmak C'nin ilk klasik versiyonunda kabul ediliyordu
imdi artk geerli deildir. rnek :
Yukardaki rnekte harf isimli char trden deikene 41H ASCII sra no.lu karakter
atanmtr. Bu da desimal sistemdeki 65 saysna eittir. 65 sra nolu ASCII karakteri 'A'
karakteridir. Dolaysyla harf isimli deikene 'A' atanmtr.
4. 8'lik (octal) say sistemde tanmlanm karakter sabitleri
Tek trnak iinde tersbl karakterinden sonra bir oktal say yazlrsa bu kullanlan karakter
setindeki o saysal deerin gsterdii sra numarasndaki karaktere iaret eden bir karakter
sabitidir. Tek trnak iindeki ters bl karakterini izleyen say basamaktan uzun
olmamaldr. Sekizlik saylarn yazmnda olduu gibi saynn banda sfr olma zorunluluu
yoktur. Bu ekilde yazlabilecek en byk karakter sabiti '\377' dir.:
Program iinde kullanmna bir rnek:
7 numaral ASCII karakteri olan an karakterini sabit olarak 3 biimde de yazabiliriz.
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 sabiti eklinde ifade
edersek hangi sistem olursa olsun an sesi karakterini verecektir. Ayrca kodu okuyan kii
an sesi karakterinin 7 numaral ASCII karakteri olduunu bilmeyebilir ama C programcs
olarak '\a' nn an sesi karakteri olduunu bilecektir.
Karakter sabitleri konusunu kapatmadan nce karakter setleri konusunda da biraz bilgi
verelim:
Gnmzde kullanlan en popler karakter seti ASCII karakter setidir. ASCII (American
Standard Code for Information Interchange) szcklerinin baharflerinden oluan bir
ksaltmadr. ASCII setinin orjinal versiyonunda karakterler 7 bitlik bir alanda kodlanmtr. Baz
bilgisayarlar ise 8 bit alana geniletilmi ASCII seti kullanrlar ki bu sette 128 yerine 256
karakter temsil edilebilmektedir. Farkl bilgisayarlar farkl karakter setleri kullanabilmektedir.
rnek olarak IBM mainframe'leri daha eski bir set olan EBCDIC seti kullanrlar. Unicode ismi
verilen daha gelitirilmi bir karakter seti vardr ki karakterler 2 byte alanda temsil edildikleri
iin bu sette 65.536 farkl karakter yer alabilmektedir. Gelecekte bir ok makinann bu karakter
setini destekleyecek biimde tasarlanaca dnlmektedir.
35
5
Yukardaki hepsi geerli birer uzun tamsay (unsigned long int) sabittir.
Sabitler yukarda gsterildii gibi her say sisteminde de yazlabilir, hatta bir ifade iinde
kullanlan sabitler farkl say sistemlerinde de yazlm olabilirler, bu derleme zamannda error
oluturacak bir neden olmayp tamamen legaldir.
...
36
SABTLER
37
6 . BLM : FONKSYONLAR
C'de alt programlara fonksiyon denir. Fonksiyon szc burada matematiksel anlamyla deil
dier programlama dillerinde kullanlan, "alt program", "prosedr", "subroutine" szcklerinin
karl olarak kullanlmaktadr.
Fonksiyonlar C dilinin temel yap talardr. altrlabilen bir C program en az bir C
fonksiyonundan oluur. Bir C programnn oluturulmasnda fonksiyon saysnda bir kstlama
yoktur.
Fonksiyonlarn onlar aran fonksiyonlardan aldklar girdileri ve yine onlar aran
fonksiyonlara gnderdikleri ktlar vardr. Fonksiyonlarn girdilerine aktel parametreler
(actual parameters) ya da argumanlar (arguments) diyoruz. Fonksiyonlarn ktlarna geri
dn deeri (return value) diyoruz.
Bir fonksiyon iki farkl amala kullanlabilir :
1. Fonksiyon, icras sresince belli amalar gerekletirir. (Belli ilemleri yapar)
2. Fonksiyon icras sonunda retecei bir deeri kendisini aran fonksiyona gnderebilir.
38
FONKSYONLAR
3. Baz fonksiyonlar kendilerine gnderilen argumanlar belirli bir kritere gre test ederler.
rettikleri geri dn deerleri ise test sonucunu belirtir. rnein:
Burada isalpha fonksiyonu arguman olarak gnderilen karakterin bir harf karakteri olup
olmadn test eder. Eer harf karakteriyse, isalpha fonksiyonu 0 d bir deere geri
dnecek, eer harf karakteri deilse 0 deerine geri dnecektir. aran fonksiyonda da
geri dn deerine gre farkl ilemler yaplabilecektir.
4. Baz fonksiyonlar hem belli bir amac gerekletirirler hem de buna ek olarak amalarn
tamamlayan bir geri dn deeri retirler. rnein :
Burada printf fonksiyonu ekrana Merhaba Dnya yazsn yazmak iin kullanlmtr. Ancak
ekrana yazd karakter saysn da geri dn deeri olarak vermektedir.
Bir yaz iersinde bulunan belirli bir karakteri silecek bir fonksiyon tasarladmz
dnelim. Fonksiyon iini bitirdikten sonra yazdan ka karakter silmi olduunu geri
dn deeri ile arld yere bildirilebilir.
5. Bazen geri dn deerlerine ihtiya duyulmaz. rnein yalnzca ekran silme amacyla
tasarlanm olan bir fonksiyonun geri dn deerine sahip olmas gereksizdir.
clrscr fonksiyonu yalnzca ekran siler, byle bir fonksiyonun geri dn deerine ihtiyac
yoktur.
Fonksiyonlarn geri dn deerlerinin de trleri sz konusudur. Fonksiyonlarn geri dn
deerleri herhangi bir trden olabilir. Geri dn deerlerinin trleri fonksiyonlarn
tanmlanmas srasnda belirtilir.
Fonksiyonlarn Tanmlanmas
Kendi yazdmz fonksiyonlar iin tanmlama (definition) terimini kullanyoruz. C'de fonksiyon
tanmlama ileminin genel biimi yledir:
[Geri dn deerinin tr] <fonksiyon ismi> ([parametreler])
{
...
...
}
Yukardaki gsterimde asal parantez iinde belirtilen ifadeler zorunlu olarak bulunmas
gerekenleri keli parantez iinde belirtilen ifadeler ise bulunmas zorunlu olmayan, istee
bal (optional) ifadeleri gstermektedir. Tanmlanan fonksiyonlar en az bir blok ierirler. Bu
bloa fonksiyonun ana blou denir. Ana blok iinde istenildii kadar iie blok yaratlabilir.
Aadaki fonksiyon tanmlamasndan fonk1 fonksiyonunun parametre almadn ve geri dn
deerinin de double trden olduunu anlyoruz.
double fonk1()
{
...
...
Fonksiyonun ana blou
...
}
39
6
1. Fonksiyon parametre parantezinin ii bo braklr, yani buraya hibirey yazlmaz.
2. Fonksiyon parametre parantezinin iine void anahtar szc yazlr.
Yukardaki tanmlamalar C'de ayn anlama gelmiyor. Fonksiyon prototipleri konusunu
renirken bu iki tanmlama arasndaki fark da renmi olacaz. imdilik bu iki tanmlamann
ayn anlama geldiini ve fonksiyonun parametre almadn belirttiklerini varsayacaz.
Geri dn deerine ihtiya duyulmad durumlarda da geri dn deerinin tr yerine void
anahtar szc yerletirilir. rnein:
Yukarda tanmlanan sample fonksiyonu parametre almamakta ve bir geri dn deeri de
retmemektedir.
Fonksiyon tanmlarken geri dn deeri yazlmayabilir. Bu durum geri dn trnn olmad
anlamna gelmez. Eer geri dn deeri yazlmazsa, C derleyicileri tanmlanan fonksiyonun int
trden bir geri dn deerine sahip olduunu varsayarlar. rnein :
Tanmlanan sample2 fonksiyonunun parametresi yoktur ama int trden bir geri dn deeri
vardr.
C dilinde fonksiyon iinde fonksiyon tanmlanamaz!
rnein aadaki durum error oluturur, nk sample2 fonksiyonu sample1 fonksiyonunun
iinde tanmlanmtr:
tanmlamann aadaki ekilde yaplmas gerekirdi :
Fonksiyonlarn geri dn deerleri nesne deildir yani sol taraf deeri (L value) deildir. Yani
C dilinde aadaki gibi bir atama her zaman hata verecektir:
Fonksiyonlarn geri dn deerleri sa taraf deeri (R value) dir.
gibi bir ifade geerlidir. arlm olan hesapla1 ve hesapla2 fonksiyonlar icra edilerek retilen
geri dn deerleri ile x deikeni iindeki deer ve 10 sabiti toplanacaktr. fadeden elde
edilen deer sonu deikenine atanacaktr.
40
FONKSYONLAR
Standart C Fonksiyonlar
Standard C fonksiyonlar, C dilinin standarlatrlmasndan sonra, her derleyicide bulunmas
zorunlu hale getirilmi fonksiyonlardr. Yani derleyicileri yazanlar mutlaka standard C
fonksiyonlarn kendi derleyicilerinde tanmlamak zorundadrlar. Bu durum C dilinin
tanabilirliini (portability) artran ana faktrlerden biridir.
Bir fonksiyonun derleyiciyi yazanlar tarafndan tanmlanm ve derleyici paketine eklenmi
olmas, o fonksiyonun standart C fonksiyonu olduu anlamna gelmez. Derleyiciyi yazanlar
programcnn iini kolaylatrmak iin ok eitli fonksiyonlar yazarak derleyici paketlerine
eklerler. Ama bu tr fonksiyonlarn kullanlmas durumunda, oluturulan kaynak kodun baka
bir derleyicide derlenebilmesi ynnde bir garanti yoktur, yani artk kaynak kodun tanabilirlii
azalr. rnein printf fonksiyonu standart bir C fonksiyonudur. Yani printf fonksiyonu her
derleyici paketinde ayn isimle bulunmak zorundadr.
Standart C fonksiyonlar zel ktphanelerin ierisinde bulunurlar. Balk dosyalar iinde, yani
uzants .h biiminde olan dosyalarn iinde standart C fonksiyonlarnn prototipleri
bulunmaktadr. Fonksiyon prototipleri konusu ileride detayl olarak incelenecektir.
Ktphaneler (libraries) derlenmi dosyalardan oluur. DOS'da ktphane dosyalarnn uzants
.lib, UNIX'de ise .a (archive) biimindedir. WINDOWS altnda uzants .dll biiminde olan
dinamik ktphaneler de bulunmaktadr.
Derleyicileri yazanlar tarafndan kaynak kodu yazlm standart C fonksiyonlar nce derlenerek
.obj haline getirilirler ve daha sonra ayn gruptaki dier fonksiyonlarn .obj halleriyle birlikte
ktphane dosyalarnn iine yerletirilirler. Standart C fonksiyonlar balama aamasnda,
balayc (linker) tarafndan alabilir (.exe) kod ierisine yazlrlar. Entegre alan
derleyicilerde balayclar ama kod ierisinde bulamadklar fonksiyonlar, yerleri nceden
belirlenmi ktphaneler iinde ararlar. Oysa komut satrl uyarlamalarnda (command line
version) balayclarn hangi ktphanelere bakaca komut satrnda belirtilir.
Standart fonksiyonlarn kullanmak programlarn tanabilirliini artrd gibi proje gelitirme
sresini de ksaltr. Bu yzden iyi bir C programcsnn C dilinin standart fonksiyonlarn ok iyi
tanmas ve bu fonksiyonlar yetkin bir ekilde kullanabilmesi gerekmektedir.
Yukardaki rnekteki sample fonksiyonunda return anahtar szcnn yannda yer alan x * y
ifadesi sample fonksiyonunu sonlandrmakta ve sample fonksiyonunun geri dn deerini
oluturmaktadr. Fonksiyonun geri dn deeri, main fonksiyonu iinde c deikenine atanm
ve daha sonra standart C fonksiyonu olan printf ile c fonksiyonunun deeri ekrana
yazdrlmtr. fonksiyonun geri dn deerini baka bir deikene atamadan aadaki ifade
ile de dorudan ekrana yazdrabilirdik :
Ayn rnekte main fonksiyonu iinde de bir return ifadesinin yer ald grlmektedir. main de
bir fonksiyondur ve main fonksiyonunun da bir geri dn deeri olabilir. main fonksiyonun geri
dn deeri programn icras bittikten sonra iletim sistemine bildirilmektedir. main
fonksiyonunun bana bir geri dn deer tr yazlmazsa derleyiciler main fonksiyonunun
geri dn deerinin int trden olduunu varsayarlar. zellikle yeni derleyiciler,
tanmlamalarnda bir geri dn deeri retecekleri belirtilen fonksiyonlarnn, return anahtar
szcyle geri dn deeri retmemelerini bir uyar (warning) mesaj ile bildirirler. Borland
derleyicilerinde bu uyar mesaj genellikle "warning : function should return a value..."
eklindedir. Bu uyar mesajn kesmek iin iki yol vardr:
1. main fonksiyonu da yukardaki rnekte olduu gibi int trden bir geri dn deeri retir.
Geleneksel olarak bu deer 0 ise programn problemsiz bir ekilde sonlandrld anlamna
gelir.
2. main fonksiyonunun bana void anahtar szc yazlarak bu fonksiyonun bir geri dn
deeri retmeyecei derleyiciye bildirilir. Bu durumda derleyici geri dn deeri
beklemedii iin bir uyar mesaj gndermez.
return anahtar szcnn kullanlmas zorunlu deildir. Bir fonksiyon iinde return anahtar
szc kullanlmamsa fonksiyonun icras, fonksiyonun ana blounun sonuna gelindiinde
otomatik olarak biter. Tabi bu tr bir fonksiyon anlaml bir ekilde bir geri dn deeri
retemeyecektir. Bir geri dn deerine sahip olacak ekilde tanmlanm fakat return ile geri
dn deeri oluturulmam fonksiyonlar rastgele bir deer dndrrler.
return anahtar szcnden sonra parantez kullanlabilir ama parantez kullanm zorunlu
deildir. Okunabilirlik asndan zellikle uzun return ifadelerinde parantez kullanm tavsiye
edilmektedir.
return (a * b - c * d);
return 5;
return sample();
Bu rnekte return anahtar szcnden sonra bir fonksiyon arma ifadesi yer almaktadr. Bu
durumda nce arlan fonksiyon icra edilir, ve geri dn deeri elde edilir, daha sonra elde
edilen geri dn deeri tanmlanmas yaplan fonksiyonun da geri dn deeri yaplmaktadr.
Geri dn deeri olmayan fonksiyonlarda return anahtar
olmakszn tek bana da kullanlabilir :
return;
Bu durumda return iinde yer ald fonksiyonu geri dn deerini oluturmadan sonlandrr.
C dilinde fonksiyonlar yalnzca bir geri dn deeri retebilirler. Bu da fonksiyonlarn
kendilerini aran fonksiyonlara ancak bir tane deeri geri gnderebilmeleri anlamna
gelmektedir. Ancak, fonksiyonlarn birden fazla deeri ya da bilgiyi kendilerini aran
42
FONKSYONLAR
fonksiyonlara iletmeleri gerekiyorsa, C dilinde bunu salayacak baka mekanizmalar vardr ve
bu mekanizmalar ileride detayl olarak incelenecektir.
Fonksiyonlarn rettii geri dn deerlerinin kullanlmas ynnde bir zorunluluk yoktur.
rnein fonk() fonksiyonu int trden bir deeri geri dnen bir fonksiyon olsun:
a = fonk();
yukardaki ifadese fonk fonksiyonunun geri dn deeri a deikenine atanmaktadr.
Dolaysyla biz bu fonksiyonu bir kez armamza karn artk geri dn deerini a
deikeninede tuttuumuz iin, bu geri dn deerine fonksiyonu tekrar armadan
istediimiz zaman ulaabiliriz. Ancak:
fonk();
eklinde bir fonksiyon arma ifadesinde artk geri dn deeri bir deikende
saklanmamakatdr. Bu duruma geri dn deerinin kullanlmamas denir. (discarded return
value).
rnein standart bir C fonksiyonu olan printf fonksiyonun da bir geri dn deeri vardr (printf
fonksiyonu ekrana bastrlan toplam karakter saysna geri dner) ama bu geri dn deeri
nadiren kullanlr.
...
/* error */
getchar Fonksiyonu
int getchar(void);
44
FONKSYONLAR
getchar standart bir C fonksiyonudur. Geri dn deeri klavyeden alnan karakterin ASCII
tablosundaki sra numarasn gsteren int trden bir saydr. getchar fonskiyonu klavyeden
karakter almak iin enter tuuna ihtiya duyar.
Aada yazlan programda nce klavyeden bir karakter alnm daha sonra alnan karakter ve
karakterin saysal karlklar ekrana yazdrlmtr. (getchar fonksiyonunun geri dn deeri
klavyede baslan tua ilikin karakterin sistemde kullanlan karakter seti tablosundaki sra
numarasdr.)
#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 dosyasnda bir makro olarak tanmlanmtr. Makrolar
konusunu daha ileride inceleyeceiz.
getch Fonksiyonu
int getch(void);
getchar fonksiyonu gibi bu fonksiyonda klavyede baslan tuun kullanlan karakter setindeki
sra numarasyla geri dner. getchar fonksiyonundan iki fark vardr.
1. Baslan tu ekranda grnmez.
2. Enter tuuna ihtiya duymaz.
Yukarda verilen programda getchar yerine getch yazarak program altrrsanz fark daha iyi
grebilirsiniz.
Tam olarak standardize edilmemitir ama neredeyse btn sistemlerde bulunur. getch
fonksiyonu zellikle tu bekleme ya da onaylama amacyla kullanlmaktadr:
....
printf("devam iin herhangi bir tua basnz...\n");
getch();
Burada baslacak tuun programc asndan bir nemi olmad iin fonksiyonun geri dn
deeri kullanlmamtr.
getche Fonksiyonu
int getche(void);
getche ngilizce get char echo szcklerinden gelmektedir. getche fonksiyonu da baslan tuun
karakter setindeki sra numarasyla geri dner ve enter tuuna gereksinim duymaz. Ama
baslan tua ilikin karakter ekranda grnr.
getchar
getch
getche
45
putchar Fonksiyonu
int putchar(int ch);
putchar standart bir C fonksiyonudur. Btn sistemlerde bulunmas zorunludur. Parametresi
olan karakteri ekranda imlecin bulunduu yere yazar. rnein:
#include <stdio.h>
main()
{
char ch;
ch = getchar();
putchar (ch);
return 0;
}
Burada putchar fonksiyonunun yapt ii printf fonksiyonuna da yaptrabilirdik;
printf("%c", ch);
putchar(ch) ile tamamen ayn ileve sahiptir.
putchar fonksiyonu ile '\n' karakterini yazdrdmzda printf fonksiyonunda olduu gibi imle
sonraki satrn bana geer. putchar fonksiyonu ekrana yazlan karakterin ASCII karl ile
geri dnmektedir.
putchar fonksiyonu derleyicilerin ounda stdio.h dosyas iinde bir
tanmlanmtr. Makrolar konusunu ileriki derslerde detayl olarak reneceiz.
makro
olarak
putch Fonksiyonu
int putch(int ch);
putch standart bir C fonksiyonu deildir. Dolaysyla sistemlerin hepsinde bulunmayabilir. Bu
fonksiyonun putchar fonksiyonundan tek fark '\n' karakterinin yazdrlmas srasnda ortaya
kar. putch, '\n" karakterine karlk yalnzca LF(line feed) (ASCII 10) karakterini yazmaktadr.
Bu durum imlecin bulunduu kolonu deitirmeksizin aa satra gemesine yol aar.
printf Fonksiyonu
Deikenlerin ierisindeki deerler aslnda bellekte ikilik sistemde tutulmaktadr. Bir deikenin
ierisindeki deerin ekrana, kalk sistemde ve nasl yazdrlaca programcnn isteine
baldr. Deikenlerin ierisindeki deerlerin ekrana yazdrlmasnda printf fonksiyonu
kullanlr. printf standart bir C fonksiyonudur.
printf aslnda ok ayrntl zelliklere sahip bir fonksiyondur. Burada yalnzca temel zellikleri
grsel bir biimde aklanacaktr. printf iki trnak ierisindeki karakterleri ekrana yazar. Ancak
iki trnak iinde grd % karakterlerini ekrana yazmaz. printf fonksiyonu % karakterlerini
yanndaki karakter ile birlikte format karakteri olarak yorumlar. Format karakterleri iki
trnaktan sonra yazlan parametrelerle birebir eletirilir. rnek:
int x, y;
46
FONKSYONLAR
x = 125;
y = 200;
printf("x = %d\ny = %d\n", x, y);
printf fonksiyonunun yukardaki ekilde arlmasyla x ve y deikeni iindeki deerler ekrana
onluk sistemde yazdrlacaktr.
Format karakterleri yerine elenen deikenlerin ierisindeki deerler ekrana yazlr. Format
karakterleri saylarn ekrana nasl yazlacan belirtmekte kullanlr.
format
karakteri
Anlam
%d
%ld
%x
%X
%lx
%u
%o
%f
%lf
%e
%c
%s
%lf
Yukardaki tabloda grld gibi double tr hem %f format karakteri hem de %lf format
karakteri ile yazdrlabilmektedir. Ama %lf (okunabilirilii artrd iin) daha ok tercih
edilmektedir.
Yukardaki tabloya gre unsigned int trnden bir sayy aadaki ekillerde yazdrabiliriz :
unsigned int u;
printf("%u", u);
printf("%o, u);
printf("%x, u);
Yukardaki bilgilerde unsigned bir tamsayy printf fonksiyonuyla 8'lik ya da 16'lk sistemde
yazdrabileceimizi grdk. Peki signed bir tamsayy 8'lik ya da 16'lk sistemde yazdramaz
myz? Yazdrrsak ne olur? Szkonusu signed tamsay pozitif olduu srece bir sorun olmaz.
Saynn iaret biri 0 olduu iin saynn nicel bykln etkilemez. Yani doru say ekrana
yazar, 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
olmayacaktr.
% karakterinin yannda nceden belirlenmi bir format karakteri yoksa , % karakterinin
yanndaki karakter ekrana yazlr.
%% (%) karakterini yaz anlamna gelir.
scanf Fonksiyonu
scanf fonksiyonu klavyeden her trl bilginin giriine olanak tanyan standart bir C
fonksiyonudur. scanf fonksiyonu da printf fonksiyonu gibi aslnda ok detayl, geni kullanm
zellikleri olan bir fonksiyondur. Ancak biz bu noktada scanf fonksiyonunu yzeysel bir ekilde
tanyacaz.
scanf fonksiyonunun da birinci parametresi bir stringdir. Ancak bu string klavyeden alnacak
bilgilere ilikin format karakterlerini ierir. Bu format karakterleri nceden belirlenmitir ve %
karakterinin yannda yer alrlar. scanf fonksiyonunun kulland format karakterlerinin printf
fonksiyonunda kullanlanlar ile ayn olduunu syleyebiliriz. Yalnzca gerek saylara ilikin
format karakterlerinde nemli bir farkllk vardr. printf fonksiyonu %f format ile hem float
hem de double trden verileri ekrana yazabilirken scanf fonksiyonu %f format karakterini
yalnzca float trden veriler iin kullanr. double tr iin scanf fonksiyonunun kulland format
karakterleri %lf eklindedir. scanf fonksiyonunun format ksmnda format karakterlerinden
baka bir ey olmamaldr. printf fonksiyonu ift trnak iindeki format karakterleri dndaki
karakterleri ekrana yazyordu, ancak scanf fonksiyonu format karakterleri dnda string iine
yazlan karakterleri ekrana basmaz, bu karakterler tamamen baka anlama gelecektir. Bu
nedenle fonksiyonun nasl altn renmeden bu blgeye format karakterlerinden baka bir
ey koymaynz. Buraya konulacak bir boluk bile farkl anlama gelmektedir.
int x, y;
scanf(%d%d, &x, &y);
Yukardaki rnekte x ve y saylar iin desimal sistemde klavyeden giri yaplmaktadr. Giri
arasna istenildii kadar boluk karakteri konulabilir. Yani ilk sayy girdikten sonra ikinci sayy
SPACE, TAB ya da ENTER tuuna bastktan sonra girebilirsiniz. rnein:
5
60
48
FONKSYONLAR
scanf fonksiyonunun yalnzca giri iin kullanlr, ekrana yazmak iin printf fonksiyonunu
kullanmamz gerekir :
int number;
printf(bir sayi giriniz : );
scanf(%d, &number);
C++ dilinde bir fonksiyon tanmlanmasnda fonksiyonun geri dn deerinin tr olarak void
anahtar szc yazlmamsa, fonksiyon return anahtar szc kullanlarak mutlaka bir geri
dn deeri retmelidir. Fonksiyonun geri dn deeri retmemesi durumunda derleme
zamannda hata oluacaktr. Yani C dilinde olduu gibi rasgele bir deer retilmesi sz konusu
deildir. Yine C++ dilinde geri dn deeri retecek bir fonksiyonun tanmlanmas iinde
return anahtar szc yaln olarak kullanlamaz. return anahtar szcnn yannda
mutlaka bir ifade yer almaldr.
49
Bloklarn ilerinde tanmlanan deikenlere yerel deikenler denir. Hatrlanaca gibi C dilinde
bloklarn ilerinde tanmlanan deikenlerin tanmlama ilemleri blok iinde ilk ilem olarak
yaplmalyd. (C++ dilinde byle bir zorunluluk yoktur) Yerel deikenler blok ilerinde
tanmlanan deikenlerdir, i ie bloklarn sz konusu olmas durumunda hangi blok ierisinde
tanmlanrlarsa tanmlansnlar bunlar yerel deiken olarak adlandracaz. Yani yerel deiken
olmalar iin en d blok iinde tanmlanmalar gerekmiyor.
Yerel deikenlerin tannabilirlik alan blok tannabilirlik alandr. Yani yerel deikenlere
yalnzca tanmlandklar blok iinde ulalabilir. Tanmlandklar bloun daha dnda bir blok
iinde bu deikenlere ulaamayz. rnek :
main ()
{
float x;
...
...
{
int y;
...
...
{
int z;
...
...
}
}
}
50
{
long z = 5;
}
}
C dilinde ayn isimli birden fazla deiken tanmlanabilmektedir. Genel kural udur: iki
deikenin scoplar (tannabilirlik alanlar ayn ise) ayn isimi tayamazlar, ayn isim altnda
tanmlanmalar derleme zamannda hata oluturur. ki deikenin scoplarnn ayn olup
olmadklar nasl tespit edilecek? Standartlar bu durumu yle aklamaktadr : ki deikenin
scoplar ayn kapanan kme parantezinde sonlanyorsa, bu deikenlerin scoplar ayn
demektir.
{
float a;
int b;
double a;
{
int c;
...
}
/* error */
}
Yukardaki program parasnn derlenmesi derleme aamasnda error ile neticelenir. nk her
iki a deikeninin de tannabilirlik alan (scoplar) ayndr. (scoplar ayn kme paranteziyle
sonlanmaktadr.)
51
printf(%d\n, x);
}
{
int a;
char ch;
long b;
double a, f; /* hata ayn tannabilirlik alannda ve ayn blok seviyesinde ayn isimli iki
deiken tanmlanm */
int var1;
char var2;
{
int var1;
char var2;
}
Yukardaki kodda herhangi bir hata bulunmamaktadr. var1 ve var2 deikenlerinin ismi ikinci
kez iteki blokta tanmlama ileminde kullanlmtr ama artk bu tannabilirlik alannda farkllk
yaratan ayr bir bloktur, dolaysyla bir hata sz konusu deildir.
52
void sample1(void)
{
int k;
...
}
void sample2(void)
{
int k;
...
}
void sample3(void)
{
int k;
...
}
Yukardaki kodda da bir hata sz konusu deildir. Zira her fonksiyonunda da k isimli bir
deiken tanmlanm olsa da bunlarn tannabilirlik alanlar tamamen birbirinden farkldr.
7
fonksiyonlarn iinde tannabilirler. Burada bir noktay gzden karmamak gerekir, bir deiken
yerel de olsa global de olsa tanmlamas yaplmadan nce bu deikene ulalamaz. Derleme
ileminin bir yn vardr ve bu yn kaynak kod ierisinde yukardan aaya dorudur. Bunu u
ekilde de ifade edebiliriz : Global deikenler tanmlandklar noktadan sonra kaynak kod
ierisinde her yerde tannabilirler.
#include <stdio.h>
int y;
void sample(void)
{
y = 10;
}
void main()
{
y = 20;
printf(y = %d\n, y);
sample();
printf(y = %d\n, y);
/* y = 20
/* y = 10
*/
*/
}
Yukardaki rnekte y deikeni tm bloklarn dnda tanmland iin (ya da hibir fonksiyonun
iinde tanmlanmad iin) global deikendir. y deikeninin tannabilirlik alan dosya
tannabilirlik alandr. yani y deikeni tanmlandktan sonra tm fonksiyonlarn iinde
tannabilir. Yukardaki programn almas main fonksiyonundan balayacaktr. y global
deikenine nce 20 deeri atanmakta ve daha sonra bu deer printf fonksiyonuyla ekrana
yazdrlmaktadr. Daha sonra sample fonksiyonu arlmtr. sample fonksiyonu arlnca
kodun ak sample fonksiyonuna geer. sample fonksiyonu iinde de y global deikeni
tannabilir. sample fonksiyonunda global y deikenine 10 deeri atanmakta ve daha sonra bu
deer yine printf fonksiyonuyla ekrana yazdrlmaktadr.
Peki bir global deikenle ayn isimli yerel bir deiken olabilir mi? Kesinlikle olabilir! ki
deikenin tannabilirlik alanlar ayn olmad iin bu durum bir hataya neden olmaz. Ayn
isimli hem global hem de yerel bir deikene ulalabilecek bir noktada, ulalan yerel deiken
olacaktr, nk daha nce de sylediimiz gibi ayn tannabilirlik alannda birden fazla ayn
isimli deiken olmas durumunda o alan iinde en dar tannabilirlik alanna sahip olanna
eriilebilir. Aadaki kodu ok dikkatli inceleyelim :
int g= 20;
void sample(void)
{
g = 100;
printf(global g = %d\n, g);
}
int main()
{
int g;
g = 200;
printf(yerel g = %d\n, g);
sample();
printf(yerel g = %d\n, g);
return 0;
/* g yerel deiken */
/* yerel olan g deikenine atama yaplyor */
/* yerel g yazdrlyor. */
/* yerel g yazdrlyor. */
54
55
7
global deikenler
stringler(iki trnak ierisndeki ifadeler)
statik yerel deikenler
stringler ve statik yerel deikenleri daha sonra inceleyeceiz.
statik mrl nesneler olan global deikenlerin mrleri konusunda unlar syleyebiliriz :
Global deikenler programn almas sresince yaayan, yani programn almas sresince
bellekte yer igal eden deikenlerdir.
ayrlyor. ve
56
/* legal */
/* error! ilk deer verme ileminde sabit ifadesi kullanlmam */
/* error! ilk deer verme ileminde funksiyon arma ifadesi var */
int main()
{
int a = b;
int k = b - 2;
/* legal, k yerel deiken olduu iin ilk deer verme ifadesi deiken
ierebilir */
int l = funk()/* legal, k yerel deiken olduu iin ilk deer verme ifadesinde fonksiyon
arma i
fadesi bulunabilir. */
...
}
int funk()
{
...
}
58
8 . BLM : OPERATRLER
Operatrler nesneler veya sabitler zerinde nceden tanmlanm birtakm ilemleri yapan
atomlardr. Operatrler mikroilemcinin bir ilem yapmasna neden olurlar ve bu ilem sonunda
da bir deer retilmesini salarlar. Programlama dillerinde tanmlanm olan her bir operatr
en az bir makine komutuna karlk gelmektedir.
Benzer ilemleri yapmalarna karlk programlama dillerinde operatr atomlar birbirlerinden
farkllk gsterebilir.
C programlama dilinde her ifade en az bir operatr ierir. (Sabitler, nesneler ve operatrlerin
kombinezonlarna ifade denir.)
c=a*b/2+3
++x * y-a >= b
Her programlama dilinde operatrlerin birbirlerine gre ncelii sz konusudur. (Eer ncelik
kavram sz konusu olmasayd, operatrlerin neden olaca ilemlerin sonular makinadan
makinaya, derleyiciden derleyiciye farkl olurdu.)
C' de toplam 45 operatr vardr, ve bu operatrler 15 ayr ncelik seviyesinde yer alr. (baknz
operatr ncelik tablosu) . Bir ncelik seviyesinde eer birden fazla operatr varsa bu
operatrlerin soldan saa m sadan sola m ncelikle dikkate alnaca da tanmlanmaldr.
Buna ncelik yn diyebiliriz. (associativity)
Bir sembol, birden fazla operatr olarak kullanllabilmektedir. rnein * operatr hem
arpma hem de ierik alma operatr (gstericilerle ilgili bir operatr) olarak kullanlr. Yine bir
C dilinde &(ampersand) hem bitsel ve hem de gstericilere ilikin adres operatr olarak
kullanlmaktadr. Operatr ncelik listesinde grdmz operatrlerin ounu bu ders
tanyacaz ama bir ksm ileriki derslerimizde yer alacak. (rnein gsterici operatrleri)
Operatr Terminolojisi
Hem operatrler konusunun daha iyi anlalmas hem de ortak bir dil oluturmak amacyla
operatrler hakknda kullanabileceimiz terimleri inceleyelim.
Operand
Operatrlerin deer zerinde ilem yaptklar nesne veya sabitlere denir. C'de operatrleri
aldklar operand saysna gre 3 gruba ayrabiliriz.
1. Tek Operand Alan Operatrler (unary operators)
rnein ++ ve -- operatrleri unary operatrlerdir. (C dilinde unary operatrler
operatrncelik tablosunun 2. seviyesinde bulunurlar.)
2. ki Operand Alan Operatrler. (binary operators)
Aritmetik ilem operatr olan + ve / operatrlerini rnek olarak verebiliriz.
3. Operand Alan Operatr (ternary operator)
oul kullanmyoruz nk C'de 3 opererand olan tek bir operatr vardr. (koul operatr
- conditional operator)
Operatrleri operandnn ya operandlarnn neresinde bulunduklarna gre de gruplayabiliriz:
1. Sonek Konumundaki Operatrler (postfix operators)
Bu tip operatrler operandlarnn arkasna getirilirler. rnein sonek ++ operatr (x++)
59
8
2. nek Konumundaki Operatrler (prefix operators)
Bu tip operatrler operandlarnn nne getirilirler.
rnein nek ++ operatr (++x)
Operatr
Tanm
()
[]
.
->
+
++
-~
!
*
&
sizeof
(tr)
*
/
%
+
<<
>>
<
>
<=
>=
==
!=
&
^
|
&&
||
?:
=
+=
-=
*=
/=
%=
<<=
>>=
&=
|=
^=
,
3
4
5
6
7
8
9
10
11
12
13
14
15
60
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
8
Son olarak operatrleri yaptklar ilere gre snflayalm :
1.
2.
3.
4.
5.
6.
lk 3 grup programlama dillerinin hepsinde vardr. Bitsel ilem yapan operatrler ve gsterici
operatrleri yksek seviyeli programla dillerinde genellikle bulunmazlar. Programlama
dillerinden ou, kendi
uygulama alanlarnda kolaylk salayacak birtakm zel amal
operatrlere de sahip olabilir.
Operatrlerin en nemli zellikleri bir deer retmeleridir. Operatrlerin ana ilevi bir deer
retmeleridir. Programc, bir ifade iinde operatrlerin rettii deeri kullanr ya da kullanmaz.
(discard edebiliriz.) Operatrlerin rettii deeri nasl kullanabiliriz:
retilen deeri baka bir deikene aktararak kullanabiliriz.
x = y + z;
Yukardaki rnekte y + z ifadesinin deer, yani + operatrnn rettii deer x deikenine
aktarlmaktadr.
retilen deeri baka bir fonksiyona arguman olarak gnderebiliriz.
func(y + z);
Yukardaki rnekte func fonksiyonuna arguman olarak y + z ifadesinin deeri gnderilmektedir.
(Yani + operatrnn rettii deer)
retilen deeri return anahtar
belirlenmesinde kullanabiliriz.
szc
ile
fonksiyonlarn
geri
dn
deerlerinin
int sample(void)
{
...
return (y + z)
}
yukarda sample fonksiyonunun geri dn deeri y + z ifadesinin deeridir. (Yani +
operatrnn rettii deer)
Operatrlerin elde ettii deerin hi kullanlmamas C sentaks asndan bir hataya neden
olmaz. Ancak byle durumlarda derleyiciler bir uyar mesaj vererek programcy uyarrlar.
rnein :
int x = 20;
int y = 10;
...
x + y;
Yukardaki ifadede + operatr bir deer retir. (+ operatrnn rettii deer operandlarnn
toplam deeri, yani 20 deeridir.) Ancak bu deer hibir ekilde kullanlmamtr. Derleyici
byle bir ilemin byk ihtimalle yanllkla yapldn dnecek ve bir uyar mesaj verecektir.
Borland derleyicilerinde verilen uyar mesaj u ekildedir :
61
8
warning : "code has no effect!"
Daha nce belirttiimiz gibi C dilinde ifadelerin trleri ve deerleri sz konusudur. Bir ifadenin
deerini derleyici u ekilde tespit eder : fade iindeki operatrler ncelik sralarna gre deer
retirler, ve rettikleri deerler, ifade iindeki ncelii daha az olan operatrlere operand
olarak aktarlr. Bu ilemin sonunda tek bir deer elde edilir ki bu da ifadenin deeridir.
int x = 10;
int y = 3;
printf("%d\n", x % y / 2 + 7 && !x || y);
Yukardaki kod parasnda printf fonksiyonu armyla x % y / 2 + 7 && !x || y ifadesinin
deeri yazdrlmaktadr. Yazdrlacak deer nedir? ifade iindeki operatrler srayla deer
retecek ve retilen deerler ncelik srasna gre, deer retecek operatrlere operand
olacaktr. En son kalan deer ise ifadenin deeri, yani ekrana yazdrlan deer olacaktr.
62
x bir nesne olmasna kar x ifadesi bir nesne deil, x nesnesinin deerinin ters iaretlisi olan
deerdir. Dolaysyla bir sol taraf deeri deildir ve bu ifadeye bir atama yaplamaz.
+ operatr yalnzca sentaks asndan C diline ilave edilmi bir operatrdr. Unary prefix bir
operand olarak derleyici tarafndan ele alnr. Operand olan ifade zerinde herhangi bir etkisi
olmaz.
Unary prefix olan ve + operatrleri operatr ncelik tablosunun 2. seviyesinde bulunurlar ve
ncelik ynleri sadan sola dorudur. Aadaki ifadeyi ele alalm :
int x = 5;
int y = -2;
-x - -y;
Yukardaki ifadede 3 operatr bulunmaktadr. Srasyla unary prefix operatr, binary infix
karma operatr ve yine unary prefix - operatr. fadenin deerinin hesaplanmasnda
operatr nceliklerine gre hareket edilecektir. unary prefix olan operatr 2. ncelik
seviyesinde olduu iin binary infix olan karma operatrne gre daha yksek nceliklidir, ve
kendi iinde ncelik yn sadan soladr. nce y ifadesi deer retir. retilen deer 2
olacaktr. daha sonra x ifadesi deer retir. retilen deer 5 olacaktr. retilen bu deerler
karma operatrne operand olurlar ve ana ifadenin deeri 5 2 yani 7 deeri olarak
hesaplanr.
* ve / Operatrleri
ki operand alan araek operatrlerdir. (binary infix) * operatr operandlar arpmak / ise
operandlar blmek amacyla kullanlr. Yani retilen deer operandlarnn arpm ya da blm
deerleridir. Operandlar herhangi bir trden olabilir. ncelik tablosunda grlebilecei gibi,
genel ncelik tablosunun 3. srasnda bulunurlar. ncelik ynleri soldan saadr. Her iki
operatrn de bir yan etkisi yoktur.
/ operatrnn kullanmnda dikkatli olmak gerekir. Eer her iki operand da tamsay
trlerindense operatrn bulunduu ifadenin tr de ayn tamsay trnden olacaktr. (Bu
konuya ileride detayl deineceiz.)
C programlama dilinde * sembol ayn zamanda bir gsterici operatr olarak da kullanlr.
Ama ayn sembol kullanlmasna karn bu iki operatr hibir zaman birbirine karmaz nk
aritmetik arpma operatr olarak kullanldnda binary infix durumundadr, ama gsterici
operatr olarak kullanldnda unary prefix dir.
% (modulus) Operatr
ki operand alan araek bir operatrdr. (binary infix) Operatrlerin her ikisinin de tr de
tamsay trlerinden (char, short, int, long) biri olmak zorundadr. (Deilse bu durum derleme
zamannda error ile neticelenir.) rettii deer sol tarafndaki operandn sa tarafndaki
operanda blmnden kalandr. Operatrn yan etkisi yoktur. rnein:
c = 15 % 4;
int c = 13 - 3 * 4 + 8 / 3 - 5 % 2;
Burada c'ye 2 deeri atanacaktr. nk ilem u ekilde yaplmaktadr:
c = 13 - (3 * 4) + (8 / 3) - (5 % 2)
c = 13 - 12 + 2 - 1;
c = 2;
Artrma ++ ve Eksiltme -- Operatrleri (increment and decrement operators)
63
8
Artrma (++) ve eksiltme (--) operatrleri C dilinde en ok kullanlan operatrlerdendir. Tek
operand alrlar. nek ya da sonek durumunda bulunabilirler. ++ operatr operand olan
deikenin ieriini 1 artrmak - operatr de operand olan deikenin ieriini 1 eksiltmek
iin kullanlr. Dolaysyla yan etkileri sz konusudur. Operandlar olan nesnenin bellekteki
deerini deitirirler. Bu iki operatr de dier aritmetik operatrlerden daha yksek ncelie
sahiptir. Operatr ncelik tablosunun 2. seviyesinde bulunurlar ve ncelik ynleri sadan
soladr. (right associative)
Yaln olarak kullanldklarnda (baka hibir operatr olmakszn) nek ya da sonek durumlar
arasnda hibir fark yoktur. ++ bir artr ve - bir eksilt anlamna gelir.
++c ve c++ ifadeleri tamamen birbirine denk olup c = c + 1 anlamna gelirler.
--c ve c ifadeleri tamamen birbirine denk olup c = c 1 anlamna gelirler.
Dier operatrlerle birlikte kullanldklarnda (rnein atama operatrleriyle) nek ve sonek
biimleri arasnda farkllk vardr :
nek durumunda kullanldnda operatrn rettii deer artrma/eksiltme yapldktan sonraki
deerdir. Yani operandn artrlm ya da azaltlm deeridir. Sonek durumunda ise operatrn
rettii deer artrma / eksiltme yaplmadan nceki deerdir. Yani operand olan nesnenin
artrlmam ya da azaltlmam deeridir. Operandn deeri ifadenin tm deerlendirildikten
sonra artrlacak ya da eksiltilecektir.
x = 10;
y = ++x;
Bu durumda:
++x 11
ve y = 11 deeri atanr..
x = 10;
y = x++;
y = 10;
++x 11
Aadaki program inceleyelim:
int main()
{
int a, b;
a = 10;
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 ifadesi ekrana 11 11 yazdrrken ikinci printf ifadesi 11 10 yazdrr.
Bir rnek :
x = 10;
y = 5;
z = x++ % 4 * --y;
64
--y 4
10 % 4 2
2 * 4 8
z=8
x++ 11
Bir rnek daha:
c = 20;
d = 10;
a = b = d + c--;
lem sras:
10 + 20 30
b = 30
a = 30
c-- 19
fadenin sonunda deikenler:
a = 30, b = 30, c = 19, d = 10 deerlerini alrlar.
Fonksiyon arma ifadelerinde bir deiken postfix ++ ya da operatr ile kullanlmsa, ilk
nce fonksiyon artrlmam veya eksiltilmemi deiken ile arlr, fonksiyonun almas
bitince deiken 1 arttlr veya eksiltilir.
#include <stdio.h>
int func(int x)
{
printf(%d\n, x);
}
int main()
{
int a;
a = 10;
func(a++);
printf(%d\n, a);
return 0;
}
++ ve -- Operatrleriyle lgili pheli Kodlar (undefined behaviours)
++ ve operatrlerinin bilinsiz baz kullanmlar derleyiciler arasnda yorum farkllna yol
aarak tanabilirlii bozarlar. Byle kodlardan saknmak gerekir.
3 tane + (+++) ya da 3 tane (---) karakteri boluk olmakszn yan yana getirilmemelidir.
x = a+++b; /* pheli kod
*/
65
y = ++x + ++x;
y = ++x + x
a = ++a;
/* pheli kod */
/* pheli kod */
/* pheli kod */
void fonk(x, y)
{
...
}
66
8
Baz programlama dillerinde x = (a < b) + 1; gibi bir ilem hata ile sonulanr. nk rnein
Pascal dilinde a < b ifadesinden elde edilen deer True ya da False dir. (yani BOOL ya da
BOOLEAN trndendir.) Ama C doal bir dil olduu iin karlatrma operatrlerinin rettikleri
deeri Boolean tr ile kstlamamtr. Cde mantksal veri tr yerine int tr kullanlr.
Mantksal bir veri trnn tamsay tryle ayn olmas Cye esneklik ve doallk kazandrmtr.
Baka bir rnek :
x = y == z;
Yukardaki deyim C dili iin son derece doal ve okunabilir bir deyimdir. Bu deyimin icrasyla x
deikenine ya 1 ya da 0 deeri atanacaktr.
Karlatrma operatrnn kullanlmasnda baz durumlara dikkat etmemiz gerekmektedir.
rnein
int x = 12;
5>x>9
Yukardaki ifade matematiksel adan doru deildir. nk 12 deeri 5 ve 9 deerlerinin
arasnda deildir. Ancak ifade C asndan doru olarak deerlendirilir. nk ayn seviyede
olan iki operatre (> ve >) ilikin ncelik yn soldan saadr. nce soldaki > operatr deer
retecek ve rettii deer olan 0 sadaki > operatrne operand olacaktr. Bu durumda 0 > 9
ifadesi elde edilecek ve bu ifadeden de 0 yani yanl deeri elde edilecektir.
67
8
Deil operatr tek operand alr ve her zaman nek durumundadr. (unary prefix) ! operatr
operandnn mantksal deerini deitirir. Yani Doru deerini yanl deerini, yanl deerini de
Doru deerine dntrr:
x
Doru (0 d deer)
Yanl (0)
!x
Yanl (0)
Doru (1)
rnekler :
a = !25;
b = 10 * 3 < 7 + !2
lem sras:
!2 = 0
10 * 3 = 30
7+0=7
30 < 7 = 0
b = 0 (atama operatr en dk ncelikli operatrdr)
y = 5;
x = !++y < 5 != 8;
lem sras:
++y 6
!6 0
/* ++ ve ! operatrleri ayn ncelik seviyesindedir ve ncelik yn sadan soladr. */
0 < 5 1
1 != 8 1
x=1
&& (ve / and) Operatr
Bu operatr ilikisel operatrlerin hepsinden dk, || (veya / or) operatrnden yksek
nceliklidir. Operandlarnn ikisi de Doru ise Doru (1), operandlardan bir tanersi yanl ise
yanl (0) deerini retir.
x
yanl
yanl
Doru
Doru
x
3
7
1
x
y
yanl
Doru
yanl
Doru
x&&y
yanl
yanl
yanl
Doru
= 3 < 5 && 7;
< 5 1
1
&& 1 1
=1
&& operatrnn nce sol tarafndaki ilemler ncelik srasna gre tam olarak yaplr. Eer bu
ilemlerde elde edilen saysal deer 0 ise && operatrnn sa tarafndaki ilemler hi
yaplmadan Yanl (0) saysal deeri retilir. rnein :
x = 20;
b = !x == 4 && sqrt(24);
!20 0
0 == 4 0
68
8
Sol taraf 0 deeri alacandan operatrn sa taraf hi icra edilmeyecek dolaysyla da sqrt
fonksiyonu arlmayacaktr. Dolaysyla b deikenine 0 deeri atanacaktr.
Uygulamalarda mantksal operatrler ounlukla ilikisel (karlatrma) operatrleriyle birlikte
kullanlrlar :
scanf(%d, &x);
y = x >= 5 && x <= 25;
Bu durumda y deikenine ya 1 ya da 0 deeri atanacaktr. Eer x 5den byk ya da eit ve
25den kk ya da eit ise y deikenine 1 deeri bunun dndaki durumlarda y deikenine 0
deeri atanacaktr.
ch = c
z = ch >= a && ch <= z
Yukardaki rnekte ch deikeninin kk harf olup olmamas durumuna gre z deikenine 1
ya da 0 atanacaktr.
|| (veya / and) Operatr
ncelii en dk olan mantksal operatrdr. ki operandndan biri Doru ise Doru deerini
retir. ki operand da yanl ise yanl deerini retir.
x
yanl
yanl
Doru
Doru
y
x||y
yanl
yanl
Doru
Doru
yanl
Doru
Doru
Doru
a = 3 || 5
x = 0 || -12
sayi = 0 || !5
/* a = 1 */
/* x = 1 */
/* sayi = 0 */
|| operatrnn nce sol tarafndaki ilemler ncelik srasna gre tam olarak yaplr. Eer bu
ilemlerden elde edilen saysal deer 1 ise sa tarafndaki ilemler yaplmaz. rnekler:
a = 20;
b = 10;
y = a + b >= 20 || a b <= 10;
a + b 30
30 >= 20 1
Artk sa taraftaki ilemlerin yaplmasna gerek kalmadan y deikenine 1 deeri atanr.
Aadaki ifadede ch deikeninin iinde bulunan karakterin (Trke karakterler de dahil olmak
zere) kk harf olup olmad bulunur:
ch = ;
a = ch >= a && ch <= z || ch == || ch == || ch == || ch == || ch == || ch
== ;
Son olarak unu da ilave edelim, mantksal operatrler bir deer retebilmek iin operandlarn
nce 1 ya da 0 (yani DORU ya da YANLI) olarak yorumlarlar, ama yan etkileri yoktur. Yani
operandlarnn nesne olmas durumunda bu neslerin bellekteki deerlerini 1 ya da 0 olarak
deitirmezler.
69
b = c atamasndan elde edilen deer c nesnesinin kendisi deil c nesnesinin saysal deeridir.
Operatr tablosundan da greceimiz gibi atama operatr kendi arasnda sadan sola
nceliklidir. (right associative) Bu yzden :
var1 = var2 = var3 = 0; deyimi Cde geerlidir. Bu deyimde nce var3 deikenine 0 deeri
atanacak ve retilen 0 deeri var2 deikenine atanacak ve yine retilen 0 deeri son olarak
var1 deikenine atanacaktr.
lemli Atama Operatrleri
Bir ilemin operand ile ilem sonucunda retilen deerin atanaca nesne ayn ise ilemli
atama operatrleri kullanlr.
<nesne1> = <nesne1> ilem <operand2> ile
<nesne1> ilem= <operand2> ayn anlamdadr.
lemli atama operatrleri atama operatryle sadan sola eit ncelike sahiptir. (operatr
ncelik tablosuna baknz)
lemli atama operatrleri hem okunabilirlik hem da daha ksa yazm iin tercih edilirler.
Aadaki ifadeler edeerdir:
deger1 += 5;
sonuc *= yuzde;
x %= 5
deger1 = deger1 + 5;
sonuc = sonuc * yuzde;
x = x % 5;
70
8
zellikle += ve -= operatrlerinin yanl yazlmas, tespit edilmesi zor hatalara neden olabilir.
x += 5;
ifadesi x degikeninin eski deerini 5 artryorken bu deyim yanllkla aadaki gibi yazld
takdirde
x =+ 5;
x deikenine 5 deeri atanacaktr. nku burada iki ayr operatr sz konusudur. (atama
operatr olan = ve iaret operatr olan +)
yukardaki rneklerden de grld gibi atama grubu operatrlerinin yan etkileri vardr. Yan
etkileri operatrn sol operandnn bellekteki deerinin deitirilmesi (operatrn sa
tarafndaki operand olan ifadenin deerinin sol tarafndaki nesneye aktarlmas) eklinde
kendini gsterir.
Virgl (,) Operatr
ki ayr ifadeyi tek bir ifade olarak birletiren virgl operatr Cnin en dk ncelikli
operatrdr.
ifade1;
ifade2;
ile
ifade1, ifade2;
ayn ileve sahiptir.
Virgl operatrnn nce sol tarafndaki ifade sonra sa tarafndaki ifade tam olarak yaplr. Bu
operatrn rettii deer sa tarafndaki ifadenin rettii deerdir. Virgln sol tarafndaki
ifadenin rettii deerin virgl operatrnn rettii deere bir etkisi yoktur. rnein :
x = (y *= 5, z = 100);
ifadesinde x deikenine 100 deeri atanacaktr.
Aadaki rnekte if deeri yanl olarak deerlendirilecektir :
if (a =10, b = 0) {
...
}
Virgl operatrleri ile birden fazla ifade tek bir ifade olarak birletirilebilir. rnein :
if (x == 20) {
a1 = 20;
a2 = 30;
a3 = 40;
}
yerine
if (x == 20)
a1 = 20, a2 = 30, a3 = 40;
yazlabilir.
ncelik Operatr ( )
71
8
ncelik operatr bir ifadenin nceliini ykseltmek amacyla kullanlmaktadr.
x = (y + z) * t;
ncelik operatrn C nin en yksek ncelikli operatrler grubundadr. ncelik operatr 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
72
if DEYM
9 . BLM : if DEYM
C dilinde program akn kontrol etmeye ynelik en nemli deyim if deyimidir. if deyiminin
genel biimi aada verilmitir:
if (ifade)
deyim1;
else
deyim2;
deyim1 ve deyim2 yaln deyim (simple statement) olabilecei gibi, bileik bir deyim (compound
statement) ya da baka bir kontrol deyimi de (control statement) olabilir.
if parantezi iindeki ifadeye kontrol ifadesi (control expression) denir.
if deyiminin icras aadaki gibi yaplr:
Derleyici nce kontrol ifadesinin saysal deerini hesaplar. Hesaplad saysal deeri mantksal
doru ya da yanl olarak yorumlar. fadenin hesaplanan deeri 0 ise yanl, 0 dnda bir deer
ise doru olarak yorumlanr. (rnein kontrol ifadesinin hesaplanan deerinin 5 olduunu
dnelim, bu durumda kontrol ifadesi doru olarak deerlendirilecektir). Eer ifadenin sonucu
doru ise else anahtar szcne kadar olan ksm, eer ifadenin sonucu yanl ise else
anahtar szcnden sonraki ksm icra edilir. rnek :
{
int var = 3;
ch = A;
if deyiminin doru ve / veya yanl ksm birden fazla deyimden oluuyorsa bloklama
yaplmaldr :
if (b * b 4 * a * c < 0) {
deyim1;
deyim2;
deyim3;
}
else {
deyim4;
deyim5;
deyim6;
}
Yukardaki rnekte kontrol ifadesinin doru olmas durumunda, deyim1, deyim2, deyim3 icra
edilecektir. Kontrol ifadesinin yanl olmas durumunda ise deyim4, deyim5, deyim6 icra
edilecektir.
Bir if deyiminin else ksm olmayabilir:
if (result < 0) {
clrscr();
printf(sonu 0dan kk\n);
}
++x;
...
Bir if deyimi yalnzca else ksmna sahip olamaz. Bu durumda if deyiminin doru ksmna bo
deyim ya bo bileik deyim yerletirilmelidir.
if (ifade)
;
else
deyim1;
ya da
if (ifade)
{}
else
deyim1;
Ama daha iyi teknik koul ifadesini deitirmektir:
if (!ifade)
deyim1;
if parantezindeki ifade deiken iermek zorunda deildir, sabit ifadesi de olabilir:
if (10)
deyim1
...
if (-1)
deyim2
Yukardaki kontrol ifadelerinin deeri her zaman doru olacaktr. (0 d deer)
if ( 0)
deyim1;
74
if DEYM
Yukardaki kontrol ifadesi ise her zaman yanl olacandan if deyiminin doru ksm hibir
zaman icra edilmeyecektir.
if (x) {
deyim1;
deyim2;
....
}
Bu if deyiminde ise x deikeninin deerinin 0 d bir deer olup olmamasna gre deyim1 ve
deyim2 icra edilecektir.
Yukardaki yapyla aadaki yap edeerdir:
if (x != 0) {
deyim1;
deyim2;
....
}
if ((ch = getchar()) == h)
deyim1;
else
deyim2;
Bu if deyiminin kontrol ifadesinde ise klavyeden bir deer alnmakta alnan deer ch
deikenine atanmakta ve daha sonra da ch deikeni deerinin h karakteri olup olmad test
edilmektedir. Eer klavyeden alnan deer 'h' ise deyim1 deil ise deyim2 yaplacaktr.
kontrol ifadesi iindeki parantezler atama ilemine ncelik kazandrmak amacyla
kullanlmaktadr. Parantez kullanlmasayd eitlik karlatrma operatrnn (==) ncelii
atama operatrnden daha yksek olduu iin nce karlatrma ilemi yaplacak daha sonra
retilen 0 ya da 1 deeri ch deikenine atanacakt.
Yukardaki rnekte de grld gibi bir if deyiminin koul ifadesi iinde atama operatrnn
bir deer retmesi fikrinden sklkla faydalanlr.
Fonksiyonlarn geri dn deerleri de sklkla if deyiminin kontrol ifadesi olarak kullanlr.
75
9
if (isupper(ch) != 0)
deyim1;
else
deyim2;
isupper parametresinin byk harf olup olmadn kontrol eden bir standart C fonksiyonudur.
Yukardaki if deyiminde ch karakterinin byk harf olup olmamasna gre deyim1 ya da
deyim2 icra edilecektir.
Yukardaki koul ifadesi yerine C programclar genellikle aadaki ifadeyi tercih ederler :
if (isupper(ch))
deyim1;
else
deyim2;
if deyiminin doru ya da yanl ksm baka bir if deyimi de olabilir :
if (ifade1)
if (ifade2) {
deyim1;
deyim2;
deyim3;
}
deyim4;
Bu rnekte ikinci if deyimi birinci if deyiminin doru ksmn oluturmaktadr. 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 olacaktr:
if (ifade1)
if (ifade2)
deyim1;
else
deyim2;
Yukardaki rnekte yazm tarz olarak 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 olacaktr. (dangling else) Eer else anahtar
szcnn birinci if deyimine ait olmas isteniyorsa, birinci if deyiminin doru ksm blok iine
alnmaldr.
if (ifade1) {
if (ifade2)
deyim1;
}
else
deyim2;
Yukardaki rnekte else ksm birinci if deyimine aittir.
if (ifade1) {
if (ifade2)
76
if DEYM
deyim1;
else {
deyim2;
deyim3;
}
deyim4;
}
else
deyim5;
Birinci if deyiminin doru ksm birden fazla deyimden olutuu iin (bu deyimlerden birisi de
yine baka bir if deyimidir) bloklama yaplmtr. deyim5 birinci if deyiminin yanl ksmn
oluturmaktadr.
Ayrk karlatrma ve else if merdivenleri :
Aadaki if deyimlerini inceleyelim :
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 verilen yapda olduu gibi, eer bir karlatrmann doru olarak
yorumlanmas durumunda yaplan dier karlatrmalarn doru olmas sz konusu deilse bu
tr karlatrmalara ayrk karlatrma denir. Ayrk karlatrmalarda ayr ayr if deyimlerinin
kullanlmas kt tekniktir. Yukardaki rnekte m deikeninin deerinin 1 olduunu dnelim.
Bu durumda ekrana Ocak yazdrlacak fakat daha sonra yer alan if deyimleriyle m deikeninin
srasyla 2, 3, .... 12ye eit olup olmad test edilecektir. Ama x deikeni 1 deerine sahip
olduundan btn dier if deyimleri iindeki kontrol ifadelerinin yanl olarak deerlendirilecei
bellidir.
Ayrk karlatrmalarda else if merdivenleri uygulamalar ok kullanlr :
if (ifade1)
deyim1;
else
if (ifade2)
deyim2;
else
if (ifade3)
deyim3;
else
if (ifade4)
deyim4;
else
deyim5;
Bu yapda artk herhangi bir if deyimi ierisindeki bir kontrol ifadesi doru olarak
deerlendirilirse programn ak hibir zaman baka bir if deyimine gelmeyecektir. 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 tarz okunabilirlik asndan tercih edilmelidir.
77
if (ifade1)
deyim1;
else if (ifade2)
deyim2;
else if (ifade3)
deyim3;
else if (ifade4)
deyim4;
else deyim5;
78
if DEYM
if (x = 5)
printf("eit\n");
...
Atama operatr atama operatrnn sa tarafndaki ifadenin deerini reteceinden if
parantezi iindeki ifadenin deeri 5 olarak hesaplanacak ve 5 de 0 d bir deer olduundan
printf fonksiyonu x deikeninin deeri ne olursa olsun, arlacaktr. Tabi, atama operatr
yan etkisi olan bir operatr olduundan x deikeni de if deyiminin icras srasnda 5 deerini
alacaktr.
C derleyicilerinin ou if parantezi iindeki ifade yaln bir atma ifadesi ise, durumu pheyle
karlayarak, bir uyar mesaj verirler. rnein Borland derleyicilerinde tipik bir uyar mesaj
aadaki gibidir :
warning : possibly incorrect assignment! (muhtemelen yanl atama!)
Oysa if parantezi ierisinde atama operatr bilinli olarak da kullanlabilir. Bilinli kullanmda,
uyar mesajnn kaldrlmas iin ifade aadaki gibi dzenlenebilir :
...
if ((x = funk()) != 0)
m = 20;
...
Yukardaki rnekte atama operatrnn rettii deer ak olarak bir karlatrma operatrne
operand yapld iin derleyiciler bu durumda bir uyar mesaj vermezler.
if deyiminin doru ya da yanl ksmnn birden fazla basit deyimden olumas durumunda if
deyiminin doru ya da yanl ksm bileik deyim haline getirilmelidir.
...
if ( x == 10)
m = 12;
k = 15;
...
Yukardaki if deyiminde sadece
m = 12;
deyimi if deyiminin doru ksmn oluturmaktadr.
k = 15;
deyimi if deyimi dndadr. Bu durum, genellikle programcnn if deyiminin doru ya da yanl
ksmn nce basit bir deyimle oluturmasndan sonra, doru ya da yanl ksma ikinci bir basit
deyimi eklerken, bloklama yapmay 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;
}
...
79
9
Aadaki if deyimi ise yine if anahtar szc ile elenmeyen bir else anahtar szc
kullanld iin derleme zamannda error oluumuna neden olacaktr :
...
if ( x == 10)
m = 12;
k = 15;
else
y = 20;
...
Bu tr yanllklardan saknmak iin baz C programclar if deyiminin doru ya da yanl ksm
basit 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 basit deyimin ilave
edilmesi durumunda bir yanllk ya da error olumayacaktr. Ancak biz yukardaki gibi bir kodu
stil asndan beenmiyoruz. Gereksiz bloklamadan kanmalyz.
Bazen de if deyiminin yanl ksm unutulur :
...
if (x == 10)
printf("x 10'a eit!\n"")
printf("x 10'a eit deil!\n);
...
if parantezi ierisindeki ifadenin yanl olmas durumunda bir yanllk sz konusu deil ama
ifade doru ise ekrana ne yazlacak?
x 10'a eit!
x 10'a eit deil!
Tehlikeli bir bug da if parantezi ierisindeki ifadenin bir fonksiyon arma ifadesi olmas
durumunda yanllkla fonksiyon arma operatrnn unutulmasdr!
...
if (funk())
m = 12;
...
yerine
...
if (funk)
m = 12;
...
yazlrsa, if deyiminin her zaman doru ksm icra edilir. Zira C dilinde bir fonksiyon ismi, o
fonksiyonun kodunun bellekteki yerine edeer bir adres bilgisi olarak ele alnr. (Gstericiler
konusunda greceiz.) Bu adres bilgisi de her zaman 0 d bir deer olacandan, koul ifadesi
her zaman doru olarak deerlendirilecektir.
80
if DEYM
ch = getchar();
if (_islower(ch))
printf(kk harf\n);
else
printf(kk harf deil\n);
Yukarda yazlan _islower fonksiyonunda nce parametre deikeninin kk harf olup olmad
test edilmektedir. Parametre deikeni eer kk harf ise if deyiminin Doru ksm
yaplacaktr. Doru ksmnn yaplmas ile fonksiyon chnn kendi deerine geri dnecektir. (Bu
da 0 d bir deerdir. Pekala 1 gibi sabit bir deer ile de geri dnebilirdik ama ch parametre
deikeninin deeri ile geri dnmemiz fonksiyonun kullanlmasnda baz avantajlar
getirebilecektir. Fonksiyonun yazmnda dikkat edilmesi gereken bir nokta da udur : if
deyiminin Yanl ksm yoktur. (Yani else anahtar szc kullanlmamtr. Test
fonksiyonlarnda bu durum ok sk grlr. nk if deyiminin Doru ksmnda return anahtar
szc ile fonksiyon yalnzca bir geri dn deeri retmekle kalmamakta ayn zamanda
sonlanmaktadr. Bu durumda else anahtar szcne gerek kalmaz. (nk Doru ksmnn
yaplmasndan sonra Yanl ksmnn da yaplmas mmkn deildir.) Bu tr durumlarda else
anahtar szcnn kullanlmas kt teknik olarak deerlendirilir.
isalpha Fonksiyonu
isalpha fonksiyonu da standart bir C fonksiyonudur. Parametresi olan karakter , eer alfabetik
karakterse (yani byk ya da kk harf ise) Doru (sfr d bir deere), alfabetik bir karakter
deilse Yanl (sfr deerine) geri dner.
#include <stdio.h>
int isalpha (char ch)
{
if (ch >= a && ch <= z || ch >= A && ch <= Z)
return ch:
return 0;
}
main()
{
char ch;
81
9
ch = getchar();
if (isalpha(ch))
printf(alfabetik karakter\n);
else
printf(alfabetik karakter deil\n);
tolower Fonksiyonu
tolower standart bir C fonksiyonudur. Parametresi olan karakter, eer byk harf ise, onun
kk harf karlyla geri dner. tolower kk harf olmayan karakterlere hi dokunmaz,
onlar deitirmeden geri dn deeri olarak verir :
#include <stdio.h>
int tolower (int ch)
{
if (ch >= A && ch <= Z)
return ch A' + a;
return ch;
}
main()
{
char ch;
ch = getchar();
printf(%c\n, tolower(ch));
isdigit Fonksiyonu
isdigit standart bir C fonksiyonudur. Parametresi olan karakter, eer bir rakam karakteri ise 0
d bir deer ile, rakam karakteri deilse 0 deeri ile geri dner.
int _digit (char ch)
{
if (ch >= 0 && ch <= 9)
return ch:
return 0;
}
yukardaki rneklerde grld gibi, fonksiyonlarn parametreleri ve geri dn deerleri char
trden olsa bile, int biiminde gsterilir.
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
hex saylar gsteren bir karakterse Doru deilse Yanl
alfabetik ya da nmerik bir karakterse Doru deilse Yanl
82
if DEYM
isspace
ispunct
isprint
isgraph
iscntrl
isascii
Uygulamalar
Kendisine gnderilen 0 ie 15 arasndaki bir saynn hexadesimal sembol karl karakter ile
geri dnen get_hex_char fonksiyonunun yazlmas :
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;
}
test kodu :
main()
{
int number;
Kendisine gnderilen hex digit olan bir karakterin desimal sistemdeki deerine geri dnen
get_hex_value(char digit) fonksiyonunun yazlmas.
#include <stdio.h>
#include <ctype.h>
int get_hex_value(char digit)
{
digit = toupper(digit);
test kodu :
main()
83
9
{
char hex;
printf("hex digit gsteren bir karakter giriniz: ");
hex = getchar();
printf("girmi oldugunuz hex basaman desimal deeri %d\n", get_hex_value(hex));
return 0;
Kendisine gderilen karakter kk harf ise byk harfe dntren, byk harf ise kk
harfe dntren, eer harf karakteri deilse karakterin kendisiyle geri dnen change_case
isimli bir fonksiyonun tasarlanmas :
#include <stdio.h>
#include <conio.h>
int change_case(int ch)
{
if (ch >= 'A' && ch <= 'Z')
return ch - 'A' + 'a';
if (ch >= 'a' && ch <= 'z')
return ch - 'a' + 'A';
return ch;
}
test kodu :
main()
{
int kar;
change_case fonksiyonunu
tanmlayabilirdik :
standart
fonksiyonlarn
kullanarak
84
aadaki
ekilde
de
if DEYM
{
double a, b, c;
double delta, kokdelta;
printf("denklemin katsaylarn giriniz : ");
scanf("%lf%lf%lf", &a, &b, &c);
delta = b * b - 4 * a * c;
if (delta < 0) {
printf("denkleminizin gerek kk yok!\n");
return 0;
}
if (delta == 0) {
printf("denkleminizin tek gerek kk var\n");
printf("kok = %lf\n", -b / (2 * a));
return 0;
}
kokdelta = sqrt(delta);
printf("denkleminizin 2 gerek kk var : ");
printf("kk 1 = %lf\n", (-b + kokdelta) / (2 * a));
printf("kk 1 = %lf\n", (-b - kokdelta) / (2 * a));
return 0;
85
10
c = calculate(a, b);
printf(%f\n, c );
return 0;
Yukardaki rnekte calculate fonksiyonu kendisini aran main fonksiyonundan daha nce
tanmlanmtr. Dolaysyla arma ifadesine gelmeden nce derleyici, calculate fonksiyonunun
geri dn deeri trn zaten bilecektir.
Eer arlan fonksiyonun tanmlamas aran fonksiyondan daha sonra yaplmsa, derleyici
fonskiyon arma ifadesine geldiinde, sz konusu fonksiyonun geri dn deerinin trn
belirleyemez. Bu problemli bir durumdur.
# include <stdio.h>
int main()
{
float a, b, c;
c = calculate(a, b);
printf(%f\n, c );
return 0;
}
float calculate (float x, float y)
{
return x * y / (x + y);
}
Yukarda calculate fonksiyonu main iinde arlmtr. Fakat calculate fonksiyonunun
tanmlamas kaynak kod iinde mainden daha sonra yer almaktadr. Derleme ak ierisinde
calculate fonksiyonuna ilikin arma ifadesine gelindiinde, derleyici bu fonksiyonun geri
dn deerini bilmemektedir.
C derleyicileri derleme ilemi srasnda bir fonksiyon arma ifadesi grdklerinde, eer
fonksiyonun geri dn deeri tr hakknda henz sahibi deillerse, sz konusu geri dn
deerinin int trden olduunu kabul ederler.
86
FONKSYON PROTOTPLER
Yukardaki rnekte derleyici calculate fonksiyonunun geri dn deerinin int trden olduunu
varsayacak ve buna gre kod retecektir. Daha sonra derleme ak fonksiyonun tanmlama
ksmna geldiinde ise artk i iten gemi olacaktr. Hedef kod oluumunu engelleyen bu
durumu derleyiciler bir hata mesaj ile bildirirler.
Bu hata mesaj Microsoft derleyicilerinde : 'calculate': redefinition
Borland derleyicilerinde ise
: Type mismatch in redeclaration of 'calculate'
arlan fonksiyonu aran fonksiyonun stnde tanmlamak her zaman mmkn deildir.
Byk bir programda yzlerce fonksiyon tanmlanabilir ve tanmlanan her fonksiyonun birbirini
armas sz konusu olabilir. Bu durumda arlacak fonksiyonu aran fonksiyonun zerinde
tanmlanmas ok zor olacaktr. Kald ki, C dilinde iki fonksiyon birbirini de arabilir. Bu tr bir
fonksiyon tasarmnda artk arlan fonksiyonun daha nce tanmlanmas mmkn
olamayacaktr :
double func1(void)
{
...
func2();
...
}
double func2(void)
{
...
func1();
...
}
Ayrca standart C fonksiyonlar da ancak balama aamasna gelindiinde balayc (linker)
tarafndan ktphanelerden alnarak alabilen kod (.exe) iine yerletirilirler. te bu gibi
durumlarda derleyiciye arlan fonksiyonun geri dn tr bilgisi fonksiyon prototipleriyle
verilir. arlana kadar tanmlamas yaplmam fonksiyonlar hakknda derleyicilerin
bilgilendirilmesi ilemi fonksiyon prototip bildirimleri ile yaplr.
87
10
Yukardaki prototip bildirimi rneinde, derleyici func fonksiyonunun geri dn deerinin int
trden olduu bilgisini alr, fonksiyonun geri dn deerinin olmad bilgisini deil. Eer
tanmlanacak fonksiyon geri dn deeri retmeyecekse, void anahtar szc
kullanlmaldr:
void func(double);
Fonksiyon protipleri yalnzca derleyiciyi bildirme amacyla kullanlr bir bildirimdir (declaration)
bir tanmlama (definition) ilemi deildir, dolaysyla yaplan bildirim sonucunda bellekte bir yer
ayrlmaz.
Fonksiyon prototip bildirimlerinde parametre deikenlerinin trlerinden sonra parametre
isimleri de yazlabilir. Prototiplerdeki parametre isimlerinin faaliyet alanlar yalnzca parametre
parantezi ile snrldr. Buraya yazlan parametre deikenleri isimleri yalnzca okunabilirlik
asndan faydaldr. Buradaki deiken isimlerinin fonksiyonun gerek tanmlamasnda
kullanlacak formal parametre deikenlerinin isimleriyle ayn olmas zorunlulugu yoktur.
Yukardaki prototiplerini parametre isimleriyle tekrar yazalm.
float calculate(float a, float b);
int multiply(int number1, int number2);
double pow(double base, double exp);
Fonksiyon prototip bildirimlerinde parametre deikenlerine isim verilmesi, bildirimleri okuyan
kiilerin fonksiyonlarn tanmlarn grmeden, deikenler iin kullanlan isimleri sayesinde,
fonksiyonlarn yapt i konusunda daha fazla bilgi sahibi olmalarna yardmc olur.
Ayn trden geri dn deerine sahip fonksiyonlarn bildirimi virgllerle ayrlarak yazlabilir,
ama bu genel olarak pek tercih edilen bir durum deildir :
double func1(int), func2(int, int), func3(float);
Yukardaki bildirimde func1, func2 ve func3 fonksiyonlarnn hepsi double trden geri dn
deerine sahip fonksiyonlardr.
Fonksiyon prototip bildirimleri deiken tanmlamalaryla da birletirilebilir. Bu da tercih edilen
bir durum deildir.
long func1(int), long func2(void), x, y;
Yukardaki deyim ile func1 ve func2 fonksiyonlarnn prototip bildirimi yaplmken, x ve y
deikenleri tanmlanmtr.
(C++ dilinde eer arlan fonksiyon aran fonksiyondan daha nce tanmlanmamsa,
fonksiyonun geri dn deeri int trden kabul edilmez. Bu durumda fonksiyon prototip
bildiriminin yaplmas zorunludur. Prototip bildiriminin yaplmamas durumunda derleme
zamannda hata (error) oluacaktr.)
88
FONKSYON PROTOTPLER
Geleneksel olarak fonksiyon prototip bildirimleri programn en yukarsnda ya da programcnn
tanmlad balk dosyalarnn birinin iinde yaplr. Balk dosyalar (header files) ileride
detayl olarak ele alnacaktr.
1. Fonksiyon prototipinin bulunduu balk dosyasn kaynak koda bir nilemci komutuyla
dahil ederek.
#include <math.h>
2. Fonksiyonun prototipini kendimiz yazarak.
double pow(double taban, double us);
Ancak tercih edilecek yntem balk dosyasn kaynak koda dahil etmek olmaldr. nk:
1. Programc tarafndan fonksiyonun prototipi yanl yazlabilir.
2. Balk dosyalarnn kaynak koda dahil edilmesinin nedeni yalnzca fonksiyon prototip
bildirimi deildir. Balk dosyalarnda daha baka bilgiler de vardr. (Makrolar, sembolik
sabitler, tr tanmlamalar, yap bildirimleri vs.)
10
x = calculate(5.8);
y = calculate(4.6, 7.9, 8.0)
/* derleme hatas */
90
FONKSYON PROTOTPLER
sample(int number1, int number2);
Yukardaki bildirimlerinin hibirinde bir eliki sz konusu deildir. Fonksiyon parametre
deikenlerinin isimleri iin daha sonraki bildirimlerde farkl isimler kullanlmas bir eliki
yaratmayacaktr. nk bu isimlerin faaliyet alan (name scope) yalnzca bildirimin yapld
parantezin iidir. Ancak aadaki farkl bildirimler derleme zamannda error oluturacaktr :
double func(int x, double y);
double func(int x, float y);
/*
error!
bildirimler
arasnda
eliki
var.
*/
91
11
KOUL OPERATR
a > b ifadesinin doru olup olmamasna gre koul operatr 20 ya da 55 deerini retecek ve
son olarak da m deikenine koul operatrnn rettii deer atanacaktr. Ancak m
deikenine a > b ? 20 : 50 ifadesinin deerinin 5 fazlas atanmak isteniyorsa bu durumda
ifade aadaki gibi dzenlenmelidir:
m = (a > b ? 20 : 50) + 5
Koul operatrnn 3 operand da bir fonksiyon arma ifadesi olabilir, ama arlan
fonksiyonlarn geri dn deeri reten fonksiyonlar olmas (void olmayan) gerekmektedir.
operanddan biri geri dn deeri void olan bir fonksiyona ilikin fonksiyon arma ifadesi
olursa koul operatr deer retmeyeceinden bu durum derleme zamannda hata
olumasna neden olacaktr.
Aadaki kod parasn inceleyelim:
#include <stdio.h>
int func1(void);
int func2(void);
int func3(void);
int main()
{
int m;
m = func1() ? func2() : func3();
return 0;
}
Yukarda koul operatrnn kullanld ifadede m deikenine, func1 fonksiyonunun geri
dn deerinin 0 d bir deer olmas durumunda func2 fonksiyonunun geri dn deeri,
aksi halde func3 fonksiyonunun geri dn deeri atanacaktr.
Koul operatrnn rettii bir nesne deil bir deerdir. Koul operatrnn rettii deer
nesne gstermedii iin bu deere bir atama yaplamaz. Aadaki if deyimini inceleyelim:
if (x > y)
a = 5;
else
b = 5;
Yukardaki if deyimine x > y ifadesinin doru olmas durumunda a deikenine, yanl olmas
durumunda ise b deikenine 5 deeri atanyor. Ayn ii koul operatr kullanarak yapmak
istenip de aadaki ifade oluturulursa:
(x > y) ? a : b = 5;
bu durum derleme zaman hatasna yol aacaktr. nk koul operatrnn rettii a ya da b
deikenlerinin deeridir, nesnenin kendisi deildir. Byle bir atama sol tarafn nesne gsteren
bir ifade olmamasndan dolay derleme zamannda hata oluturur.
Ayn nedenden dolay aadaki ifadenin deerlendirilmeside derleme zamannda
olumasna neden olacaktr:
(x > 5 ? y : z)++;
93
hata
11
Parantez iindeki ifade deerlendirildiinde elde edilen y ya da z nesneleri deil bunlarn
deerleridir. Yani postfix ++ operatrnn operand nesne deildir. Bu durumda error
oluacaktr. (L value required!)
94
KOUL OPERATR
Yukardaki durumlarda koul operatrnn if deyimine tercih edilmesi iyi tekniktir. Bu
durumlarda koul operatr daha okunabilir bir yap oluturmaktadr. (Cye yeni balayanlar
iin if yaps daha iyi okunabilir ya da alglanabilir, ancak bir C programcisi iin koul
operatrnn kullanlmas daha okunabilir bir yap oluturur.)
Koul operatrnn bilinsizce kullanlmamas gerekir. Eer koul operatrnn rettii
deerden dorudan faydalanlmayacaksa koul operatr yerine if kontrol deyimi tercih
edilmelidir. rnein:
x > y ? a++ : b++;
Deyiminde koul operatrnn rettii deerden faydalanlmamaktadr. Burada aadaki if
yaps tercih edilmelidir:
if (x > y)
a++;
else
b++;
Baka bir rnek:
x == y ? printf(eit\n) : printf(eit deil\n);
Bu rnekte printf fonksiyonunun bir geri dn deeri retmesinden faydalanlarak koul
operatr kullanlmtr. Koul operatr x == y ifadesinin doru olup olmamasna gre, 2.
veya 3. ifade olan printf fonksiyonu arma ifadelerinden
birinin deerini (geri dn
deerini) retecektir. (Bu da aslnda ekrana yazlan karakter saysdr.) Ama ifade iinde koul
operatrnn rettii deerin kullanlmas sz konusu deildir. Burada da if kontrol deyimi
tercih edilmelidir :
if (x == y)
printf(eit\n);
else
printf(eit deil\n);
Koul operatrnn ikinci ve nc operandlarnn trleri farkl ise tr dntrme kurallari
dier operatrlerde olduu gibi devreye girecektir:
long a;
int b;
m = (x == y) ? b : a;
Bu rnekte a nesnesi long trden b nesnesi ise int trdendir. x == y karlatrma ifadesi
yanl olsa bile tr dnm gerekleecek ve int trden olan b long tre dntrlecektir.
Baz durumlarda koul operatrnn de if kontrol deiminin de kullanlmas gerekmeyebilir.
if (x > 5)
m = 1;
else
m = 0;
Yukardaki if deyimi koul operatr ile aadaki ekilde oluturulabilirdi :
m = (x > 5) ? 1 : 0;
Ancak koul operatrnn retecei deerlerin 1 veya 0 olabilecei durumlarda dorudan
karlatrma operatrn kullanmak daha iyi teknik olarak deerlendirilmelidir.
95
11
m = x > 5;
Baka bir rnek :
return x == y ? 1 : 0;
yerine
return x == y;
yazabilirdik.
Aada tanmlanan is_leap fonksiyonunu inceleyelim, fonksiyonun geri dn deerinin
retilmesinde koul operatr kullanlmayp dorudan mantksal operatrlerin 0 ya da 1 deeri
retmeleri fikrinden faydalanlmtr:
#define BOOL
int
96
DNG DEYMLER
97
srece blok
12
#include <stdio.h>
#include <ctype.h>
int main()
{
char ch;
98
DNG DEYMLER
Yukardaki programda bir sonsuz dng oluturulmutur. Dng ierisinde, dngnn her bir
iterasyonunda ch deikenine klavyeden bir deer alnmaktadr. Eer klavyeden alnan
karakter 'q' ise break anahtar szcyle programn ak while dng gvdesi dndaki ilk
deyimle devam edecektir.
ie Dngler
Bir dngnn gvdesini baka bir kontrol deyimi oluturabilir. Dng gvdesini oluturan
kontrol deyimi bir if deyimi olabilecei gibi baka bir dng deyimi de olabilir. (while, do
while, for deyimleri)
int main()
{
int i = 0;
int k = 0;
while (i < 10) {
while (k < 10) {
printf("%d %d", i, k);
++k;
}
}
++i;
return 0;
}
ie dnglerde ierideki dngde break deyimi kullanldnda yalnzca ierideki dngden
klr, her iki dngden birden kmak iin goto deyimi kullanlmaldr. (ileride greceiz)
while dngs bir btn olarak tek deyim iinde ele alnr. rnek:
while (1)
while (1) {
.....
.....
.....,
}
Burada ikinci while dngs tek bir kontrol deyimi olarak ele alnaca iin, bloklamaya gerek
yoktur.
while dngsnn yanllkla bo deyim ile kapatlmas ok sk yaplan bir hatadr.
int main()
{
int i = 10;
while (--i > 0);
/* burada bir bo deim var */
printf("%d\n", i);
return 0;
}
Dng while parantezi ierisindeki ifadenin deeri 0 olana kadar devam eder ve bo deim
dng gvdesi olarak icra edilir. Dngden kldnda ekrana 0 baslr.
Sonlandrc ; while parantezinden sonra konulursa herhangi bir sentaks hatas olumaz.
Derleyici while dngsnn gvdesinin yalnzca bir bo deyimden olutuu sonucunu kartr.
Eer bir yanllk sonucu deil de bilinli olarak while dngsnn gvdesinde bo deyim (null
statement) bulunmas isteniyorsa, okunabilirlik asndan, bu bo deyim while parantezinden
hemen sonra deil, alt satrda ve bir tab ieriden yazlmaldr.
99
12
}
Baka bir rnek:
...
int i = 10;
while (i-- > 0)
printf("%d\n", i);
printf("%d\n", i);
n bir pozitif tam say olmak zere while dngs kullanlarak n defa dnen bir while dngs
oluturmak iin
while (n-- > 0)
ya da
while (n--)
kullanlabilir. Aadaki iie dng yaps bir gecikme salamak iin kullanlmtr.
int main()
{
int i = 0;
long j;
Bazen dngler bilinli bir ekilde bo deyimle kapatlmak istenebilir. Bu durumda bo deyim
normal bir deyim gibi tablama kuralna uygun olarak yerletirilmelidir.
DNG DEYMLER
ifade 2;
} while (ifade);
do while dngsnde kontrol ifadesi sondadr. while parantezinden sonra sonlandrc ";"
bulunmaldr. Yani buradak sonlandrc yanllk sonucu koyulmamtr, deyime ilikin
sentaksn bir parasdr. Dng gvdesindeki deyim(ler) en az bir kere icra edilecektir. rnek :
int main()
{
int i = 0;
do {
++i;
printf("%d\n", i);
} while (i < 10);
return 0;
}
Baka bir rnek:
int main()
{
char ch;
do {
printf ("(e)vet / (h)ayt?\n");
ch = getch();
} while (ch != 'e' && ch != 'h');
printf("ok...\n");
return 0;
Uygulama
1'den 100'e kadar saylar her satrda be tane olacak biimde ekrana yazan bir C programnn
yazlmas:
#include <stdio.h>
int main()
{
int i = 0;
do {
printf("%d ", ++i);
if (i % 5 == 0)
printf("\n");
} while (i < 100);
return 0;
}
Baka bir zm:
#include <stdio.h>
void main()
{
int i = 0;
while (i < 100) {
printf ("%d", i);
101
12
if (i % 5 == 4)
printf("\n");
++i;
return 0;
}
Uygulama
Bir tamsaynn basamak saysn bulan program.
#include <stdio.h>
int main()
{
int digits = 0;
int number;
printf("bir tamsayi girin: ");
scanf("%d", &number);
do {
n /= 10;
digits++;
} while (n > 0);
printf("the number has %d digit(s).\n", digits);
return 0;
}
Ayn program while dngs kullanarak yazalm.
...
while (n > 0) {
n /= 10;
digits++;
}
...
do while dngs yerine while dngs kullanldnda, girilen saynn 0 olmas durumunda
dng gvdesindeki deyimler hi icra edilmeyecekti. Bu durumda ekranda:
The number has 0 digit(s)
yazs kacakt.
for Dngleri
for dngleri yalnzca C dilinin deil, belki de tm programlama dillerinin en gl dng
yaplardr. for dnglerinin genel biimi u ekildedir:
for (ifade1; ifade2; ifade3)
deyim1;
for (ifade1; ifade2; ifade3)
deyim1;
deyim2;
...
}
102
DNG DEYMLER
Derleyici for anahtar szcnden sonra bir parantez almasn ve parantez ierisinde iki
noktal virgl bulunmasn bekler. Bu iki noktal virgl for parantezini ksma ayrr. Bu
ksmlar yukarda ifade1 ifade2 ve ifade 3 olarak gsterilmitir.
for parantezi iinde mutlaka 2 noktal virgl bulunmaldr. for parantezi iinin bo braklmas,
ya da for parantezi ierisinde 1, 3 ya da daha fazla noktal virgln bulunmas derleme
zamannda hata olumasna yol aacaktr.
for parantezinin kapanmasndan sonra gelen ilk deyim dng gvdesini (loop body) oluturur.
Dng gvdesi basit bir deyimden oluabilecei gibi, bileik deyimden de yani blok iine alnm
birden fazla deyimden de oluabilir.
for parantezi ierisindeki her ksmn da ayr ayr ilevleri vardr.
for parantezinin 2. ksmn oluturan ifadeye kontrol ifadesi denir. (control expression). Tpk
while parantezi iindeki ifade gibi, dngnn devam konusunda bu ifade sz sahibidir. Bu
ifadenin deeri 0 d bir deer ise, yani mantksal olarak doru ise, dng devam eder. Dng
gvdesindeki deyim(ler) icra edilir. Kontrol ifadesinin deeri 0 ise programn ak for
dngsnn dndaki ilk deyimle devam edecektir.
Programn ak for deyimine gelince, for parantezinin 1. ksm 1 kez icra edilir ve genellikle
dng deikenine ilk deer verme amacyla kullanlr. (Byle bir zorunluluk yoktur).
for dngsnn 3. ksm dng gvdesindeki deyim ya da deyimler icra edildikten sonra,
dnte altrlr. Ve ounlukla dng deikeninin artrlmas ya da azaltlmas amacyla
kullanlr. (Byle bir zorunluluk yok.)
for (ilk deer; koul; ilem) {
...
...
...
}
int main()
{
int i;
103
12
Programn ak yine for parantezinin 3. ksmna geliyor ve buradaki ifade bir deyimmi gibi
icra edeiliyor, yani i deikeninin deeri 1 artrlyor. i deikeninin deeri 2 oluyor.
Programn ak yine for parantezinin 2. ksmna geliyor ve buradaki kontrol ifadesi tekrar
sorgulanyor. i < 2 ifadesi bu kez yanl olduu iin programn ak dng gvdesine girmiyor
ve programn ak dng gvdesi dndaki ilk deyimle devam ediyor.
Yani ekrana :
son deer = 2
yazlyor.
Uygulama
1den 100e kadar olan saylarn toplamn bulan program :
int main()
{
int i;
int total = 0;
for (i = 0; i < 100; ++i)
total += i;
printf(Toplam = %d, total);
return 0;
}
Dng deikeninin tamsay trlerinden birinden olmas gibi bir zorunluluk yoktur. Dng
deikeni gerek say trlerinden de olabilir.
int main()
{
double i;
for (i = 0; i < 6.28; i = i + 0.01)
printf(lf\n, i);
return 0;
}
Daha nce de sylendii gibi for parantezi iindeki her 3 ksm da ifade tanmna uygun ifadeler
ierebilir, yani bir dng deikenine ilk deer verilmesi, dng deikenine bal bir koul
ifadesi olmas, dng deikeninin de azaltlmas ya da artrlmas bir zorunluluk deildir.
int main()
{
char ch;
104
DNG DEYMLER
Virgl operatr ile birletirilmi deimlerin soldan saa doru srayla icra edileceini ve toplam
ifadenin retecei deerin en sadaki ifadenin deeri olacan hatrlayn.
for dngsnn 1. ksm hi olmayabilir. rnein dng dnda, programn ak for deyiminin
icrasna gelmeden nce, dng deikenine ilk deer verilmi olabilir.
...
i = 0;
for (; i < 100; ++i)
printf(%d\n, i);
for dngsnn 3. ksm da olmayabilir. Dng deikeninin artrlmas ya da eksiltilmesi for
parantezi ii yerine dng gvdesi ierisinde gerekletirilebilir.
1. ve 3. ksm olmayan (yalnzca 2. ksma sahip) bir for dngs rnei:
...
i = 0;
for (; i < 100; ) {
printf(%d\n, i);
++i;
}
...
1.ve 3. ksm olmayan for dngleri tamamen while dngleriyle edeerdir. Cde for
dngleriyle while dngleriyle yapabildiimiz hereyi yapabiliriz. O zaman yle bir soru
aklmza gelebilir: Madem for dngleri while dnglerini tamamen kapsyor, o zaman
while dnglerine ne gerek var? while dnglerinin baz durumlarda kullanlmas for
dnglerine gre ok daha okunabilir bir yap yaratmaktadr.
for parantezinin 2. ksm da hi olmayabilir. Bu durumda kontrol ifadesi olmayaca iin dng
bir koula bal olmakszn srekli dnecektir. Yani sonsuz dng oluturulacaktr. Ancak iki
adet noktal virgl yine parantez iinde mutlaka bulunmak zorundadr.
for parantezinin hibir ksm olmayabilir. Ancak yine iki noktal virgl bulunmak zorundadr:
...
i = 0;
for (;;) {
printf(%d\n, i);
++i;
if (i == 100)
break;
}
...
for (;;) ile while (1) edeerdir. kisi de sonsuz dng belirtir.
Sonsuz dng oluturmak iin for (;;) biimi while (1)'e gre daha ok tercih edilir. Bunun
nedeni eski derleyicilerde while(1) ifadesi kullanldnda dgnn her dnnde kontrol
ifadesinin tekrar test edilmesidir. Ama yeni derleyicilerde byle bir kontrol sz konusu deildir.
Ama baz programclar while (1) ifadesini tercih ederler. (Tabi burada kontrol ifadesi 1 yerine
0 d herhangi bir deer de olabilirdi ama geleneksel olarak 1 ifadesi kullanlmaktadr.)
Sonsuz Dnglerden k
1. break anahtar szc ile.
Bu durumda programn ak dng gvdesi dndaki ilk deyime ynlenecektir. (eer i ie
dng varsa break anahtar szc ile yalnzca iteki dngden klacaktr.)
105
12
break anahtar szc bir dngy sonlandrmak iin, continue anahtar szc de bir
dngnn o anda iinde bulunulan yinelemesini sonlandrmak iin kullanlr.
continue anahtar szc zellikle, dng ierisinde uzun if deyimlerini varsa, okunabilirlii
artrmak amacyla kullanlr.
for (i = 0; i < n; ++i) {
ch = getch();
if (!isspace(ch)) {
...
...
...
}
}
Yukardaki kod parasnda dng iinde, klavyeden getch fonksiyonu ile deer atanan ch
deikeni boluk karakteri deilse, bir takm deyimlerin icras istenmi. Yukardaki durum
continue anahtar szcyle daha okunabilir hale getirilebilir :
for (i = 0; i < n; ++i) {
ch = getch();
if (isspace(ch))
continue;
...
...
...
}
n kere dnen for deyimi kalplar
106
DNG DEYMLER
Uygulama
Basamaklarnn kpleri toplam kendisine eit olan 3 basamakl saylar bulan program.
#include <stdio.h>
#include <conio.h>
int main()
{
int i, j, k;
int number = 100;
clrscr();
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 says artlar saglyor\n", number);
number++;
}
return 0;
clrscr();
for (i = 100; i <= 999; ++i) {
b1 = i / 100;
b2 = i % 100 / 10;
b3 = i % 10;
if (b1 * b1 * b1 + b2 * b2 * b2 + b3 * b3 * b3 == i)
printf("%d says artlar salyor\n", i);
}
return 0;
Uygulama
Kendisine gnderilen iki tamsaynn obeb ve okek deerlerini hesaplayan fonksiyonlar.
#include <stdio.h>
#include <conio.h>
107
12
Uygulama
Kendisine gnderilen int trden argumann faktriyel deerini hesaplayan fonksiyon.
long 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;
}
Uygulama
Birinci parametre deikeninde tutulan tamsaynn ikinci parametre deikeninde tutulan
tamsay kuvvetini hesaplayan fonksiyon.
108
DNG DEYMLER
long power(int base, int exp)
{
long result = 1;
int k;
for (k = 1; k <= exp; ++k)
result *= base;
return result;
}
ya da
long power(int base, int exp)
{
long result = 1;
while (exp-- > 0)
result *= base;
}
Uygulama
Kendisine gnderilen saynn asal say olup olmadn test eden isprime fonksiyonu.
int isprime(long 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;
Uygulama
Blenlerinin toplamna eit olan saylara mkemmel tamsay (perfect integer) say denir.
rnein 28 says bir mkemmel tamsaydr.
1 + 2 + 4 + 7 + 14 = 28
Kendisine gnderilen bir argumann mkemmel tamsay olup olmadn test eden is_perfect
fonksiyonu.
#include <stdio.h>
int is_perfect(int number);
int main()
{
int k;
109
12
for (k = 1000; k <= 9999; ++k)
if (isperfect(k)) {
printf("%d perfect\n");
return 0;
}
return 0;
}
int is_perfect(int number)
{
int i;
int total = 1;
Uygulama
int trden bir sayy arpanlarna ayran ve arpanlar kkten bye ekrana yazdran
display_factors fonksiyonunu.
#include <stdio.h>
#include <conio.h>
void factors(int number);
/* test kodu : 1111 ile 1200 arasndaki saylar arpanlara ayryor */
int main()
{
int k;
Uygulama
Klavyeden alnan cmleyi ekrana yazan ve cmle "." karakteriyle sonlannca yazlan toplam
kelime saysn ve ortalama kelime uzunlugunu bulan program.
110
DNG DEYMLER
#include <stdio.h>
#include <conio.h>
#include <ctype.h>
int main()
{
int ch;
int wordlength = 0, total = 0, wordcount = 0;
clrscr();
while ((ch = getch()) != '.') {
putchar(ch);
if (isspace(ch)) {
total += wordlength;
if (wordlength)
wordcount++;
wordlength = 0;
}
else
wordlength++;
}
wordcount++;
total += wordlength;
printf("\n\ntoplam kelime says = %d\n", wordcount);
printf("ortalama uzunluk = %f\n", (double) total / wordcount);
return 0;
}
Uygulama
Klavyeden srekli karakter alnmasn salayan, alnan karakterleri ekranda gsteren, ancak
arka arkaya "xyz" karakterleri girildiinde sonlanan bir program.
#include <stdio.h>
#include <conio.h>
main()
{
char ch;
int total = 0;
alma Sorular
Prototipi aada verilen isprimex fonksiyonunu tanmlaynz.
111
12
int isprimex(long number);
isprimex fonksiyonuna gnderilen argumann asal olup olmad test edilecek, eer say asal
ise bu kez saynn basamak deerleri toplanarak elde edilen saynn asal olup olmad test
edilecektir. Bu ilem sonuta tek basamakl bir say kalana kadar devam edecektir. Eer en son
elde edilen tek basamakl say dahil tm saylar asal ise isprimex fonksiyonu 0 d bir deere
geri dnecektir. Eer herhangi bir kademede asal olmayan bir say elde edilirse fonksiyon 0
deerine geri dnecektir.
Yazdnz fonksiyonu aadaki main fonksiyonu ile test edebilirsiniz :
#include <stdio.h>
#include <conio.h>
int isprimex(long number);
int main()
{
long k;
clrscr();
for (k = 19000; k <= 20000; ++k)
if (isprimex(k))
printf("%ld \n", k);
return 0;
}
112
TR DNMLER
13 . BLM : TR DNMLER
Bilgisayarlarn aritmetik ilemleri gerekletirmesinde bir takm kstlamalar sz konusudur.
Bilgisayarlarn aritmetik bir ilemi gerekletirmesi iin (genellikle) ileme sokulan operandlarn
uzunluklarnn ayn olmas (yani bit saylarnn ayn olmas) ve ayn ekilde bellee yerletirilmi
olmalar gerekmektedir. rnek vermek gerekirse, bilgisayar 16 bit uzunluunda iki tam sayy
dorudan toplayabilir ama 16 bit uzunluunda bir tam say ile 32 bit uzunluundaki bir
tamsayy ya da 32 bit uzunluunda bir tamsay ile 32 bit uzunluunda bir gerek sayy
dorudan toplayamaz.
C programlama dili, deiik trlerin ayn ifade ierisinde bulunmalarna izin verir. Yani tek bir
ifadede bir tamsay trnden deiken, bir float sabit 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 bir int sayyla 32 bitlik bir int sayy topladmzda, derleyici nce 16 bitlik
int sayy 32 bit uzunluunda bir int sayya dntrecek ve ondan sonra toplama ilemini
gerekletirecektir. Yine 16 bitlik bir int sayyla 64 bitlik bir double sayy arpmak
istediimizde derleyici nce int sayy 64 bitlik bir double sayya dntrecektir. Bu tr
dnm daha komplekstir nk int ve double saylar bellekte farkl ekillerde tutulurlar.
Bu tr dnmleri programcnn kontrol dnda otomatik olarak gerekletirilirler. Bu tr
dnmlerine otomatik tr dnmleri (implicit type conversions) diyeceiz. C dili
programcya herhangi bir deikenin ya da sabitin trn, bir operatr kullanarak deitirme
olana da verir. Programc tarafndan yaplan bu tip tr dnmlerine bilinli tr dnmleri
(explicit type conversions/type casts) diyeceiz.
nce otomatik tr dnmlerini inceleyeceiz. Otomatik tr dnmleri ne yazk ki karmak
yapdadr ve iyi renilmemesi durumunda programlarda hatalar kanlmazdr. Zira C dilinde
11 ana tr vardr. Herhangi bir hataya dmemek iin bunlarn her trl ikili kombinezonu iin
nasl bir otomatik tr dnm yaplacan ok iyi bilmemiz gerekir.
Aada belirtilen 4 durumda mutlaka otomatik bir tr dnm yaplacaktr:
1. Aritmetik ya da mantksal bir ifadedenin operandlar ayn trden deilse:
...
int x, y;
float fl;
if (fl * ix / iy) {
...
}
Bu durumda yaplan tr dnmlerine genel aritmetik tr dnmleri diyeceiz.
2. Atama operatr kullanldnda atama operatrnn sa tarafyla sol taraf ayn trden
deilse:
double toplam;
long sayi1, sayi2;
toplam = sayi1 + sayi2;
Bu durumda yaplan tr dnmlerine atama tr dnmleri diyeceiz.
3. Bir fonksiyon arlmas srasnda kullanlan bir argumann tr ile fonksiyonun ilgili
parame deikeni ayn trden deilse:
113
13
double sonuc;
int sayi1, sayi2;
...
sonuc = pow(sayi1, sayi2)
double pow (double taban, double us)
{
...
}
4. Bir return ifadesinin tr ile ilgili fonksiyonun geri dn deerinin tr arasnda farkllk
varsa:
double funktion (int para1, int para2)
{
...
return (para1 + para2)
}
3. ve 4. durumlar da bir atama ilemi olarak dnlebilir. Zira fonksiyon arma ifadesindeki
argumanlar parametre deikenlerine kopyalanarak (atanarak) geirilir. Yine return ifadesi de
aslnda geici blgeye yaplan bir atama ilemidir.
Otomatik Tr Dnmleri
Otomatik tr dnmleri iki operand alan operatrlerin bulunduu ifadelerde operandlarn
trlerinin farkl olmas durumunda uygulanr. Ve otomatik tr dnm sonucunda farkl iki
tr olmas durumu ortadan kaldrlarak operandlarn 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. (biri int dieri double
trden). Bu durumda i ve d nesnelerinin trleri otomatik olarak ayn yaplr. Peki int tr m
double tre dntrlecek yoksa double tr m int tre dntrlecek? Eer double tr
int tre dntrlse bilgi kayb sz konusu olurdu (nk bu durumda gerek saynn en az
virglden sonraki ksm kaybedilir).
C'de otomatik tr dnmleri mmknse bilgi kayb olmayacak ekilde yaplr.
Bu durumda bilgi kaybn engellemek iin genel olarak kk tr byk tre dntrlr.
(istisnalar var) Bu duruma terfi (promotion) diyeceiz.
Kurallar detayl olarak renmek iin oluabilecek durumlar iki ana durum altnda inceleyelim:
1. Operandlardan birinin tr gerek say trlerinden biriyse.
Operandlardan birinin long double dierinin farkl bir tr olmas durumunda dier operand
long double trne evrilir.
Operandlardan birinin double dierinin farkl bir tr olmas durumunda dier operand
double trne evrilir.
Operandlardan birinin float dierinin farkl bir tr olmas durumunda dier operand float
trne evrilir.
114
TR DNMLER
2. Operandlardan hibiri gerek say trlerinden deilse:
Eer ifade iindeki operandlardan herhangi biri char, unsigned char, short ya da
unsigned short trden ise aadaki algoritma uygulanmadan nce bu trler int tre
dntrlr. Bu duruma tam sayiya terfi (integral promotion) denir.
Daha sonra aadaki kurallar uygulanr:
Operandlardan birinin unsigned long dierinin farkl bir tr olmas durumunda (long,
unsigned int, int) dier operand unsigned long trne evrilir.
Operandlardan birinin long trden dierinin farkl bir trden olmas durumunda (unsigned
int, int) dier operand long trne evrilir.
Operandlardan biri unsigned int trden dierinin farkl bir trden olmas durumunda (int)
ikinci operand unsigned int trne evrilir.
stisnalar:
Eer operandlardan biri long int dieri unsigned int trnden ise ve kullanlan sistemde bu
trlerin uzunluklar ayn ise (UNIX ve Win 32 sistemlerinde olduu gibi) her iki tr de
unsigned long int trne dntrlr.
Eer operandlardan biri int dieri unsigned short trnden ise ve kullanlan sistemde bu
trlerin uzunluklar ayn ise (DOS'da olduu gibi) her iki tr de unsigned int trne
dntrlr.
Otomatik tr dnmleri ile ilgili kurallar aadaki tabloda zetleyelim:
operandlardan herhangi biri
yaplacak dnm
char,short,unsigned char,unsigned ilgili operand int tre dntrlecek.
short
operand 1
long
double
double
float
unsigned
long
long
unsigned
int
operand 2
double, float, unsigned
long, long, int, unsigned
int
float, unsigned long,
long, int, unsigned int
unsigned long, long, int,
unsigned int
long, int, unsigned int
int, unsigned int
int
yaplacak dnm
2. operand long double trne
evrilecek.
2. operand double trne evrilecek.
2. operand float trne evrilecek.
2. operand unsigned long trne
evrilecek
2. operand long trne dntrlecek.
(istisnai duruma dikkat!)
2. operand unsigned int trne
dntrlecek.
Fonksiyon arma ifadeleri de, operatrlerle birlikte baka ifadeleri oluturuyorsa, otomatik tr
dnmlerine neden olabilir. Zira geri dn deerine sahip olan fonksiyonlar iin fonksiyonun
arlma ifadesi, fonksiyonun geri dn deerini temsil etmektedir. rnein:
int i = 5;
...
pow(2, 3) + i
ifadesinde pow fonksiyonunun geri dn deeri double trden olduu iin, int trden olan i
deikeni de, ilemin yaplabilmesi iin double trne evrilerek ileme sokulacaktr.
115
13
Atama Tr Dnmleri
Bu tr dnmlerin ok basit bir kural vardr: Atama operatrnn sa tarafndaki tr, atama
operatrnn sol tarafndaki tre otomatik olarak dntrlr.
Kk trlerin byk trlere dntrlmesinde bilgi kayb sz konusu deildir. rnein :
double leftx;
int righty = 5;
leftx = righty;
yukardaki rnekte righty deikeninin tr inttir. nce double tre otomatik dnm
yaplacak ve double hale getirilen 5 sabiti (5.) leftx deikenine atanacaktr.
Aada 16 bitlik sistemler iin baz rnekler verilmektedir :
TR
desimal
hex
dntrlecektr hex
int
138
0x008A long int
0x0000008A
char
d (100)
0x64
int
0x0064
int
-56
0xFFC8 long int
0xFFFFFFFC8
char
\x95 (-07) 0x95
int
0xFF95
unsigned int 45678
0xB26E long int
0XFFFFB26EL
char
0 (48)
0x30
long int
0x00000030L
desimal
138L
100
-56L
-107
-19858L
30L
Negatif olan bir tamsay kk trden byk tre dntrldnde saynn yksek anlaml
bitleri negatifliin korunmas amacyla 1 ile beslenmektedir. (Hex olarak F ile)
Derleyici tarafndan yaplan otomatik, atama tr dnmlerinde, byk trn kk tre
dntrlmesi durumunda bilgi kayb sz konusu olabilir.
Aadaki basit kurallar verebiliriz:
Eer atama operatrnn her iki taraf da tam say trlerinden ise (char, short, int, long),
atama operatrnn sa tarafnn daha byk bir trden olmas durumunda bilgi kayb olabilir.
Bilgi kayb ancak, atama operatrnn sa tarafndaki deerin, sol taraftaki trn snrlar
iinde olmamas durumunda sz konusu olacaktr. Bilgi kayb yksek anlaml bytelarn
kaybolmas eklinde ortaya kar. rnek:
long m = 0x12345678;
int y;
y = m;
printf (m = %x\n, m);
Yukardaki rnekte int trden olan y deikenine long trden bir deikenin deeri atanmtr.
(16 bitlik bir sistemde rnein DOS altnda altmz dnyoruz.). DOS altnda int tr
iin say snrlar 32768 +32767 deerleridir. Bu saylarda iki bytelk bir alan iin iaretli
olarak yazlabilecek en byk ve en kk saylardr. Hex gsterimde her bir hex digit 4 bite ve
her iki hex digit 1 byte alana tekabl edecektir. Dolaysyla 0x12345678 says 8 hex digit yani
4 byte uzunluunda bir saydr. Oysa atamann yaplaca taraf int trdendir ve bu tr max. 4
hex digit (2 byte) uzunlukta olabilmektedir. Bu durumda m deikenine ilikin deerin yksek
anlaml 2 byte yani (4 hex digiti) kaybedilecektir. Atama ileminden sonra, printf
fonksiyonuyla y deikeninin deeri yazdrldnda (hex gsterimli) ekrana 5678 deerinin
yazdrld grlecektir.
Atama operatrnn sa taraf gerek say trlerinden bir trden ise (float, double, long
double) ve sol taraf ise tam say trlerinden birine ait ise, bu hereyden nce undefined
behaviour (pheli kod) durumudur ve bu durumun olutuu kodlardan kesinlikle kanmak
gerekir. Ama derleyicilerin hemen hemen hepsi bu durumda aadaki ekilde tr dnm
yaparlar:
116
TR DNMLER
Sa taraftaki gerek say trndeki deer nokta ieriyorsa, nce kesir ksm kaybedilir. Kesir
ksm kaybedildikten sonra kalan deer eer sol taraf trnn snrlar iinde kalyorsa daha
fazla bir bilgi kayb olmaz, fakat sol taraf trnn snrlar alyorsa ilave bir bilgi kayb daha
olur ve yksek anlaml bytelar kaybedilir.
rnek:
double y = 234.12;
int x;
x = y;
printf(x = %d\n, x );
y = 32768.1;
x = y;
printf(x = %d\n, x );
117
13
118
TR DNMLER
fonksiyonun int trden bir geri dn deerine sahip olmas gerekecektir) tr dnm
gerekleebilecek mi?
Bu durumda fonksiyonun parametre deikenlerinin trleri hakknda derleyici bilgi sahibi
olamayaca iin, fonksiyona gnderilen argumanlar, default arguman dnm denilen
dnme tabi tutar. Default arguman dnm u ekilde olur:
char ya da short trnden olan argumanlar tamsayya terfi ettirilir. (integral promotion).
float trnden olan argumanlar double trne dntrlr. Bunun dndaki trlerden olan
argumanlarn tr dntrlmesine tabi tutulmaz.
119
14
switch (a) {
case 1: printf(bir\n);
case 2: printf(iki\n);
case 3: printf(\ n);
case 4: printf(drt\n);
default: printf(hibiri\n);
}
return 0;
Burada unutulmamas gereken noktay tekrar edelim: Uygun bir case ifadesi bulunduunda
programn ak buraya geirilir. Yalnzca bulunan case ifadesini izleyen deyim ya da deyimlerin
icra edilmesi sz konusu deildir.Uygun case ifadesini izleyen deyimlerin icrasndan sonra
programn ak daha aada bulunan case ifadlerini izleyen deyimlerin icra edilmesiyle devam
eder.
Yukardaki rnekte scanf fonksiyonu ile a deikenine 1 atandn varsayalm. Bu durumda
program kts u ekilde oluacaktr :
bir
iki
120
switch DEYM
drt
hibiri
Eer uygun case ifadesi bulunduunda yalnzca bu ifadeye ilikin deyim(ler)in icra edilmesini
istersek break anahtar szcnden faydalanrz. break anahtar szc dnglerden olduu
gibi switch deyimlerinden de kmamza olanak verir.
#include <stdio.h>,
int main()
{
int a;
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;
default : printf(hibiri\n); break;
}
return 0;
}
Uygulamalarda da switch deyiminde ounlukla her case ifadesi iin bir break anahtar
szcnn kullanldn grrz. (Tabi byle bir zorunluluk yok!)
case ifadelerini izleyen ":" atomundan sonraki deyimler istenildii kadar uzun olabilir. case
ifadelerinin sral olmas ya da default anahtar szcnn en sonda olmas gibi bir zorunluluk
yoktur. default herhangi bir yere yerletirilebilir. default ifadesi nerede olursa olsun,
programn ak ancak uygun bir case ifadesi bulunamazsa default iine girecektir.
Yukarda da anlatld gibi switch parantezi ierisindeki ifadenin saysal deerine eit bir case
ifadesi bulunana kadar derleyici derleme ynnde (yani yukardan aaya doru) tm case
ifadelerini srasyla kontrol eder. Bu yzden en yksek olasla ilikin (biliniyorsa) case
ifadesinin en baa (dierlerinden nce) yerletirilmesi iyi tekniktir.
switch kontrol deyimi belli llerde else if (else if ladder - cascaded if) yaplaryla
karlanabilir. Yani switch deyimi olmasayd yapmak istediklerimizi else if deyimi ile
yapabilirdik. Ancak baz durumlarda else if yaps yerine switch deyimi kullanmak
okunabilirlii artrmaktadr. rnein aadaki iki kod ilevsel olarak birbirinin ayndr:
if ( a == 1) {
ifade_1;
ifade_2;
}
else if (a == 2) {
ifade_3;
ifade_4;
}
else if (a == 4) {
ifade_5;
}
else {
ifade_6;
}
ifade_7;
}
switch (a) {
case 1:
ifade_1;
ifade_2;
case 2:
ifade_3;
ifade_4;
case 4:
ifade_5;
default:
ifade_6;
ifade_7;
121
14
rnek :
Bir tarih bilgisini (ay, gn, yl) yaz ile gg yaz yyyy (12 - Austos - 2002 gibi) biiminde
ekrana yazan, prototipi void display_date(int day, int month, int year) biiminde olan
fonksiyon. .
#include <stdio.h>
#include <conio.h>
void display_date(int day, int month, int year);
int main()
{
int d, m, y;
int k;
for (k = 0; k < 10; ++k) {
scanf(%d%d%d, &d, &m, &y);
display_date(d, m, y);
putchar('\n');
}
getch();
return 0;
}
void display_date(int day, int month, int year)
{
printf(%d , day);
switch (month) {
case 1: printf(Ocak); break;
case 2: printf(Subat); break;
case 3: printf(Mart); break;
case 4: printf(Nisan); break;
case 5: printf(Mayis); break;
case 6: printf(Haziran); break;
case 7: printf(Temmuz); break;
case 8: printf(Agustos); break;
case 9: printf(Eylul); break;
case 10: printf(Ekim); break;
case 11: printf(Kasim); break;
case 12: printf(Aralik); break;
}
printf( %d\n, year);
Birden fazla case ifadesi iin ayn ilemlerin yaplmas yle salanabilir.
case 1:
case 2:
case 3:
ifade1;
ifade2;
ifade3;
break;
case 4:
Bunu yapmann daha ksa bir yolu yoktur. Baz programclar bu yapy u ekilde de yazarlar:
122
switch DEYM
case 1: case 2: case 3: case 4: case 5:
ifade1:
ifade2;
Her switch deyimini else if yapsyla karlayabiliriz, ama her else if yapsn switch
deyimiyle karlayamayz. switch deiminin parantezi iindeki ifadenin tr tamsay olmak
zarundadr. case ifadeleri de tamsay sabit ifadesi olmak zarundadr. switch deyimi, tamsay
trnden bir ifadenin deerinin deiik tamsay deerlerine eitliinin test edilmesi ve eitlik
durumunda farkl ilerin yaplmas iin kullanlr. Oysa else if yapsnda her trl karlatrma
sz konusu olabilir.
rnek :
if (x > 20)
m = 5;
else if (x > 30 && x < 55)
m = 3;
else if (x > 70 && x < 90)
m = 7;
else
m = 2;
Yukardaki else if yapsn switch deyimiyle karlayamayz.
yle bir soru aklmza gelebilir : Madem her switch yapsn else if yapsyla
karlayabiliyoruz, o zaman switch deyimine ne gerek var? Yani switch deyiminin varl C
diline ne kazandryor?
switch deyimi baz durumlarda else if yapsna gre ok daha okunabilir bir yap
oluturmaktadr, yani switch deyiminin kullanlmas hereyden nce kodun daha kolay
okunabilmesi ve anlamlandrlmas asndan bir avantaj salayacaktr.
case ifadelerinin tam say trnden (integral types) sabit ifadesi olmas gerekmektedir.
Bilindii gibi sabit ifadeleri derleme aamasnda derleyici tarafndan net saysal deerlere
dntrlebilir.
case 1 + 3:
/* legal */
/* error */
nk sabit ifadesi deil. Derleyici derleme aamasnda saysal bir deer hesaplayamaz.
case a :
case 3.5 :
123
14
case FINDREC:
findrec();
break;
gibi. (Bu rnekte case ifadelerindeki ADDREC, DELREC vs. daha nce tanmlanm sembolik
sabitlerdir.)
Sembolik sabitler derleme ileminden nce nilemci tarafndan deitirilecekleri iin, case
ifadelerinde yer alabilirler :
#define TRUE
#define FALSE
#define UNDEFINED
...
1
0
2
case TRUE:
case FALSE:
case UNDEFINED:
Yukardaki ifadeler, sembolik sabitlerin kullanld geerli birer case ifadesidir.
char trnn de bir tamsay tr olduunu hatrlatarak case ifadelerinin doal olarak karakter
sabitleri de ierebileceini belirtelim.
char ch;
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 olmaz. Bu durum
derleme zamannda hata oluturur.
switch deyimi baka bir switch deyiminin, do while ya da for deyiminin gvdesini
oluturabilir. Bu durumda dardaki dngnn bloklanmasna gerek olmayacaktr, nk
switch deyimi gvdeyi oluturan tek bir deyim olarak ele alnacaktr :
...
for ((ch = getch()) != ESC)
switch (rand() % 7 + 1) {
case 1: printf("Pazartesi"); break;
case 2: printf("Sal"); break;
case 3: printf("aramba"); break;
case 4: printf("Perembe"); break;
case 5: printf("Cuma"); break;
case 6: printf("Cumartesi"); break;
case 7: printf("Pazar");
}
Yukardaki kod parasnda switch deyimi dtaki for dngsnn gvdesini oluturmaktadr,
ve switch deyimi tek bir deyim (kontrol deyimi) olarak ele alnacandan, dtaki for
dngsnn bloklanmasna gerek yoktur (tabi bloklama bir hataya neden olmayacaktr.) Ancak
case ifadeleri iinde yer alan break anahtar szcyle yalnzca switch deyiminden klr, for
dngsnn dna kmak iin case ifadesi iinde goto anahtar szc kullanlmaldr.
124
switch DEYM
Uygulama
Kendisine gnderilen bir tarihi ingilizce (15th Aug. 2000 ) formatnda ekrana yazan fonksiyonun.
void displaydate(int day, int month, int year);
#include <stdio.h>
#include <conio.h>
void dispdate(int day, int month, int year);
int main()
{
int day, month, year;
int n = 20;
clrscr();
while (n-- > 0) {
printf("gun ay yil olarak bir tarih giriniz : ");
scanf("%d%d%d", &day, &month, &year);
dispdate(day, month, year);
putchar('\n');
}
return 0;
switch (month) {
case 1 : printf("Jan "); break;
case 2 : printf("Feb "); break;
case 3 : printf("Mar "); break;
case 4 : printf("Apr "); break;
case 5 : printf("May "); break;
case 6 : printf("Jun "); break;
case 7 : printf("Jul "); break;
case 8 : printf("Aug "); break;
case 9 : printf("Sep "); break;
case 10: printf("Oct "); break;
case 11: printf("Nov "); break;
case 12: printf("Dec ");
}
printf("%d", year);
125
14
Uygulama
Kendisine gnderilen bir tarihin (gn, ay, yl ) o yln kanc gn olduunu bulan fonksiyon.
#include <stdio.h>
#include <conio.h>
int isleap(int year);
int dayofyear(int day, int month, int year);
int main()
{
int n = 20;
int day, month, year;
clrscr();
while (n-- > 0) {
printf("gun ay yil olarak bir tarih giriniz : ");
scanf("%d%d%d", &day, &month, &year);
printf("%d yilinin %d. gunudur.\n", year, dayofyear(day, month, year));
}
return 0;
Uygulama
01.01.1900 31.12.2000 tarihleri arasnda geerli rasgele tarih reterek ekrana yazan
fonksiyon.
#include
#include
#include
#include
<stdio.h>
<conio.h>
<stdlib.h>
<time.h>
switch DEYM
int main()
{
int n = 20;
clrscr();
srand(time(NULL));
while (n-- > 0) {
randomdate();
putchar('\n');
}
return 0;
}
int isleap(int year)
{
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)
return year;
return 0;
}
void randomdate(void)
{
int day, month, year;
int monthdays;
year = rand() % 101 + 1900;
month = rand() % 12 + 1;
switch (month) {
case 4:
case 6:
case 9:
case 11: monthdays = 30; break;
case 2: monthdays = isleap(year) ? 29 : 28; break;
default : monthdays = 31;
}
day = rand() % monthdays + 1;
printf("%02d - %02d - %d", day, month, year);
}
Uygulama
int make_char_eng(char ch); fonksiyonu. Kendisine gnderilen karakter trke'ye zel
karakterlerden birisi ise (, , , vs.) bu karakterlerin ingilizce benzerine aksi halde karakterin
kendisine geri dnen fonksiyon:
#include <stdio.h>
#include <conio.h>
int make_char_eng(char ch);
int main()
{
int ch;
while ((ch = getch()) != 'q')
putchar(make_char_eng(ch));
return 0;
127
14
}
int make_char_eng(char ch)
{
switch (ch) {
case '': return 'c';
case '': return 'g';
case '' : return 'i';
case '': return 'o';
case '': return 's';
case '': return 'u';
case '': return 'C';
case '': return 'G';
case '': return 'I';
case '': return 'O';
case '': return 'S';
case '': return 'U';
default : return ch;
}
}
alma Sorusu:
ki basamakl bir sayy yaz olarak ekrana basan num_text isimli fonksiyonu yaznz.
Fonksiyonun prototipi :
void num_text(int n);
eklindedir.
Fonksiyonun parametre deikeni yazlacak olan iki basamakl saydr. Aadaki programla test
edebilirsiniz :
#include <stdio.h>
void num_text(int n);
int main()
{
for (k = 10; k < 100; ++k) {
num_text(k);
putchar('\n');
getch();
}
return 0;
}
128
NLEMC KAVRAMI
nilemci
derleyici
ama program
129
15
#include, ilgili kaynak dosyann derleme ilemine dahil edileceini anlatan bir nilemci
komutudur. Bu komut ile nilemci belirtilen dosyay diskten okuyarak komutun yazl olduu
yere yerletirir. (metin editrlerindeki copy paste ilemi gibi)
#include komutundaki dosya ismi iki biimde belirtilebilir:
1. Asal parantezlerle:
#include <stdio.h>
#include <time.h>
2. ift trnak ierisinde:
#include "stdio.h"
#include "deneme.c"
Dosya ismi eer asal parantezler iinde verilmise, szkonusu dosya nilemci tarafndan
yalnzca nceden belirlenmi bir dizin ierisinde aranr. altmz 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. Genellikle standart balk dosyalar nilemci tarafndan belirlenen dizinde
olduundan, asal parantezler ile kaynak koda dahil edilirler.
Dosya ismi iki trnak iine yazldnda nilemci ilgili dosyay nce allan dizinde (current
directory), burada bulamazsa bu kez de sistem ile belirlenen dizinde arayacaktr. rnein:
C:\SAMPLE
dizininde alyor olalm.
#include "strfunc.h" komutu ile nilemci strfunc.h dosyasn nce C:\SAMPLE dizininde arar.
Eer burada bulamazsa bu kez sistem ile belirlenen dizinde arar. Programclarn kendilerinin
oluturduklar balk dosyalar genellikle sisteme ait dizinde olmadklar iin iki trnak iinde
kaynak koda dahil edilirler.
#include ile koda dahil edilmek istenen dosya ismi dosya yolu da (path) de ierebilir:
#include <sys\stat.h>
#include "c:\headers\myheader.h"
....
gibi.
Bu durumda asal parantez ya da iki trnak gsterimleri arasnda bir fark yoktur. Her iki
gsterimde de nilemci ilgili dosyay yalnzca yolun belirttii dizinde arar.
#include komutu ile yalnzca baslk dosyalarnn koda dahil edilmesi gibi bir zorunluluk yoktur.
Herhangi bir kaynak dosya da bu yolla kaynak koda dahil edilebilir.
130
NLEMC KAVRAMI
prog.c
#include "topla.c"
int main()
{
toplam = a + b;
printf("%d", toplam);
return 0;
}
topla.c
int a = 10;
int b = 20;
int toplam;
Yukardaki rnekte #include "topla.c" komutu ile nilemci komutunun bulunduu yere topla.c
dosyasnn ieriini yerletirecek bylece prog.c dosyas derlendiinde herhangi bir hata
olumayacaktr.
nk artk derleme ilemine girecek dosya:
int a = 10;
int b = 20;
int toplam;
int main()
{
toplam = a + b;
printf("%d", toplam);
return 0;
}
eklinde olacaktr.
#include komutu kaynak programn herhangi bir yerinde bulunabilir. Fakat standart balk
dosyalar gibi, ierisinde eitli bildirimlerin bulunduu dosyalar iin en iyi yer kukusuz
programn en tepesidir.
#include komutu iie gemi (nested) bir biimde de bulunabilir. rnein ok sayda dosyay
kaynak koda dahil etmek iin yle bir yntem izleyebiliriz.
ana.c
project.h
#include "project.h"
#include
#include
#include
#include
int main()
{
...
}
<stdio.h>
<conio.h>
<stdlib.h>
<time.h>
ana.c dosyas ierisine yalnzca project.h dahil edilmitir. nilemci bu dosyay kaynak koda
dahil ettikten sonra yoluna bu dosyadan devam edecektir.
131
15
nilemci define anahtar szcnden sonra boluklar atarak ilk boluksuz yaz kmesini elde
eder. (Buna STR1 diyelim.) Daha sonra boluklar atarak satr sonuna kadar olan tm
boluklarn kmesini elde eder. (Buna da STR2 diyelim) Kaynak kod ierisinde STR1 yazs
yerine STR2 yazsn yerletirir. (STR2 yazs yalnzca boluktan ibaret de olabilir. Bu durumda
STR1 yazs yerine boluk yerletirilir, yani STR1 yazs silinmi olur.) rnekler :
#define SIZE
100
nilemci komutuyla, nilemci kaynak kod ierisinde grd tm SIZE szckleri yerine 100
yerletirecektir. Derleme modlne girecek kaynak programda artk SIZE szc hi yer
almayacaktr.
#define kullanlarak bir yaznn bir saysal deerle yer deitirmesinde kullanlan yazya
"sembolik sabit" (symbolic constants) denir. Sembolik sabitler nesne deildir. Derleme
modlne giren kaynak kodda sembolik sabitler yerine bunlarn yerini saysal ifadeler alm
olur.
Sembolik sabitler basit makrolar (simple makro) olarak da isimlendirirler ama biz "sembolik
sabit" demeyi yeliyoruz.
Sembolik sabitlerin kullanlmasnda 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 50 deeri atanr. Ancak n ilemci komutunu
#define MAX
(10 + 20)
MAX
MIN
100
(MAX - 50)
nilemci " " ierisindeki yazlarda deiiklik yapmaz. (stringlerin blnemeyen atomlar
olduunu hatrlayalm.) Yer deitirme ilemi byk kk harf duyarl ile yaplr. Ancak
sembolik sabitler geleneksel olarak byk harf ile isimlendirilirler. Bunun nedeni, kodu okuyan
kiinin deikenlerle sembolik sabitleri ayrt edebilmesine yardmc olmaktr. Bilindii gibi
geleneksel olarak deiken isimlendirmesinde C dilinde arlkl olarak kk harfler
kullanlmaktadr.
#define komutu ile ancak deikenler ve anahtar szckler yer deitirilebilir. Sabitler ve
operatrler yer deitiremez.
Aadaki #define nilemci komutlar geerli deildir:
#define
#define
+
100
200
132
NLEMC KAVRAMI
10
tanmlamasnda hata oluur. (Hata tanmlama satrnda deil sembolik sabitin kod iinde
kullanld yerlerde oluur. Tanmlanan sembolik sabit kod iinde kullanlmazsa hata da
olumayacaktr.)
nilemci #include komudu ile kaynak koda dahil edilen dosyann ierisindeki nilemci
komutlarn da altrr. inde semboli sabit tanmlamalar yaplm bir dosya #include komudu
ile kaynak koda dahil edildiinde, bu sembolik sabitler de kaynak kod iinde tanmlanm gibi
geerli olur.
#define sembolik sabit tanmlamalarnda stringler de kullanlabilir :
#define
HATA_MESAJI
...
printf(HATA_MESAJI);
...
Sembolik sabit tanmlamasnda kullanlacak string uzunsa okunabilirlik asndan birden fazla
satra yerletirilebilir. Bu durumda son satr dnda dier satrlarn sonuna "\" karakteri
yerletirilmelidir.
nilemci deitirme ilemini yaptktan sonra #define komutlarn koddan kartr.
Okunabilirlik asndan tm sembolik sabit tanmlamalar alt alta getirecek ekilde yazlmaldr.
Seilen sembolik sabit isimleri kodu okuyan kiiye bunlarn ne amala kullanld hakknda fikir
vermelidir.
C'nin balk dosyalarnda baz sembolik sabitler tanmlanmtr. rnein stdio.h ierisinde
#define NULL
biiminde bir satr vardr. Yani stdio.h dosyas koda dahil edilirse NULL sembolik sabiti 0 yerine
kullanlabilir. math.h iinde de pek ok matematiksel sabit tanmlanmtr.
Bir sembolik sabitin tanmlanm olmas kaynak kod ierisinde deitirilebilecek bir bilginin
olmasn zorunlu hale getirmez. Tanmlanm bir sembolik sabitin kaynak kod ierisinde
kullanlmamas hataya yol amaz.
133
15
PI
3.14159
sembolik sabitini kullanabiliriz. Her defasnda pi saysnn sabit olarak koda girersek, her
defasnda ayn deeri yazamayabiliriz. rnein bazen 3.14159 bazen 3.14156
girebileceimiz gibi yanllkla 3.15159 da girebiliriz. Sembolik sabit kullanm bu tr
hatalar ortadan kaldrr.
4. Sembolik sabitler kullanlarak C sintaksnda kk deiiklikler yaplabilir.
#define
#define
#define
FOREVER
BEGIN
END
}
for(;;)
{
Byle bir sembolik sabit kullanmn kesinlikle tavsiye etmiyoruz. Okunabilirlii artrmas
deil azaltmas sz konusudur. Bir C programcs iin en okunabilir kod C'nin kendi
sentaksnn kullanld koddur.
#define komutu kaynak kodun herhangi bir yerinde kullanlabilir. Ancak tanmland yerden
kaynak kodun sonuna kadar olan blge ierisinde etki gsterir.
Ancak en iyi tanmlama yeri kaynak kodun tepesidir. Geleneksel olarak sembolik sabitler
#include satrlarndan (bir satr boluk verildikten sonra) hemen sonra yer alrlar.
N = 100 /* yanl */
Bu durumda nilemci N grd yere = 100 yaptracaktr. rnein int a[N] gibi bir dizi
tanmlanmsa nilemci bu tanmlamay a[N = 100] yapar ki bu da derleme aamasnda
hata (error) ile neticelenir.
2. Sembolik sabit tanmlama satrn ; ile sonlandrmak.
#define
100;
/* yanl */
Bu durumda nilemci N grd yere 100; yerletirir. int a[N]; tanmlamas int a[100;]
haline gelir. Derleme aamasnda hata oluur. (Borland derleyicileri hata mesaj :Array
bounds missing ])Bu tr hatalarda derleyici sembolik sabit ka yerde kullanlmsa o kadar
error verecektir.
3. Sembolik sabitlerle yer deitirecek ifadelerin operatr iermesi durumunda bu ifadeleri
paranteze almadan yerletirmek.
#define
...
SIZE
i = SIZE * 5
...
5 + 10
/* 5 + 10 * 5
= 55 (75 deil) */
134
goto DEYM
16
ak deiikliin yapld yere goto deyimleri ile atlatlm ise, bu noktalarda da bir
deiiklik yaplmas gerekebilerecektir.
Bu olumsuzluklara karn, baz durumlarda goto deyiminin kullanlmas programn
okunabilirliini bozmak bir yana, dier alternatiflere gre daha okunabilir bir yapnn
olumasna yardmc olacaktr:
ie birden fazla dng varsa, ve iteki dnglerden birindeyken, yalnzca bu dngden deil,
btn dnglerden birden klmak isteniyorsa goto deyimi kullanlmaldr.
Aadaki kod parasnda iie 3 dng bulunmaktadr. En iteki dngnn iinde func
fonksiyonu arlarak fonksiyonun geri dn deeri test edilmekte, fonksiyon eer 0 deerine
geri dnyorsa programn ak goto deyimiyle tm dnglerin dna ynlendirilmektedir:
int i, j, k;
...
for (i = 0; i < 100; ++i) {
...
for (j = 0; j < 100; ++j) {
...
for (k = 0 {
...
if (!func())
goto BREAK;
...
}
}
}
BREAK:
printf("dng dndaki ilk deyim\n");
...
Oysa goto deyimini kullanmasaydk, ancak bir bayrak (flag) kullanarak, ve her dngnn
knda bayrak olarak kullanlan deikenin deerinin deitirilip deitirilmediini kontrol
ederek bunu baarabilirdik:
int i, j, k;
int flag = 0;
...
for (i = 0; i < 100; ++i) {
...
for (j = 0; j < 100; ++j) {
...
for (k = 0; k < 100; ++k) {
...
if (!func()) {
flag = 1;
break;
}
...
}
if (flag)
break;
}
if (flag)
break;
136
goto DEYM
}
printf("dng dndaki ilk deyim\n");
...
Yine aadaki kod parasnda goto deyimiyle hem switch deyiminden hem de switch
deyiminin iinde bulunduu for dngsnden klmaktadr.
...
int main()
{
int option;
for (;;) {
option = get_option();
switch (option) {
case ADDREC
:addrec();break;
case LISTREC
:listrec();break;
case DELREC
:delrec(); break;
case SORTREC :sortrec(); break;
case EXITPROG
:goto EXIT;
}
}
EXIT:
return SUCCESS;
}
Yukardaki kod parasnda option deikeninin deeri
EXITPROG olduunda programn ak
goto deyimiyle
sonsuz dngnn dna gnderilmitir. goto deyimi yerine break anahtar szc kullanlsayd,
yalnzca switch deyiminden klm olunacakt.
137
16
Yukardaki kaynak kodla oluturulan programn her altrlmasnda ekrana ayn saylar
yazlacaktr. rnein yukardaki program DOS altnda Borland Turbo C 2.0 derleyicisi ile
derleyip altrdmzda ekran kts aadaki gibi oldu:
346 130 10982 1090 11656 7117 17595 6415 22948 31126
Oluturulan program her altrldnda neden hep ayn say zinciri elde ediliyor? rand
fonksiyonu rasgele say retmek iin bir algoritma kullanyor. Bu algoritma derleyiciden
derleyiciye deisede, rasgele say retiminde kullanlan ana tema ayndr. Bir balang deeri
ile ie balanr. Buna tohum deer diyoruz. Bu deer zerinde baz ilemler yaplarak rasgele
138
139
16
Yukardaki rnek program her altnda farkl say zinciri retecek hale 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 rasgele say retmek isteyebiliriz. Bu durumda mod
operatr kullanlabilir :
rand()
rand()
rand()
rand()
%
%
%
%
2
6
6+1
6+3
Karmak olaslk problemleri, olsla konu olayn bir bilgisayar program ile simule edilemesi
yoluyla zlebilir. yi bir rasgele say reticisi kullanld takdirde, olasla konu olay bir
bilgisayar program ile simule edilir ve olay bilgisayarn ilem yapma hzndan faydanlanlarak
yksek saylarda tekrar ettirilir. phesiz hesap edilmek istenen olaya ilikin olaslk deeri,
yaplan tekrar saysna ve rasgele say reticisinin kalitesine bal olacaktr. Aadaki kod yaz
tura atlmas olaynda tura gelme olasln hesap etmektedir.
#include
#include
#include
#include
<stdio.h>
<conio.h>
<stdlib.h>
<time.h>
#define TIMES
#define HEADS
100
1
int main()
{
long heads_counter = 0;
long k;
for (k = 0; k < TIMES; ++k)
if (rand() % 2 == HEADS)
heads_counter++;
printf("tura gelme olasl = %lf", (double) heads_counter / TIMES);
getch();
}
return 0;
Yukardaki program TIMES sembolik sabitinin farkl deerleri iin altrdmzda ekran kts
aadaki ekilde oldu:
#define TIMES 100
tura gelme olasl = 0.480000
#define TIMES 500
tura gelme olasl = 0.496000
140
<stdio.h>
<conio.h>
<stdlib.h>
<time.h>
#define TIMES
20
void write_word(void);
int main()
{
int k;
srand(time(0));
for (k = 0; k < TIMES; ++k) {
write_word();
putchar('_);
}
getch();
return 0;
}
void write_word(void)
{
int len = rand() % 6 + 3;
while (len--)
putchar('A' + rand() % 26);
}
Programn ekran kts:
USPFY
KDUP
BUQJB
LMU
PKPBKFA
WQM
NQHPTXL
QCANSTEH
XZU
141
16
MNRI
OXUTGISR
XBNG
BYOQ
TFO
MQUCSU
OIHFPJ
BLVD
WDDEM
OHMHJBZY
ALIAQ
142
DZLER
18 . BLM : DZLER
Bellekte ardl bir biimde bulunan ve ayn trden nesnelerin oluturduu veri yapsna dizi
(array) denir. Dizilerin kullanlmasn gerektiren iki nemli zellikleri vardr:
1. Dizi elemanlar bellekte ardl (contiguous) olarak bulunurlar.
2. Dizi elemanlar ayn trden nesnelerdir.
Diziler bileik nesnelerdir. Yani bir dizinin tanmlanmasyla birden fazla sayda nesne birlikte
tanmlanabilir. (Bileik szc ingilizce "aggregate" szcnn karl olarak kullanlmtr.)
10 elemanlk bir dizi tanmlamak yerine, phesiz farkl isimlere sahip 10 ayr nesne de
tanmlanabilir. Ama 10 ayr nesne tanmlandnda bu nesnelerin bellekte ardl olarak
yerlemeleri garanti altna alnm bir zellik deildir. Oysa dizi tanmlamasnda, dizinin eleman
olan btn nesnelerin bellekte ardl olarak yer almalar garanti altna alnm bir zelliktir.
Dizilerde bir veri tr olduuna gre dizilerin de kullanlmalarndan nce tanmlanmalar
gerekir.
Dizilerin Tanmlanmas
Dizi tanmlamalarnn genel biimi:
<tr> <dizi ismi> [<eleman says>];
Yukaridaki gsterimde keli parantez eleman saysnn seimlik olduunu deil, eleman says
bilgisinin keli parantez iine yazlmas gerektiini gstermektedir.
tr
dizi ismi
eleman says
100
/* geerli bir bildirimdir */
Dier deiken bildirimlerinde olduu gibi, virgl ayracyla ayrlarak, birden fazla dizi tek bir
tr belirten anahtar szckle tanmlanabilir.
143
18
...
a[0]
a[1]
a[2]
a[3]
a[4]
...
10 byte
Dizi kullanmnn getirdii en byk avantaj dng deyimleri kullanarak tm dizi elemanlarn
kolay bir ekilde eriilebilmesidir.
Dizi indis ifadelerinde ++ ya da operatrlerinin kullanld sk grlr.
int a[20];
int k = 10;
int i =5;
144
DZLER
a[k++] = 100; /* a dizisinin 10 indisli elemanna yani 11. elemanna 100 deeri atanyor. */
a[--i] = 200;
/* a dizisinin 4 indisli elemanna yani 5. elemanna 200 deeri atanyor. */
ndex operatrnn kullanlmasyla artk dizinin herhangi bir eleman dier deikenler gibi
kullanlabilir.
rnekler:
a[0] = 1;
/* a dizisinin ilk elemanna 0 deeri atanyor. */
printf(%d\n, sample[5]);
/* sample dizisinin 6. eleman yazdrlyor. */
++val[3];
/* val dizisinin 4. eleman 1 artrlyor. */
val[2] = sample[2];
/* val dizisinin 3. elemanna sample dizisinin 3. eleman atanyor. */
Diziler zerinde ilem yapmak iin sklkla for ve while dngleri kullanlr. Aada SIZE
elemanl ve sample isimli bir dizi iin for ve while dnglerinin kullanld baz kalplar
gsterilmektedir:
for (i = 0; i < SIZE; ++i)
sample[i] = 0;
i = 0;
while (i < SIZE) {
sample[i] = 0;
++i;
}
/* sample dizisinin btn elemanlar sfrlanyor */
for (i = 0; i < SIZE; i++) {
scanf(%d, &sample[i]);
++i;
}
i = 0;
while (i < SIZE) {
scanf(%d, &sample[i]);
++i;
}
/* sample dizisinin elemanlarna scanf fonksiyonuyla klavyeden deer aliniyor.*/
for (i = 0; i < SIZE; i++)
total += sample[i];
i = 0;
while (i < SIZE) {
total += sample[i];
++i;
}
/* sample dizisinin elemanlar toplaniyor. */
Bir dizi tanmlamas yapld zaman derleyici tanmlamas yaplm dizi iin bellekte toplam dizi
uzunluu kadar yer ayrr. rnein :
double a[10];
gibi bir tanmlama yapldnda dizi iin bellekte ardl (contigious) toplam 80 bytelk bir yer
ayrlacaktr.
145
18
Dizinin son eleman a[9] olacaktr. ok sk yaplan bir hata, dizinin son eleman diye bellekte
derleyici tarafndan tahsis edilmemi bir yere deer atamaktr.
a[10] = 5.;
deyimiyle bellekte rasgele 8 bytelk bir alana (gvenli olmayan) bir yere 5. deeri
yazlmaktadr.
Dizilere ilk deer verilmesi (array initialization)
Dizilere ilk deer verme ileminin genel ekli aadaki gibidir :
<tr> <dizi ismi>[[uzunluk]] = {d1, d2, d3........};
rnekler :
double sample[5] = {1.3, 2.5, 3.5, 5.8, 6.0};
char str[4] = {d, i, z, i};
unsigned[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
Dizilere yukardaki gibi ilk deer verildiinde, verilen deerler dizinin ilk elemanndan
balayarak dizi elemanlarna srayla atanm olur.
Dizilerin tm elemanlarna ilk deer verme zorunluluu yoktur. Dizinin eleman saysndan daha
az sayda elemana ilk deer verilmesi durumunda kalan elemanlara otomatik olarak 0 deeri
atanm olur. Bu kural hem yerel hem de global diziler iin geerlidir.
Bu durumda btn dizi elemanlarna 0 deeri atanmak isteniyorsa bunun en ksa yolu :
int a[20] = {0};
yalnzca dizinin ilk elemanna 0 deeri vermektir. Bu durumda derleyici dizinin kalan
elemanlarna otomatik olarak 0 deeri atayacaktr.
Dizi elemanlarna ilk deer verilmesinde kullanlan ifadeler, sabit ifadeleri olmaldr.
int a[10] = {b, b + 1, b + 2};
gibi bir ilk deer verme ilemi derleme zaman hatas oluturur.
Bir diziye ilk deer verme ileminde dizi eleman saysndan daha fazla sayda ilk deer vermek
derleme zamannda hata oluumuna neden olur :
int b[5] = {1, 2, 3, 4, 5, 6};
/* error */
yukardaki rnekte b dizisi 5 elemanl olmasna karn, ilk deer verme ifadesinde 6 deer
kullanlmtr.
dizi elemanlarna ilk deer verme ileminde dizi uzunluu belirtilmeyebilir, bu durumda
derleyici dizi uzunluunu verilen ilk deerleri sayarak kendi hesaplar ve dizinin o uzunlukta
aldn kabul eder. rnein :
int sample[] = {1, 2, 3, 4, 5};
derleyici yukardaki ifadeyi grdnde sample dizisinin 5 elemanl olduunu kabul edecektir.
Bu durumda yukardaki gibi bir bildirimle aadaki gibi bir bildirim edeer olacaktr:
int sample[5] = {1, 2, 3, 4, 5};
146
DZLER
baka rnekler :
char name[ ] = {N, e, c, a, t, i , E, r, g, i, n, \0};
unsigned short count[ ] = {1, 4, 5, 7, 8, 9, 12, 15, 13, 21};
derleyici name dizisinin uzunluunu 13, count dizisinin uzunluunu ise 10 olarak varsayacaktr.
yerel ve global diziler
Bir dizi de, dier nesneler gibi yerel ya da global olabilir. Yerel diziler bloklarn ilerinde
tanmlanan dizilerdir. Global diziler ise tm bloklarn dnda tanmlanrlar. Global bir dizinin
tm elemanlar global nesnelerin zelliklerine sahip olacaktr. Yani dizi global ise dizi eleman
olan nesneler dosya faaliyet alanna (file scope) sahip olacak, ve mr karakteri asndan da
statik mrl (static storage duration) olacaklardr. Global bir dizi sz konusu olduunda eer
dizi elemanlarna deer verilmemise, dizi elemanlar 0 deeriyle balatlacaktr. Ama yerel
diziler sz konusu olduunda, dizi eleman olan nesneler blok faaliyet alanna (block scope)
sahip olacaklar, mr asndan ise dinamik mr karakterinde olacaklardr. (dynamic storage
class) Deer atanmam dizi elemanlar iinde rasgele deerler (garbage values) bulunacaktr.
Aadaki rnei yazarak derleyicinizde yazarak deneyiniz :
#include <stdio.h>
int global[10];
main()
{
int yerel[10], i;
for (i = 0; i < 10; ++i)
printf(global[%d] = %d\n, i, global[i]);
/*
hata
*/
yukardaki gibi bir atama derleme zaman hatas verecektir. nk a ve b dizi isimleridir. C
dilinde dizi isimleri nesne gstermezler. Dizi isimleri dizilerin bellekte yerletirildikleri alann
balangcn gsteren ve dizinin tr ile ayn trden adres deerleridir. (Dolaysyla sabit
deerlerdir.)
Dizileri ancak bir dng kullanarak kopyalayabiliriz :
for (i = 0; i < SIZE; ++i)
a[i] = b[i];
Yukardaki dng deyimiyle b dizisinin her bir elemannn deeri a dizisinin ilgili indisli
elemanna atanmtr. Dizilerin kopyalanmas iin baka bir yntem de bir standart C
fonksiyonu olan memcpy (memory copy) fonksiyonunu kullanmaktr. Bu fonksiyon gstericiler
konusundan sonra ele alnacaktr.
dizilerle ilgili uygulama rnekleri:
147
18
Dizilerin kullanlmasn tevik eden temel nedenlerden biri ayn trden nesnelerin bir dizi altnda
tanmlanmasyla, dngler yardmyla dizi elemanlarnn ok kolay bir ekilde ileme
tutulabilmesidir. Aadaki rneklerde bu temalar ilenmitir :
Uygulama 1 : Bir dizi elemanlarnn toplamnn bulunmas
#include <stdio.h>
#include <conio.h>
#define SIZE
10
main()
{
int dizi[SIZE] = {12, 25, -34, 45, 67, 89, 24, -2, -15, 40};
int toplam = 0;
int k;
clrscr();
for (k = 0; k < SIZE; ++k)
toplam += dizi[k];
printf("dizi elemanlar toplam = %d\n", toplam);
return 0;
}
Uygulama 2 : bir dizi iindeki en kk sayy bulan program :
#include <stdio.h>
#include <conio.h>
#define SIZE
10
main()
{
int dizi[SIZE] = {12, 25, -34, 45, 67, 89, 24, -2, -15, 40};
int min, k;
clrscr();
min = dizi[0];
for (k = 1; k < SIZE; ++k)
if (min > dizi[k])
min = dizi[k];
printf("en kk eleman = %d\n", min);
return 0;
}
eer en kk elemann kendisiyle birlikte, dizinin kanc eleman olduu da bulunmak
istenseydi :
int indis;
...
for (k = 1; k < SIZE; ++k)
if (min > dizi[k]) {
min = dizi[k];
indis = k; /* en kk eleman yenilendike indisi baka bir deikende saklanyor. */
}
148
DZLER
Uygulama 3: Bir diziye klavyeden deer alarak daha sonra dizi elemanlarn ekrana yazdran
program :
#include <stdio.h>
#include <conio.h>
#define SIZE
10
main()
{
int dizi[SIZE];
int k;
clrscr();
for (k = 0; k < SIZE; ++k)
scanf("%d", &dizi[k]);
for (k = 0; k < SIZE; ++k)
printf("dizi[%d] = %d\n", k, dizi[k]);
return 0;
Uygulama 4 : Bir dizi ierisindeki elemanlar kkten bye doru bubble sort algoritmasyla
sraya dizen program:
#include <stdio.h>
#include <conio.h>
#define SIZE
10
main()
{
int dizi[SIZE] = {12, 25, -34, 45, -23, 29, 12, 90, 1, 20};
int i, k, temp;
clrscr();
for (i = 0; i < SIZE - 1; ++k)
for (k = 0; k < SIZE - 1; ++k)
if (dizi[k] > dizi[k + 1]) {
temp = dizi[k];
dizi[k] = dizi[k + 1];
dizi[k + 1] = temp;
}
for (i = 0; i < SIZE; ++i)
printf("dizi[%d] = %d\n", k, dizi[k]);
return 0;
Bu algoritmann performans basit bir dzenleme ile artrlabilir. Dtaki dngnn her
dnnde en byk say en sona gidecektir. Bu durumda iteki dngnn her defasnda SIZE
1 kez dnmesine gerek yoktur. teki dng SIZE 1 i kez dnebilir.
...
for (i = 0; k < SIZE - 1; ++k)
for (k = 0; k < SIZE - 1; ++k)
...
Bubble sort algoritmasn sraya dizme ilemi tamamlandnda dtaki dngy sonlandracak
biimde dzenleyebiliriz :
#include <stdio.h>
149
18
#include <conio.h>
#define SIZE
#define UNSORTED
#define SORTED
10
0
1
main()
{
int dizi[SIZE] = {12, 25, -34, 45, -23, 29, 12, 90, 1, 20};
int i, k, temp, flag;
for (i = 0; i < SIZE - 1; ++k) {
flag = SORTED;
for (k = 0; k < SIZE - 1; ++k)
if (dizi[k] > dizi[k + 1]) {
temp = dizi[k];
dizi[k] = dizi[k + 1];
dizi[k + 1] = temp;
flag = UNSORTED;
}
if (flag == SORTED)
break;
}
for (i = 0; i < SIZE; ++i)
printf("dizi[%d] = %d\n", i, dizi[i]);
return 0;
}
bu yeni dzenleme dierine gre daha iyi de olsa performans asndan ok ciddi bir farkll
yoktur.
Ayn algoritmay bir do while dngs kullanarak da yazabilirdik:
#include <stdio.h>
#include <conio.h>
#define SIZE
#define UNSORTED
#define SORTED
10
0
1
main()
{
int dizi[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 (dizi[k] > dizi[k + 1]) {
temp = dizi[k];
dizi[k] = dizi[k + 1];
dizi[k + 1] = temp;
flag = UNSORTED;
}
} while (flag == UNSORTED);
for (i = 0; i < SIZE; ++i)
printf("dizi[%d] = %d\n", i, dizi[i]);
return 0;
150
DZLER
}
Uygulama 5: Bir dizi ierisindeki elemanlar kkten bye insertion sort algoritmasyla
sraya dizen program:
#include <stdio.h>
#include <conio.h>
#define SIZE
10
main()
{
int dizi[SIZE] = {12, 25, -34, 45, -23, 29, 12, 90, 1, 20};
int i, j, temp;
clrscr();
for (i = 1; i < SIZE; ++i) {
temp = dizi[i];
for (j = i; j > 0 && dizi[j - 1] > temp; --j)
dizi[j] = dizi[j - 1];
dizi[j] = temp;
}
for (i = 0; i < SIZE; ++i)
printf("dizi[%d] = %d\n", i, dizi[i]);
return 0;
}
sralama ynn kkten bye yapmak yerine bykten ke yapmak iin ierideki
dngy
for (j = i; j > 0 && dizi[j - 1] < temp; --j)
eklinde deitirmek yeterli olacaktr.
Uygulama 6 : Bir dizi ierisindeki elemanlar kkten bye selection sort algoritmasyla
sraya dizen program:
#include <stdio.h>
#define
SIZE
10
int a[SIZE] = { 12, 23, 45, 78, -23, ,56, 78, 3, 9, -4};
int main()
{
int k, l, max, indis;
for (k = 0; k < SIZE; ++k) {
max = a[k];
indis = k;
for (l = k + 1; l < SIZE; ++l)
if (a[l] > max) {
max = a[l];
indis = l;
}
a[indis] = a[k];
a[k] = max;
151
18
}
for (k = 0; k < SIZE; ++k)
printf(%d\n, a[k]);
return 0;
}
karakter dizileri
Karakter dizileri char trden dizilerdir. Karakter dizilerinin baz ilave zellikler dnda dier dizi
trlerinden bir fark yoktur. char trden diziler daha ok ilerinde yaz tutmak iin tanmlanrlar.
char s[100];
yukardaki tanmlamada s dizisi btn elemanlar char trden olan 100 elemanl bir dizidir.
char trden bir dizi iinde bir yaz tutmak demek, dizinin herbir elemanna srayla yaznn bir
karakterini atamak anlamna gelecektir. (Bu arada char trden bir dizinin iinde bir yaz
tutmann zorunlu olmadn, byle bir dizinin pekala kk tamsaylar tutmak amacyla da
kullanlabileceini hatrlatalm)
Yukarda tanmlanan dizi iinde "Ali" yazsn tutmak isteyelim :
s[0] = 'A';
s[1] = 'l';
s[2] = 'i';
imdi yle bir problem ortaya kyor. Dizi 100 karakterlik olmasna karn biz dizi iinde 100
karakter uzunluundan daha ksa olan yazlar da tutabiliriz. Peki biz yazya tekrar ulamak
istediimizde bunu nasl yapacaz? Yaznn uzunluk bilgisini bilmiyoruz ki! rnein yazy
ekrana yazdrmak istediimizde, int trden dizilerde kullandmz ekilde aadaki gibi bir
dng kullanrsak :
for (k = 0; k < 100; ++k)
putchar(s[k]);
bu dng ile yalnzca ALi yazs ekrana yazdrlmayacak dizinin dier 97 elemannn da
grntleri (rasgele deerler) ekrana yazdrlacak.
Programlama dilleri bu duruma bir zm bulma konusunda iki temel yaklam benimserler.
a. Dizinin 1. elemanna yaznn uzunluk bilgisi yazlr. Bylece dizideki yazya ulalmak
istendiinde nce dizinin 1. elemanndan yaznn uzunluk bilgisi ekilir. Bylece dng
deyiminin iterasyon says deeri elde edilmi olur. Dng bu deere gre oluturulur.
s[0]
s[0]
s[1]
s[2]
=
=
=
=
3;
'A';
'l';
'i';
....
for (k = 1; k <= s[0]; ++k)
putchar(s[k]);
C dilinde bu yaklam kullanlmaz.
b. Dizinin elemanlarna yaznn karakterleri srasyla yerletirilir. Yaz bittikten sonra dizinin
sradaki elemanna zel bir karakter yerletirilir. Bu zel karakter doal olarak normal artlar
altnda bir yaznn eleman olamayacak bir karakter olarak seilmelidir. Bylece char trden dizi
iinde saklanm yazya tekrar ulalmak istendiinde, kullanlacak dng deyiminde, dizinin
152
DZLER
dng deikeni olan indisli elemannn seilen zel karaktere eit olmad srece dngnn
dnmesi art oluturulur. C dilinin tasarmnda bu yaklam tercih edilmitir.
C dilinde karakterler zerinde ilemlerin hzl ve etkin bir biimde yaplabilmesi iin sonlandrc
karakter (NULL KARAKTER) kavramndan faydalanlmaktadr.
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. Bu karakter DOS ve UNIX sistemlerinde sonlandrc karakter olarak
kullanlmaktadr. stdio.h ierisinde NULL sembolik sabiti 0 olarak tanmland iin sonlandrc
karaktere NULL karakter de denir. NULL karakter 0 karakteri ile kartrlmamaldr.
0 karakterinin ASCII sra numaras 48dir. Dolaysyla tamsay deeri olarak 48 deerine
sahiptir.
\0 karakterinin ASCII sra numaras 0dr. Dolaysyla tamsay deeri olarak 0 deerine
sahiptir.
...
printf(%d\n, 0);
printf(%d\n, \0);
...
yukardaki ilk printf fonksiyonunun arlmasyla ekrana 48 deeri yazdrlrken, ikinci printf
fonksiyonunun arlmasyla ekrana 0 deeri yazdrlmaktadr.
char trden dizilere ilk deer verilmesi
char trden dizilere ilk deer verme ilemi (initializing) aadaki biimlerde yaplabilir .
Dier trden dizilerde olduu gibi virgllerle ayrlan ilk deerler kme parantezi iinde yer alr :
char name[12] = {N, e, c, a, t, i, , E, r, g, i,n};
Dier dizilerde olduu gibi dizi eleman saysndan daha fazla sayda elemana ilk deer vermek
derleme zamannda hata oluumuna neden olur.
char name[5] = {N, e, c, a, t, i, , E, r, g, i,n};
/* error */
Dizi eleman says kadar elemana ya da dizi eleman saysndan daha az sayda elemana ilk
deer verilebilir. Daha az sayda elemana ilk deer verilmesi durumunda ilk deer verilmemi
elemanlar dier dizilerde olduu gibi 0 deeriyle balatlacaklardr. 0 deerinin NULL karakter
olduunu hatrlayalm :
char name [10] = {A, l, i};
...
A
l
i
\0
\0
\0
\0
\0
\0
\0
...
...
name[0]
name[1]
name[2]
name[3]
name[4]
name[5]
name[6]
name[7]
name[8]
name[9]
...
Dizi elemanlarna ilk deer verilirken dizi boyutu belirtilmeyebilir. Bu durumda derleyici dizi
boyutunu verilen ilk deerleri sayarak saptar ve diziyi bu boyutta alm varsayar.
153
18
deyimiyle
derleyici
name
dizisinin
elemanl
olarak
aldn
Boyut bilgisi vermeden, char trden dizilere tek tek ilk deer verilmesi durumunda, ve boyut
bilgisi verilerek dizinin toplam eleman says kadar elemana tek tek ilk deer verilmesi
durumunda, derleyici NULL karakteri dizinin sonuna otomatik olarak yerletirmeyecektir. Bu
durumda eer sonlandrc karakter zelliinden faydalanlmak isteniyorsa, NULL karakter de
verilen dier ilk deerler gibi programc tarafndan verilmelidir. rnek :
char name[ ] = {A, l, i, \0};
char isim[7] = {N, e, c, a, t, i, \0};
Bu ekilde ilk deer vermek zahmetli olduundan, ilk deer vermede ikinci bir biim
oluturulmutur. Karakter dizilerine ilk deerler ift trnak iinde de verilebilir :
char name[ ] = Ali;
bu biimin dierinden fark derleyicinin sonuna otomatik olarak NULL karakteri yerletirmesidir.
...
A
...
name[0
]
l
name[1
]
i
name[2
]
\0 name[3
]
yukardaki rnekte derleyici diziyi 4 elemanl olarak alm varsayacaktr. Dizi eleman
saysndan daha fazla sayda elemana ilk deer vermeye almak, bu biimin kullanlmas
durumunda da derleme zamannda hata oluumuna neden olacaktr.
char city[5] = stanbul;
/* error */
Bu durumun bir istisnas vardr. Eger tam olarak dizi eleman says kadar dizi elemanna ift
trnak iinde ilk deer verilirse bu durum ERROR oluturmaz. Derleyici bu durumda NULL
karakteri dizinin sonuna yerletirmez. Bu durum C dili standartlarna yneltilen eletirilerden
biridir. (C++ dilinde son kabul edilen standartlara gre bu durum da error oluturmaktadr.)
char name[3] =Ali;
...
A
l
i
...
...
name[0]
name[1]
name[2]
buraya
bu
durumda
yerletirilmiyor.
null
karakter
'\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 gerekmektedir. Ama char trden diziler sz konusu olduunda
artk dizi uzunluunu bilmemiz gerekmez, nk yaznn sonunda '\0' karakter bulunacandan,
kontrol ifadelerinde bu durum test edilerek yaznn sonuna gelinip gelinmedii anlalr. Ancak
'\0' karakterin, karakter dizilerinde yazlarn son eleman olarak kullanlmasnn dezavantaj da
154
DZLER
diziye fazladan bir karakter yani '\0' karakteri eklemek zorunluluudur. Bu nedenle SIZE
elemanl bir diziye en fazla SIZE 1 tane karakter girilmelidir.
klavyeden karakter dizisi alan ve ekrana karakter dizisi yazan standart C fonksiyonlar
Daha nce grdmz getchar, getch, ve getche fonksiyonlar klavyeden tek bir karakter
alyorlard. Yine putchar fonksiyonu ise tek bir karakteri ekrana yazyordu. C dilinde birden
fazla karakteri (bir stringi) klavyeden alan ya da birden fazla karakteri ekraana yazan standart
fonksiyonlar bulunmaktadr.
gets fonksiyonu
gets fonksiyonu klavyeden karakter dizisi almakta kullanlan standart bir C fonksiyonudur.
Kullanc karakterleri girdikten sonra enter tuuna basmaldr. Klavyeden girilecek karakterlerin
yerletirilecei dizinin ismini parametre olarak alr. daha nce de belirtildii gibi dizi isimleri
aslnda bir adres bilgisi belirtmektedir. gets fonksiyonunun da parametresi aslnda char trden
bir adrestir. Ancak gstericilerle ilgili temel kavramlar henz renmediimiz iin imdilik gets
fonksiyonunun char trden bir dizi iine klavyeden girilen karakterleri yerletirdiini kabul
edeceiz. rnein :
char name[20];
gets(name);
ile klavyeden enter tuuna baslana kadar girilmi olan tm karakterler name dizisi iine srayla
yerletirilirler. Klavyeden Necati yazsnn girildiini kabul edelim.
...
N
...
name[0
]
e name[1
]
c name[2
]
a name[3
]
t
name[4
]
i
name[5
]
\0 name[6
]
... ...
gets fonksiyonu klavyeden girilen karakterleri diziye yerletirdikten sonra dizinin sonuna NULL
karakter (sonlandrc karakter) diye isimlendirilen 0 numaral ASCII karakterini (ya da
kullanlan karakter setinin 0 numaral karakterini) koyar.
gets fonksiyonu dizi iin hi bir ekilde snr kontrolu yapmaz. gets fonksiyonu ile dizi eleman
saysndan fazla karakter girilirse, d,z, taaca iin beklenmeyen sonularla karlalabilir. Bu
tr durumlar gstericiler konusunda (gsterici hatalar) detayl olarak incelenecektir.
gets fonksiyonu \0 karakterini dizinin sonuna ekledii iin SIZE uzunluunda bir dizi iin gets
fonksiyonuyla alnacak karakter says en fazla SIZE 1 olmaldr. nk sonlandrc
karakterde dier karakterler gibi bellekte bir yer kaplamaktadr. rnek :
char isim[12];
gets(isim);
155
18
ile klavyeden Necati Ergin isminin girildiini dnelim.
...
N
e
c
a
t
i
E
r
g
i
...
isim[0]
isim[1]
isim[2]
isim[3]
isim[4]
isim[5]
isim[6]
isim[7]
isim[8]
isim[9]
isim[10
]
n isim[11
]
\0 tama
...
isim dizisinin tanmlanmasyla derleyici bu dizi iin bellekte 12 byte yer ayracaktr. isim[0]
...isim[11]
gets fonksiyonu bu durumda \0 karakterini derleyicinin dizi iin tahsis etmedii bir bellek
hcresine yazacaktr. Bu tr durumlara dizinin tarlmas (off bye one) denmektedir.
tama durumuyla ilgili olarak ortaya kacak hatalar derleme zamanna deil alma zamanna
(run time) ilikindir.
puts fonksiyonu
puts fonksiyonu bir karakter dizisinin ieriini ekrana yazdrmak iin kullanlr. erii
yazdrlacak olan karakter dizisinin ismini parametre olarak alr. puts fonksiyonu karakter
dizisini ekrana yazdktan sonra imleci sonraki satrn bana geirir.
char name[20];
gets(name);
puts(name);
yukardaki rnekte gets fonksiyonu ile klavyeden alnan karakter dizisi puts fonksiyonu ile
ekrana yazdrlmaktadr.
karakter dizilerini ekrana yazdrmak iin printf fonksiyonu da kullanlabilir.
printf(%s\n, name);
ile
puts(name);
ayn ii yapmaktadr. Ancak printf fonksiyonu dizi ieriini ekrana yazdrdktan sonra imleci alt
satra tamaz.
puts(name);
deyimi yerine aadaki kod parasn da yazabilirdik.
for (i = 0; name[i] != \0; ++i)
putchar(s[i]);
putchar(\n);
156
DZLER
157
18
SIZE
100
main()
{
char s[SIZE];
int k;
100
main()
{
char s[SIZE];
int k;
printf ("bir yaz giriniz : ");
gets(s);
for (k = 0; s[k] != '\0'; ++k)
s[k] = isupper(s[k]) ? toupper(s[k]) : tolower(s[k]);
printf("dntrlm yaz \n");
puts(s);
return 0;
}
Uygulama 10 : Karakter dizisini tersyz eden program :
#include <stdio.h>
main()
158
DZLER
{
char s[50];
int n, j, temp,
gets(s);
for (n = 0; s[n] != \0; ++n)
;
for (j = 0; j < n / 2; ++j) {
temp = s[n j 1];
s[n j 1] = s[j];
s[j] = temp;
}
puts(s);
Uygulama 11 : bir karakter dizisi iindeki harfleri kkten bye doru sralayan bir program
#include <stdio.h>
#define
#define
SIRALI
SIRASIZ 0
main()
{
char s[100];
int flag, k, temp;
clrscr();
printf("bir yaz giriniz :");
gets(s);
do {
flag = SIRALI;
for (k = 0; s[k + 1] != '\0'; ++k)
if (s[k] > s[k + 1]) {
temp = s[k];
s[k] = s[k + 1];
s[k + 1] = temp;
flag = SIRASIZ;
}
} while (flag == SIRASIZ);
printf("sralanm yaz :\n");
puts(s);
getch();
159
19
19 . BLM : GSTERCLER
Adres Kavram
Adres kavram hem donanma hem de yazlma ilikindir. Donanmsal adan adres bellekte yer
gsteren bir saydan ibarettir. Mikroilemci bellekte bir blgeye ancak o blgenin adres
bilgisiyle eriebilir. Bellekte (RAM'de) her byte (8 bit) dierlerinden farkl bir adresle temsil
edilir. Sfr saysndan balayarak her bytea artan srada bir karlk getirerek elde edilen
adresleme sistemine dorusal adresleme sistemi (linear addressing), bu sistem kullanlarak
elde edilen adreslere de dorusal adresler denilmektedir. Donanmsal olarak RAM'deki her bir
byte'a okuma ya da yazma yapma amacyla ulalabilir.
rnein, 64 Klk bir bellein dorusal olarak adreslenmesi aadaki biimde yaplabilir :
BELLEK DORUSAL ADRES
0 (0000)
1
2
3
4
.......... ..................
.
65533 (FFFD)
65534 (FFFE)
65535 (FFFF)
Bilgisayara ilikin pekok nitelikte olduu gibi dorusal adreslemede de 10luk sistem yerine
16lk sistemdeki gsterimler tercih edilir. Bundan byle yalnzca adres dendiinde dorusal
adres anlalmaldr.
Nesnelerin Adresleri
Her nesne bellekte yer kapladna gre belirli bir adrese sahiptir. Nesnelerin adresleri,
sistemlerin ounda, derleyici ve program ykleyen iletim sistemi tarafndan ortaklaa olarak
belirlenir. Nesnelerin adresleri program yklenmeden nce kesin olarak bilinemez ve programc
tarafndan da nceden tespit edilemez. Programc, nesnelerin adreslerini ancak programn
almas srasnda (run time) renebilir. rnein:
char ch;
biiminde bir tanmlamayla karlaan derleyici bellekte ch deikeni iin 1 byte yer ayracaktr.
Derleyicinin ch deikeni iin bellekte hangi byte' ayracan nceden bilemeyiz. Bunu ancak
programn almas srasnda renebiliriz. Yukardaki rnekte ch yerel bir deikendir. ch
deikeni ilgili blok icra edilmeye balandnda yaratlp, bloun icras bittiinde de yok
olmaktadr. ch deikeninin 1A03 adresinde olduu varsaylarak aadaki ekil izilmitir:
ch
1A00
1A01
1A02
1A03
1A04
1A05
Tanmlanan nesne 1 bytedan daha uzunsa, o zaman nesnenin adresi nasl belirlenir?
int b;
1C00
160
GSTERCLER
1C01
1C02
1C03
1C04
1C05
1C06
1C07
1 bytedan uzun olan nesnelerin adresleri, onlarn ilk bytelarnn (dk anlaml bytelarnn)
adresleriyle belirtilir. Yukardaki rnekte x deikeninin adresi 1C03tr. Zaten x deikeninin
tamsay trnden olduu bilindiine gre dier parasnn 1C04 adresinde olaca da aktr.
Benzer biimde long trnden olan y deikeninin bellekteki yerleiminin aadaki gibi olduu
varsaylrsa, adresinin 1F02 olduunu syleyebiliriz:
1F00
1F01
1F02
1F03
1F04
1F05
1F06
1F07
Yerel ya da global olsun, ardl (contigious) bir biimde tanmlanm nesnelerin bellekte de
ardl bir biimde tutulacann bir garantisi yoktur. rnein:
{
int x;
char ch;
...
}
Buradaki ch deikeninin x deikeninden 2 byte sonra bulunacann bir garantisi yoktur.
161
19
Adreslerin Trleri
Bir adresin tr demekle o adrese ilikin bellek blgesinde bulunan bilginin derleyici tarafndan
yorumlan biimi anlalmaldr. rnein:
char ch;
gibi bir bildirim sonrasnda ch deikeninin bellee aadaki biimde yerlemi olduunu kabul
edelim:
ch
1A00
1A01
1A02
1A03
1A04
1A05
Yukardaki ekle baktmzda 1A03 saysnn bir adres belirttiini anlyoruz. 1A03 adresinde
bulunan bilgi char trdendir. nk derleyici 1A03 adresinde bulunan bilgiyi char trden bir
nesne olarak yorumlamaktadr. Adres yalnz bana saysal bileeniyle bir anlam tamaz,
gsterdii trle birlikte belirtilmesi gerekmektedir.
Cde adres bilgisi ayr bir veri/nesne trdr. Daha nce grdmz 11 temel veri trne
ilaveten 11 ayr adres trnn de varlndan sz edebiliriz.
Adres Sabitleri
Adresler tamsay grnmnde olsalar da tamsay sabitleri gibi belirtilmezler. nk tr
bilgilerinin de belirtilmesi gerekir. Adres sabitleri, tamsay trlerindeki sabitler zerinde bilinli
tr dnm yaplarak elde edilirler. Bir tamsay sabitini adres trne evirmek iin tr
dntrme operatr kullanlr.
(<tr> *) <tamsay sabiti>
Tr dntrme operatrnn iindeki * adres ya da gstericiyi temsil etmektedir. rnein
0x1F00
hexadesimal olarak gsterilmi int trden bir sabittir. Ancak:
(int *) 0x1F00
int trnden bir adres sabitidir.
0x16C0L
long trden bir tamsay sabittir. Ancak:
(long *) 0x16C0L
long trden bir adres sabitidir. Bunun anlam udur: Derleyici 16C0 adresiyle belirtilen yerdeki
bilgiyi long olarak yorumlayacaktr.
Adres trne bilinli dnm yalnz sabitlerle yaplmayabilir, rnein:
(char *) var
var isimli deiken hangi trden olursa olsun, yukardaki ifade ile char trden bir adres haline
dntrlmtr.
162
GSTERCLER
Bir adres bilgisini bir nesne iinde tutmak isteyelim. (u an iin neden byle bir ey
isteyebileceimiz sorusu akla gelebilir, ama ileride bunun ok doal ve gerekli bir ilem
olduunu greceiz.) Bu ii nasl gerekletireceiz? lk olarak aklmza u gelebilir: int trden
bir nesne tanmlayalm ve adresin saysal bileenini tanmladmz int trden nesne iinde
tutalm. Yani adresin saysal bileeni olan tamsayy int trden bir nesneye atayalm. Bu
durumda iki nemli saknca ortaya kacaktr:
Sz konusu int nesnenin deerine programn herhangi bir yerinde tekrar ulatmzda, bunun
bir adres bilgisinin (yani iki bileenli bir bilginin) saysal bileeni mi yoksa int trden normal bir
deer mi olarak yorumlanacan nereden bileceiz? Peki rnein deikenin isminden,
deerinin bir adres bilgisinin saysal bileeni olduu sonucunu kardmz dnelim, bu
durumda adresin tr bileeninin ne olduunu nereden anlayacaz?
O zaman belki de u nerilecektir: int trden bir adres bilgisini int trden bir nesnede, char
trden bir adres bilgisini char trden bir nesnede, double trden bir adres bilgisini ise double
trden bir nesnede saklayalm, vs. Ama rnein 64K'lk bir adres alannn sz konusu olduunu
dnelim. toplam 65535 byte sz konusu olabileceine gre bize 2byte uzunluunda bir nesne
gerekecek. rnein 1 byte uzunlukta bir nesne iinde ancak ilk 255 byte'a ilikin saysal
bileenleri tutarken, 8 byte uzunluunda bir nesne iinde de gerekmedii halde ok byk bir
alana ilikin adres bilgisini tutabiliriz.
int sabitleri int trden deikenlere, gerek say sabitleri gerek say trnden deikenlere
doal olarak atanyorlar. Yani her sabit trnn doal olarak atanabilecei trden bir deiken
tanmlayabiliyoruz. te adres de ayr bir tr olduuna gre adres trnn de doal olarak
atanabilecei deikenler tanmlanabilir. Bu deikenlere (nesnelere) gsterici (pointer) denir.
a
/* char trden bir sabittir */
char a;
/* a char trden bir deikendir */
int b;
/* b int trden bir deikendir */
2000L
/* long trden bir sabittir */
long l;
/* l long trden bir deikendir */
(<tr> *) 0x1B00
/* adres sabiti */
pointer
/* iinde adres tutan bir deiken */
Gsterici (pointer) iinde adres bilgisi tutan bir deikendir (nesnedir). Gstericiler de nesne
olduklar iin bellekte bir yer kaplarlar. Gstericilerin bellekte kapladklar yerdeki 1ler ve
0larn bir tamsay olarak yorumlanr, ve yorumlanan bu deer bir adres bilgisinin saysal
bileenini gsterir.
Peki adres bilgisinin iki bileenli bir bilgi olduunu sylemitik. Gstericinin deeri adresin
saysal bileeni olarak yorumlanacaksa adresin tr bileeni nasl elde edilecek? Zira bellekte
yalnzca 1 ler ve 0 lar var. Gstericilerin tuttuu adres bilgilerinin saysal bileenleri gstericiler
iinde saklanan tamsaynn deeridir. Adres bilgisinin tr bileeni ise gstericinin tanmlanmas
srasnda bildirilen trdr.
Gstericilerin Bildirimleri
Gstericiler adres bilgilerini saklamak ve adreslerle ilgili ilemler yapmak iin kullanlan
nesnelerdir. Gstericilerin ilerinde adres bilgileri bulunur. Bu nedenle gsterici ile adres hemen
hemen e anlaml olarak dnlebilir. Ancak gsterici deyince bir nesne, adres deyince bir tr
akla gelmelidir.
Gsterici bildirimlerinin genel biimi yledir:
<tr> *<gsterici ismi>;
<tr> gstericinin (ierisindeki adresin) trdr. char, int, float... gibi herhangi bir tr
olabilir.
Burada * gstericiyi ya da adresi temsil etmektedir.
163
19
Gstericilerin Uzunluklar
Bir gsterici tanmlamasyla karlaan derleyici dier tanmlamalarda yapt gibi- bellekte o
gsterici iin bir yer tahsis eder. Derleyicilerin gstericiler iin tahsis ettikleri yerlerin uzunluu
donanm baml olup, sistemden sisteme deiebilmektedir. 32 bit sistemlerde (rnein UNIX
ve Windows 95 sistemlerinde) gstericiler 4 byte uzunluundadr. 8086 mimarisinde ve DOS
altnda alan derleyicilerde ise gstericiler 2 byte ya da 4 byte olabilirler. DOSta 2 byte
uzunluunda ki gstericilere yakn gstericler (near pointer), 4 byte uzunluundaki
gstericilere ise uzak gstericiler (far pointer) denilmektedir. Biz uygulamalarmzda imdilik
gstericilerin 2 byte olduunu varsayacaz.
Gstericilerin uzunluklar trlerinden bamszdr. rnein:
char *str;
int *p;
float *f;
164
GSTERCLER
DOS altnda str, p ve f isimli gstericilerin hepsi de bellekte 2 byte ya da 4 byte yer kaplarlar.
nk gstericilerin tr yalnzca iinde tuttuklar adres bilgisinin hangi tr olarak
yorumlanaca ile ilgilidir.
Bir gstericiye ayn trden bir adres bilgisi yerletirilmelidir. rnein :
int *p;
p = 100;
Burada p gstericisine adres olmayan bir bilgi atanmaktadr. C dilinin kurallarna gre, derleme
zamannda bir hata oluumuna yol amaz ama yanltr. (Derleyiciler bu durumu bir uyar
mesaj ile bildirirler.) Bu durum ileride detayl olarak ele alnacaktr.
int *p;
p = (char *) 0x1FC0;
Burada int trden p gstericisine char trden bir adres bilgisi atanmaktadr. C dilinin
kurallarna gre, derleme zamanndan bir hata oluumuna yol amaz ama yanltr.
(Derleyiciler bu durumu bir uyar mesaj ile bildirirler.)
int *p;
p = (int *) 0x1FC5;
Bir adres bilgisi gstericiye atandnda adresin saysal bileeni gsterici ierisine yerletirilir.
int *p;
p = (int *) 0x1FC3;
Burada bellekte p gsterici deikeninin tutulduu yere 0x1FC3 saysal deeri yerletirilecektir.
...
0001
1111
1100
0011
...
Gstericilere kendi trlerinden bir adres bilgisi atanmasnn gerektiini sylemitik. imdiye
kadar adres bilgilerini yalnzca adres sabitleri eklinde grdk ve rneklerimizde de
gstericilere adres sabitlerini atadk. Peki adres sabitleri dnda adres bilgileri tayan baka
ifadeler mevcut mudur? Evet. rnein diziler konusunu incelerken dizi isimlerinin, nesne
gstermediini, bir adres bilgisi olduunu sylemitik, imdi bu konuyu daha detayl olarak
inceleyeceiz:
Dizi isimleri bir adres bilgisi belirtir. Adres bilgisinin iki bileeni olduuna gre rnein:
char s[10];
gibi bir dizi tanmlamas yapldnda dizi ismi olan s bir adres bilgisi belirtecektir. Peki bu
bilginin tr bileeni ve saysal bileenleri nelerdir?
Dizi isimleri, trleri dizinin trleriyle ayn ve saysal bileenleri dizi iin bellekte ayrlan bloun
balang yerini gsteren bir adres bilgisi olarak ele alnrlar. rnein yukardaki rnekte dizinin
bellekte aadaki ekilde yerletirildiini dnelim:
s[0] 1C00
165
19
s[1]
s[2]
s[3]
s[4]
s[5]
s[6]
s[7]
s[8]
s[9]
1C01
1C02
1C03
1C04
1C05
1C06
1C07
1C08
1C09
166
GSTERCLER
p = (int *) 0x1AA0;
q = p;
Yukardaki atama ile q gstericisine p gstericisinin deeri atanmtr. Yani bu atama
deyiminden sonra q gstericisinin de iinde (int *) 0x1AA0 adresi bulunacaktr.
...
0001
1010
1010
0000
...
...
...
0001
1010
1010
0000
int k;
gibi bir tanmlama yaptmzda k deikeni int trdendir, iindeki deer int olarak
yorumlanacaktr.
20
gibi, tek bir sabitten oluan bir ifade de int trdendir, nk 20 int trden bir sabittir. 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. (sa taraf deeridir)
int *ptr;
gibi bir tanmlama yapldnda ptr nesnesinin tr nedir? ptr iinde int trden bir adres
sakladna gre ptr nesnesinin tr int trden bir adrestir.
int a[100];
Yukardaki tanmlamadan sonra
a
gibi bir ifade kullanlrsa bu ifadenin tr de "int trden bir adres" dir. Ancak ptr ifadesi nesne
gsteren bir ifadeyken, yani bir sol taraf deeriyken, a ifadesi nesne gsteren bir ifade
deeridir. Sol taraf deeri olarak kullanlamaz.
Yine bir adres sabitinden oluan
(int *) 0x1A00
167
19
ifadesinin tr de int trden bir adrestir. Ancak bu ifade de sol taraf deeri deildir.
Grld gibi gstericiler, belirli bir adres trnden, nesnelerdir. (sol taraf deerleridir.)
Gsterici Operatrleri
C dilinde toplam 4 tane gsterici operatr vardr. Bu operatrler gstericiler ve adres
bilgileriyle kullanlabilirler.
Gsterici operatrleri unlardr :
*
&
[]
->
ierik operatr
adres operatr
keli parantez operatr
ok operatr
Adres sabitleri.
Gstericiler.
Dizi isimleri.
& operatr ile oluturulmu ifadeler.
168
GSTERCLER
int x;
++&x
/* error */
gibi bir ilem error ile neticelenir. ++ operatrnn operand nesne olmaldr. Yukardaki
ifadede ++ operatrne operand olan &x ifadesi bir nesne gstermemektedir. Yalnzca bir
adres deeridir.
169
19
putchar(*s);
}
return 0;
GSTERCLER
{
char ch = '0';
(&ch)[0] = 'b'
putchar(ch);
return 0;
}
&ch ifadesi parantez iine alnmasayd [] operatrnn ncelii sz konusu olacandan nce
ch[0] yaplrd. Buradan da bir nesne elde edilemeyeceinden (& operatrnn operandnn
nesne olmas gerektiinden) hata oluurdu.
*++p durumu
p gstericisinin deeri 1 artrlr. Artrlm adresteki nesneye ulalm olur.
x = *++p;
171
19
*p++ durumu
++ operatr ve * operatrnn ikisi de 2. ncelik seviyesindedir ve bu ncelik seviyesine
ilikin ncelik yn sadan soladr. nce ++ operatr ele alnr ve bu operatr ifadenin geri
kalan ksmna p gstericisinin artmam deerini gnderir. Bu adresteki nesneye ulalr ve
daha sonra p gstericisinin deeri 1 artrlr.
x = *p++;
deyimi ile x deikenine *p nesnesinin deeri atanr daha sonra p gstericisinin deeri 1
artrlr.
&x++
/* error */
x nesnesinin artmam deeri ifadenin geri kalanna gnderilir. (Adres operatrne operand
olur.) Bu da bir nesne olmad iin error oluur. (Adres operatrnn operand nesne olmak
zorundadr.)
&++x /* error */
x nesnesinin artm deeri ifadenin geri kalanna gnderilir. (Adres operatrne operand olur.)
Bu da bir nesne olmad iin error oluur. (Adres operatrnn operand nesne olmak
zorundadr.)
++&x /* error */
x nesnesinin adresi ++ operatrne operand olur. ++ operatrnn operand nesne olmak
zorunda olduu iin derleme zamannda error oluacaktr.
& operatr ile ++ ya da -- operatrlerinin her trl kombinasyonu derleme zamannda hata
olumasna neden olur.
++p[i] Durumu
ndex operatr 1. ncelik seviyesinde, ++ operatr ise 2. ncelik seviyesindedir. Bu
durumda nce derleyici tarafndan indeks operatr ele alnr. p[i] ifadesi bir nesne gsterir.
Dolaysyla ++ operatrne operand olmasnda bir saknca yoktur. Sz konusu ifade
p[i] = p[i] + 1;
anlamna gelmektedir. Yani p[i] nesnesinin deeri 1 artrlacaktr.
p[i]++ Durumu
x = p[i]++;
nce p[i] nesensinin artmam deeri retilir, ifadenin geri kalanna p[i] nesnesinin artmam
deeri kullanlr. Yani yukardaki rnekte x deikenine p[i] nesnesinin artrlmam deeri
atanr, daha sonra p[i] nesnesi 1 artrlr.
p[++i] Durumu
x = p[++i];
nce i 1 artrlr. Daha sonra artrlm adresteki bilgi x deikenine atanr.
p[i++] Durumu
172
GSTERCLER
x = p[i++];
Burada p[i] nesnesinin deeri x deikenine atanr. Daha sonra i deikeni 1 artrlr.
p++[i] durumu
x = p++[i];
Pek tercih edilen bir ifade deildir.Burada nce p[i] x deikenine atanr. Sonra p gstericisinin
deeri 1 artrlr.
173
19
2. Elde edilen deer aran fonksiyonun gndermi olduu adrese yerletirilir. Tabi bunun iin
arlan fonksiyonun parametre deikeninin bir gsterici olmas gerekir. Bir rnekle
gsterelim:
Kendisine gnderilen bir saynn faktoriyelini hesaplayana ve bu deeri parametre olarak
gnderilen adrese kopyalayan bir fonksiyon yazalm.
void factorial(int n, long *p);
#include <stdio.h>
int main()
{
long a;
factorial(7, &a);
printf ("%d! = %ld", 7,
}
a);
return 0;
174
GSTERCLER
parametre deikenleri x ve y'nin deerleri. stediimiz amac gerekletirecek fonksiyon
dardan adres alaca iin gsterici parametre deikenlerine sahip olmal:
#include <stdio.h>
double getavg(int *p, int size);
int main()
{
int s[10] = {1, 23, 45, -4, 67, 12, 22, 90, -3, 44};
double average;
#include <stdio.h>
int getmax(int *p, int size);
int main()
{
int s[10] = {1, 23, 45, -4, 67, 12, 22, 90, -3, 44};
175
19
return max;
Bubble sort yntemiyle int trden bir diziyi kkten bye sraya dizen fonksiyon rnei:
#include <stdio.h>
#define SIZE 10
void bsort(int *p, int size);
void bsort(int *p, int size)
{
int i, k, temp;
for (i = 0; i < size - 1; ++i)
for (k = 0; k < size - 1 - i; ++k)
if (p[k] > p[k+1]) {
temp = p[k];
p[k] = p[k+1];
p[k+1] = temp;
}
}
int main()
{
int a[SIZE] = {3, 4, 5, 8, 78,12, -2, 11, 41, -34};
int i;
bsort(a, SIZE);
for (i = 0; i < SIZE; ++i)
printf("a[%d] = %d\n",i
return 0;
a[i]);
176
GSTERCLER
int *sample(void)
{
...
}
Yukardaki fonksiyon tanmlama ifadesinden * atomu kaldrlrsa fonskiyon int trden bir deer
dndrr.
Bir adres trne geri dnen bir fonksiyonun arlma ifadesi, ayn trden bir gstericiye
atanmaldr.
int *ptr;
ptr = sample();
gibi.
Benzer ekilde:
char *str;
char *func(void) {
...
}
str = func();
...
Adrese geri dnen fonksiyonlara C programlarnda ok rastlanr. Standart C fonksiyonlarndan
bir ou, adres trnden bir deer dndrr.
Bir dizinin en byk elemann bulup bu elemann deerine geri dnen getmax fonksiyonunu
daha nce tasarlamtk. imdi ayn fonksiyonu en byk elemann adresine geri dnecek
ekilde tasarlayalm:
#include <stdio.h>
int *getmax(int *p, int size);
int main()
{
int s[10] = {1, 23, 45, -4, 67, 12, 22, 90, -3, 44};
printf("%d\n", *getmax(s, 10));
return 0;
}
int *getmax(int *p, int size)
{
int *pmax, i;
pmax = p;
for (i = 1; i < size; ++i)
if (*pmax > p[i])
pmax = p + i;
return pmax;
177
19
/* uyar */
178
GSTERCLER
eklindedir. Peki bir gstericiye adres bilgisi olmayan bir deer atarsak ne olur? Yine otomatik
tr dnm sz konusudur. Atama operatrnn sa tarafndaki ifadenin tr, atama
operatrnn sol tarafnda bulunan nesne gsteren ifadenin trne evrilerek, atama
yaplacaktr. Dolaysyla, atanan deer gstericinin trnden bir adrese evrilecek ve
gstericiye atanacaktr. rnein:
int main()
{
int k, *ptr;
k = 1356;
ptr = k;
...
return 0;
/* uyar */
}
Yukardaki rnekte ptr = k; atama deyiminden sonra bellekte ptr gstericisi iin ayrlan yere
1356 yazlacaktr. Yani *ptr ifadesi ile int trden bir nesneye ulalacaktr ki bu nesne de 1356
ve 1357 adreslerinde bulunan nesnedir.
Bu durumun bilinli olarak yaplmas durumunda yine tr dntrme operatr kullanlarak
derleyici ikna edilmeli ve uyar mesaj kesilmelidir:
int main()
{
int k, *ptr;
k = 1356;
ptr = (int * ) k;
...
return 0;
/* uyar
yok */
179
19
#include <stdio.h>
void myputs(char *str)
{
while (*str != '\0') {
putchar(*str);
++str;
}
putchar('\n');
}
int main()
{
char s[] = "Deneme";
myputs(s);
return 0;
strlen Fonksiyonu
Bu fonksiyon bir yaznn karakter uzunluunu (ka karakterden olutuu bilgisini) elde etmek
iin kullanlr.
Fonksiyonun prototipi:
unsigned int strlen(char *str);
eklindedir. Fonksiyonun parametre deikeni uzunluu hesaplanacak yaznn balang
adresidir. Fonksiyon null karakter grene kadar karakterlerin saysn hesaplar.
#include <stdio.h>
#include <string.h>
int main()
{
char s[100];
180
GSTERCLER
int main()
{
char s[100];
printf("bir yaz giriniz
gets(s);
printf("yaznn uzunluu
printf("yaznn uzunluu
printf("yaznn uzunluu
: ");
: %d\n", strlen1(s));
: %d\n", strlen1(s));
: %d\n", strlen1(s));
return 0;
}
unsigned int strlen1(char *str)
{
unsigned int length = 0;
strlen2 fonksiyonunda len deikeni hem dng deikeni hem de saya olarak kullanlmtr.
null karakter '\0' saysal deer olarak 0 deerine eit olduu iin yukardaki dnglerin koul
ifadelerini aadaki ekilde yazabilirdik:
while (*str)
for (i = 0; str[i]; ++i)
Yukardaki koul ifadelerinde de *str ya da str[i] 0 deerine eit olduunda kodun ak dng
dndaki ilk deyimle devam ederdi. Ancak okunabilirlik asndan null karakterle
karlatrmann aka yaplmas daha uygundur.
strchr fonksiyonu
Fonksiyonun ismi olan strchr "string character" szcklerinin ksaltlarak birletirilmesinden
elde edilmitir. strchr fonksiyonu bir karakter dizisi iinde belirli bir karakteri aramak iin
kullanlan standart bir C fonksiyonudur. Prototipi string.h dosyas iinde bulunmaktadr.
strchr fonksiyonunun prototipi aadaki gibidir:
char *strchr(char *str, int ch);
181
19
182
GSTERCLER
strcpy fonksiyonu
fonksiyonun ismi olan strcpy, string ve copy szcklerinin ksaltlarak birletirilmesinden elde
edilmitir.Fonksiyon ikinci parametresinde tutulan adresten balayarak, NULL karakter grene
kadar, (NULL karakter dahil olmak zere) tm karakterleri srasyla birinci parametresinde
tutulan adresten balayarak srayla yazar. Fonksiyonun prototipi string.h dosyas iindedir.
Fonksiyonun prototipi aadaki gibidir:
char *strcpy(char *dest, char *source);
Fonksiyonun geri dn deeri kopyalamann yaplmaya baland adrestir. (Yani dest adresi)
#include <stdio.h>
#include <string.h>
int main()
{
char dest[100] = "C reniyoruz!";
char source[100];
printf("kopyalanacak yazy giriniz : ");
gets(source);
printf("kopyalama yaplmadan nce kopyalamann yapaca yerde bulunan yaz :
\n");
puts(dest);
strcpy(dest, source);
printf("kopyalamadan sonra kopyalamann yapld yerde bulunan yaz : \n");
puts(dest);
return 0;
}
strcpy fonksiyonunu kendimiz yazmak isteseydik aadaki ekilde yazabilirdik :
char *_strcpy(char *dest, char *source)
{
int i;
fonksiyon iinde kullanlan for dngsnde nce atama yaplm, daha sonra atama ifadesinin
deeri (k, bu da atama operatrnn sa tarafnda bulunan deerdir) NULL karakter ile
karlatrlmtr. Bylece ilgili adrese NULL karakter de kopyalandktan sonra dngden
klmtr.
fonksiyonu aadaki gibi de yazabilirdik :
...
for (i = 0; source[i] != '\0'; ++i)
dest[i] = source[i];
dest[i] = '\0';
...
for dngsnde indeks operatr kullanld iin, birinci parametre deikenine kopyalanan
dest adresi deitirilmemi ve fonksiyonun sonunda bu dest adresi ile geri dnlmtr.
Fonksiyonun tasarmnda whilde dngs kullansaydk, ve dest iindeki adresi deitirseydik,
fonksiyonun dest gstericisinin ilk deeriyle geri dnebilmesini salayabilmek iin, dest
gstericisindeki deeri deitirmeden nce, bu deeri baka bir gsterici iinde saklamak
gerekecekti :
char *_strcpy(char *dest, char *source)
183
19
{
}
Yazlan fonksiyonlarn doru alp almadklarn ayn main fonksiyonu ile test edebiliriz.
strcat fonksiyonu
fonksiyonun ismi string ve concatanate szcklerinin ksaltlarak birletirilmesiyle elde
edilmitir.
strcat fonksiyonu bir karakter dizisinin sonuna baka bir karakter dizisinin kopyalanmas
amacyla kullanlmaktadr. Fonksiyonun prototipi string.h dosyas iindedir. Fonksiyonun
prototipi aadaki gibidir:
char *strcat(char *s1, char *s2);
strcat fonksiyonu eklemenin yaplaca ve balang adresi s1 birinci parametre deikeninde
tutulan yaznn sonundaki NULL karakteri ezerek, balang adresi ikinci parametre
deikeninde tutulan yazy birinci yaznn sonuna (NULL karakter de dahil olmak zere)
eklemektedir. Yani ilem sonunda s1 dizisi s2 dizisi kadar bymektedir.
Fonksiyonun geri dn deeri, sonuna eklemenin yapld yaznn balang adresidir. (Yani s1
adresi)
#include <stdio.h>
#include <string.h>
int main()
{
char s1[100], s2[100];
printf("sonuna ekleme yaplacak yazy giriniz : ");
gets(s1);
printf("girdiiniz yaznn uzunluu = %d\n", strlen(s1));
printf("eklemek istediiniz yazy giriniz : ");
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;
/* strcpy(s1, s2); */
184
GSTERCLER
Yazlan fonksiyonun doru alp almadn ayn main fonksiyonu ile test edebiliriz.
strset fonksiyonu
Standart olmayan bu fonksiyon derleyicilerin ounda bulunur. Fonksiyonun ismi string ve set
szcklerinin ksaltlarak birletirilmesinden elde edilmitir. Bir karakter dizisinin belirli bir
karakterle doldurulmas amacyla kullanlmaktadr. Prototipi string.h dosyas iinde
bulunmaktadr. Fonksiyonun prototipi aadaki gibidir :
char *strset(char *str, int ch);
Fonksiyon birinci parametre deikeninde balang adresi olan yazy NULL karakter grene
kadar ikinci parametre deikeninde tutulan karakterle doldurur. (yaznn sonundaki NULL
karaktere dokunmaz) .
Fonksiyonun geri dn deeri yine doldurulan yaznn balang adresidir.
#include <stdio.h>
#include <conio.h>
int main()
{
char s[100];
int ch;
printf("bir yaz giriniz :");
gets(s);
printf("yazy hangi karakterle doldurmak istiyorsunuz : ");
ch = getchar();
printf("\nyaznn %c karakteriyle doldurulduktan sonraki hali : %s\n", ch,
strset(s, ch));
}
return 0;
strcmp fonksiyonu
185
19
Standart bir C fonksiyonudur. Fonksiyonun ismi string ve compare szcklerinin ksaltlarak
birletirilmesinden elde edilmitir. Fonksiyon iki karakter dizisini karlatrmakta kullanlr.
Karlatrma, iki karakter dizisi iindeki yaznn kullanlan karakter seti tablosu gznnde
bulundurularak, ncelilk ya da eitlik durumunun sorgulanmasdr. rnein :
Adana yazs Ankara yazsndan daha kktr. nk eitlii bozan 'n' karakteri ASCII
tablosunda 'd' karakterinden sonra gelmektedir.
ankara yazs ANKARA yazsndan daha byktr. nk kk harfler ASCII tablosunda
byk harflerden sonra gelmektedir.
kalem yazs kale yazsndan daha byktr.
strcmp fonksiyonunun string.h ierisindeki prototipi aadaki gibidir :
int strcmp(char *s1, char *s2);
fonksiyon 1. parametre deikeninde balang adresi tutulan yaz ile, ikinci parametre
deikeninde balang adresi tutulan yazlar karlatrr.
fonksiyonun geri dn deeri
1. yaz 2.yazdan daha bykse pozitif bir deere
1. yaz 2. yazdan daha kkse negatif bir deere
1.yaz ve 2. yaz birbirine eit ise 0 deerine geri dner.
#include <stdio.h>
#include <string.h>
int main()
{
char s[20];
char password[ ] = "Mavi ay";
186
GSTERCLER
Standart olmayan bu fonksiyon derleyiclerin ounda bulunur. Fonksiyonun ismi ingilizce string
ve reverse scklerinin ksaltlarak birletirilmesinden elde edilmitir. Karakter dizilerini ters
evirmek amacyla kullanlr. string.h ierisinde yer alan prototipi aadaki gibidir :
char *strrev(char *str);
fonksiyon parametre deikeninde balang adresi tutulan yazy tersyz eder. Fonksiyonun
geri dn deeri tersyz edilen yaznn balang adresidir.
#include <stdio.h>
#include <string.h>
main()
{
char s[100];
strncpy fonksiyonu
Standart bir C fonksiyonudur. Fonksiyonun ismi ingilizce, string number copy szcklerinin
ksaltlarak birletirilmesinden elde edilmitir. Fonksiyon bir yaznn (karakter dizisinin) ilk n
karakterini baka bir yazya(karakter dizisine) kopyalamakta kullanlr. Fonksiyonun string.h
ierisindeki prototipi aadaki gibidir :
char *strncpy(char *dest, char *source, int n);
fonksiyon 1. parametre deikeninde balang adresi tutulan yazya, ikinci parametre
deikeninde adresi tutulan yazdan, nc parametresinde tutulan sayda karakteri kopyalar.
Fonksiyonun geri dn deeri kopyalamann yaplaca adrestir. (Yani dest adresi)
nc parametre olan n says eer kopyalanacak yaznn uzunluundan daha kk ya da
eit ise fonksiyon kopyalama sonunda NULL karakteri birinci dizinin sonuna eklemez.
n <= strlen(source) ise NULL karakter eklenmiyor.
nc parametre olan n says eer kopyalanacak yaznn uzunluundan daha byk
fonksiyon kopyalama sonunda NULL karakteri birinci dizinin sonuna ekler.
187
ise
19
strncat fonksiyonu
Standart bir C fonksiyonudur. Fonksiyonun ismi ingilizce string number concatanate
szcklerinin ksaltlarak birletirilmesiyle elde edilmitir. Bir karakterden dizisinin sonuna
baka bir karakter dizisinden belirli bir sayda karakteri kopyalamak amacyla kullanlr. string.h
iinde bulunan prototipi aadaki gibidir :
char *strncat(char *s1, char *s2, int n);
fonksiyon 1. parametre deikeni iinde balang adresi verilen yaznn sonuna (NULL
karakteri ezerek), 2. parametresinde balang adresi tutulan karakter dizisinden, 3.
parametresinde tutulan tamsay adedi kadar karakteri kopyalar.
fonksiyonun geri dn deeri sonuna ekleme yaplacak yaznn balang adresidir. (yani s1
adresi)
fonksiyonun almasn aklayacak bir rnek aada verilmitir :
#include <stdio.h>
#include <string.h>
int main()
188
GSTERCLER
{
karakter
kopyalamak
strncmp fonksiyonu
Standart bir C fonksiyonudur. Fonksiyonun ismi ingilizce string number compare szcklerinin
ksaltlarak birletirilmesiyle elde edilmitir. strcmp fonksiyonuna benzer, ancak bu fonksiyon
iki yaznn tmn deil de, belirli bir sayda karakterlerini karlatrma amacyla kullanlr.
fonksiyon 1. parametre deikeninde balang adresi tutulan yaz ile, ikinci parametre
deikeninde balang adresi tutulan yazlarn, nc parametresinde tutulan saydaki
karakterlerini karlatrr.
fonksiyonun geri dn deeri
1. yaznn n karakteri 2.yaznn n karakterinden daha bykse pozitif bir deere
1. yaznn n karakteri 2.yaznn n karakterinden daha kkse negatif bir deere
1.yaz ve 2. yaznn n kakateri birbirine eit ise 0 deerine geri dner.
/* byk harf kk harf duyarl ile (case sensitive) bir yaz iinde baka bir yazy arayan
mystrstr fonksiyonu. Fonksiyon aranan yazy aramann yaplaca yaz iinde bulursa bulduu
yaznn balang adresine, bulamazsa NULL adresine geri dnmektedir.
*/
#include <stdio.h>
#include <conio.h>
#include <string.h>
char *mystrstr(char *s1, char *s2);
int main()
{
char s1[100];
char s2[100];
char *ptr;
clrscr();
printf("aramann yaplaca yazy girin : ");
gets(s1);
printf("aranacak yazy girin :");
gets(s2);
ptr = mystrstr(s1, s2);
if (ptr)
puts(ptr);
else
puts("aradnz yaz bulunamad\n");
getch();
return 0;
189
19
}
char *mystrstr(char *s1, char *s2)
{
int i, j;
int lens1, lens2;
lens1 = strlen(s1);
lens2 = strlen(s2);
for (i = 0; lens1 - i >= lens2; ++i, ++s1) {
for (j = 0; s1[j] == s2[j]; ++j)
if (s2[j + 1] == '\0')
return s1;
}
return NULL;
}
0;
}
strupr ve strlwr fonksiyonlarn kendimiz de aadaki ekilde
#include <stdio.h>,
#include <ctype.h>
char *_strupr(char *str)
{
char *temp = str;
190
*/
GSTERCLER
temp = str;
while (*str != '\0') {
p = strchr(trkupper, *str);
if (p) {
index = p - trkupper;
*str = trklower[index];
}
else
*str = tolower(*str);
++str;
}
return temp;
191
*/
19
i.
p += strlen(p);
ii.
p = strchr(p, '\0');
iii.
Yukardakiler iinde en hzl alabilecek kod ncsdr. 2. biim tercih edilebilir ama 1.
yntem pek tercih edilmez.
Aadaki dngden ktktan sonra p gstericisi NULL karakterden bir sonraki adresi
gstermektedir :
while (*p++ != '\0')
;
GSTERC HATALARI
Gstericileri kullanarak RAM zerinde herhangi bir blgeye eriebiliriz. 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 kabilecektir. Bu bozukluk tm
sistemi olumsuz ynde etkileyebilir.
Kim tarafndan kullanldn bilmediimiz bellek blgelerine gvenli olmayan blgeler denir.
Gvenli olmayan blgelere veri aktarlmasna da "gsterici hatalar" denir.
Gsterici hatalar yapldnda sistem kilitlenebilir, programlar yanl alabilirler. Gsterici
hatalar sonucundaki olumsuzluklar hemen ortaya kmayabilir.
Gsterici hatalar gvenli olmayan blgelere eriildiinde deil oralara veri aktarldnda
oluur.
Gsterici hatalar derleme srasnda derleyici tarafndan tespit edilemezler. Programn alma
zaman srasnda olumsuzluklara yol aarlar. tanmlama yntemiyle tahsis 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
1) ilk deer 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 rasgele deerlerle balatlrlar. (garbage value)
Yerel bir gsterici tanmlandktan sonra, herhangi bir ekilde bu gstericiye bir deer atamas
yaplmaz ise gstericinin iinde rasgele bir deer bulunacandan, bu gsterici *operatr ile
ya da [ ] operatr ile kullanldnda, bellekte rasgele bir yerde bulunan bir nesneye
ulalacaktr. Dolaysyla, elde edilen nesneye bir atama yapld zaman, bellekte, bilinmeyen
rasgele bir yere yazlm olunur. Bu durum tipik bir gsterici hatasdr. rnekler :
main()
{
int *p;
*p = 25;
}
Yukardaki rnekte rasgele bir yere (gvenli olmayan bir yere) veri aktarlmaktadr. Verinin
aktarld yerde iletim sisteminin, derleyicinin ya da bellekte kalan baka bir programn
192
GSTERCLER
(memory resident) kodu bulunabilir. Verinin aktarld yerde programn kendi kodu da
bulunabilir.
lk deer verilmemi global gstericilerin iinde (ya da statik yerel gstericilerin ierisinde) sfr
deeri bulunmaktadr. Sfr says (NULL adresi) gstericilerde test amacyla kullanlmaktadr.
Bu adrese bir veri aktarlmas durumunda , derleyicilerin ounda istee bal olarakbu hata
alma zaman (runtime) srasnda kontrol edilmektedir. rnek :
char *ptr;
main()
{
*p = 'm';
}
Yukardaki kodun altrlmasnda "NULL pointer assignment" eklinde bir alma zaman
hatasyla karlalabilir. Bu kontrol derleyicinin alabilen program ierisine yerletirdii
"kontrol kodu" sayesinde yaplmaktadr.
lk deer verilmemi gstericilerin neden olduu hatalar fonksiyon armalaryla da ortaya
kabilir :
main()
{
char *ptr;
}
gets(ptr);
/* ????? */
Yukardaki kod parasnda gets fonksiyonu ile klavyeden alnan karakterler, bellekte rasgele bir
yere yazlacaktr. gets fonksiyonu klavyeden alnan karakterleri kendisine arguman olarak
gnderilen adresten balayarak yerletirdiine gre, daha nceki rnekte verilen hata
klavyeden girilen btn karakterler iin sz konusudur.
2) Gvenli olmayan ilk deerlerin neden olduu gsterici hatalar
Bir gstericiye ilk deer verilmesi , o gstericinin gvenli bir blgeyi gsterdii anlamna
gelmeyecektir. 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 ierisinde belli amalar iin kullanlan gvenli blgeler varsa da 1FC5 byle
bir blgeyi gstermemektedir.
3) dizi tamalarndan doan gsterici hatalar
Bilindii gibi bir dizi tanmlamas grdnde derleyici, derleme srasnda dizi iin bellekte
toplam dizi uzunluu kadar yer ayrr. C'nin seviyesi ve felsefesi gerei dizi tamalar derleyici
tarafndan tespit edilmemektedir.
main()
{
int a[10], k;
193
19
Yukardaki rnekte dng k deikeninin 10 deeri iin de srecektir. Oysa a[10] eleman iin
bir tahsisat yaplmamtr. Dizinin son eleman a[9] elemandr. Derleyici a dizisi iin a[0]'dan
balayarak a[9] eleman iin bellekte toplam 10 elemanlk yani 20 byte'lk bir yer tahsis
edecektir. Oysa tahsis edilmemi olan a[10] blgesinin kim tarafndan ve ne amala kullanld
hakknda herhangi bir bilgi bulunmamaktadr.
(Bu konuda standartlar tarafndan bir zorunluluk bulunmamakla birlikte derleyicilerin ou,
ardl olarak tanmlanan elemanlar bellekte ardl olarak (contigious) olarak yerletirirler.
Ama bu garanti altna alnm bir zellik deildir. Yani bunun garanti altna alnd dnlerek
kod yazlmas problemlere yol aacaktr. Yukardaki rnekte a[10] blgesi derleyicilerin
ounda a dizisinden hemen sonra tanmlanan ve dng deikeni olarak kullanlan k
deikenine ayrlacaktr. Dolaysyla a[10] elemanna 0 deerini vermekle aslnda k deikenine
0 deeri verilecek ve bu da dngnn sonsuz bir dngye dnmesine yol aabilecektir.)
Bilindii gibi indeks operatr de bir gsterici operatrdr, bu operatr kullanarak dizi iin
tahsis edilen alann dna atama yaplabilir. C dili bu konuda bir kontrol mekanizmas
getirmemektedir. Ayruca a dizisi iin a[-1], a[-2].. gibi ifadelerin de sentaks asndan
geerlidir ve buraya yaplacak atamalar da gsterici hatalarna yol aacaktr.
Bazan dizi tamalarna gizli bir biimde fonksiyonlar da neden olabilirler. rnein :
char str[12];
...
printf("ad soyad : ");
gets(str);
yukardaki kod parasnda str dizisi iin toplam 12 karakterlik (12 byte) yer tahsis edilmitir.
gets fonksiyonu klavyeden alnan karakterleri kendisine gnderilen adresten balayarak bellee
yerletirdikten sonra, NULL karakteri de eklemektedir. O halde yukardaki rnekte programn
almas srasnda 11 karakterden fazla giri yaplmas gsterici hatasna neden olacaktr.
Sonlandrc karakter olan NULL karakter de ('\0') bellekte bir yer kaplayaca iin tahsis
edilmi bir blge iinde bulunmas gerekir. rnein klavyeden girilen ad ve soyad :
Necati Ergin
olsun. gets fonksiyonu bu karakterleri aadaki gibi yerletirecektir :
s[0]
s[1]
s[2]
s[3]
s[4]
s[5]
s[6]
s[7]
s[8]
s[9]
s[10]
s[11]
...
'N'
'e'
'c'
'a'
't'
'i'
''
'E'
'r'
'g'
'i'
'n'
'\0' sonlandrc karakter gvenli olmayan bir yere
yazlyor.
...
Grld gibi sonlandrc karakter, dizi iin tahsis edilen blgenin dna yerletirilmitir. Bu
rnekte girilen isim daha uzun olsayd, tahsis edilmemi blgeye daha fazla karakter
yazlacakt. Bu tr hatalarla karlamamak iin dizi yeteri kadar uzun olmal ya da standart bir
194
GSTERCLER
C fonksiyonu olan gets fonksiyonu yerine, dizi uzunluundan daha fazla sayda eleman
yerletirilmesine izin vermeyecek zel bir giri fonksiyonu yazlmal ve kullanlmaldr.
stringlerle ilgili ilemler yapan standart C fonksiyonlarndan strcpy, strcat, strncpy, strncat
fonksiyonlarnn yanl kullanlmas da benzer hatalar oluturabilecektir. rnein :
char s[10] = "Eskiehir";
...
strcpy(s, "Kahramanmara");
strcat(s, "li");
strncpy(s, "Kahramanmara", 15)
strncat(s, "liyim", 5);
/* gsterici hatas */
/* gsterici hatas */
/* gsterici hatas */
/* gsterici hatas */
yukardaki fonksiyonlardan hepsi tahsis edilmeyen bir blgeye yazma yaptklar iin gsterici
hatasna neden olacaktr.
void Gstericiler
void gstericiler herhangi bir trden olmayan gstericilerdir. Bildirimlerinde void anahtar
szc kullanlr.
void *ptr;
void *str;
void gstericilerin tr bilgisi yoktur. void gstericilerde adreslerin yalnzca saysal bileenleri
saklanr. Bu yzden void gstericilerle dier trden gstericler (adresler) arasnda yaplan
atamalarda uyar sz konusu deildir. void gstericileri kullanrken tr dntrme operatrn
kullanmaya gerek yoktur.
char *str;
void *p;
....
str = p;
p = str;
funk2(int * p)
{
...
}
195
19
int main()
{
void *ptr;
...
funk2(ptr);
}
void gstericiler belirli bir tre ait olmadklar iin, tr bilgisine sahip olan gstericiler zerinde
uygulanan baz ilemler void trden gstericilere uygulanamazlar:
1. void trden gstericilerin * ya da [ ] operatrleriyle kullanlmalar derleme zamannda error
oluturacaktr. nk bu operatrler nesneye erimek iin tr bilgisine ihtiya duyarlar.
long l[50];
void *vptr;
vptr = l;
...
*p = 10L;
...
p[2] = 25L;
/* normal bir ilem. void trden gstericiye long trden bir adres atanyor. */
/* hata! void gsterici * operatryle kullanlamaz. */
/* hata! void gsterici [ ] operatryle kullanlamaz. */
2. void trden bir gstericiden bir tamsaynn toplanmas, ya da void trden bir gstericiden bir
tamsaynn kartlmas derleme zamannda hata oluturur. nk pointer aritmetiine gre bir
gstericiyi n kadar artrdmzda, gsterici iindeki adresin saysal bileeni n * gstericinin
trn uzunluu kadar artar. void gstericilerin trleri olmad iin bu durumda saysal
bileenin ne kadar artaca da bilinemez.
void trden gstericiler ++ ve -- operatrlerine operand olamazlar.
++ptr;
ifadesi
ptr = ptr +1;
ifadesine edeerdir.
int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
void *ptr = &k;
void *p;
p = ptr + 2; /* error! void trden bir gstericiye bir tamsay toplanyor! */
++ptr;
/*error ! */
--ptr;
/* error! */
ptr += 2;
/*error */
ptr -= 3;
/* error */
3. Benzer ekilde, void trden iki adres birbirinden kartlamaz. (Dier trden adresler iin,
ayn trden iki adresin birbirinden kartlmasnn tamamen legal oldugunu ve ifadenin
deerinin pointer aritmetiine gre bir tamsay oldugunu hatrlayalm!)
void *p1, *p2;
int k;
...
k = p1 - p2;
void gstericiler adreslerin saysal bileenlerini geici olarak saklamak amacyla kullanlrlar.
Dier tr gstericiler arasndaki atama ilemlerinde uyar ya da hata oluturmadklarndan
196
GSTERCLER
dolay, trden bamsz adres ilemlerinin yapld fonksiyonlarda parametre deikeni
biiminde de bulunabilirler. rnein:
void sample(void *p)
{
...
}
sample isimli fonksiyonun parametre deikeni void trden bir gsterici olduundan bu
fonksiyona arguman olarak herhangi trden bir adres bilgisi gnderilebilir. Yani sample
fonksiyonu herhangi trden bir adres ile arlabilir. Bu durumda derleme zamannda bir hata
olumad gibi bir uyar mesaj da alnmaz.
C dilinde fonksiyonlar void trden adreslere de geri dnebilirler. Void trden adresler derleme
zamannda bir hata olumakszn, ve bir uyar mesaj alnmadan herhangi trden bir gstericiye
atanabildii iin, bu fonksiyonlarn geri dn deerleri herhangi trden bir gstericiye
atanabilir:
main()
{
int *p;
char * str;
p = sample();
...
str = sample();
}
void *sample();
{
...
}
void gstericilere ilikin uygulamalar
void gstericilerin kullanmn en iyi aklayan rnek memcpy fonksiyonudur. memcpy
fonksiyonu 2. parametresiyle belirtilen adresten balayarak n sayda byte birinci
parametresiyle belirtilen adresten balayarak kopyalar. Fonksiyonun NULL karakterle ya da
yazlarla bir ilikisi yoktur, koulsuz bir kopyalama yapar. Yani bir blok kopyalamas sz
konusudur.
Uygulamada en fazla, ayn trden herhangi iki dizinin kopyalanmas amacyla kullanlr.
Fonksiyonun prototipi string.h balk dosyas iindedir.
rnek :
#include <stdio.h>
#include <string.h>
#define
SIZE
10
void main()
{
int a[SIZE] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int b[SIZE];
int i;
memcpy(b, a, 2 * SIZE);
for (i = 0; i < SIZE; ++i)
197
19
printf(%d\n, b[i]);
GSTERCLER
0;
#include <stdio.h>
#include <string.h>
#define NEGATIVE
#define POSITIVE
(-1)
1
19
}
else
sign = POSITIVE;
i = 0;
do {
digit = val % 10;
str[i++] = digit + '0';
val /= 10;
if (i % 4 == 3 && val)
str[i++] = ',';
} while (val);
str[i] = '\0';
strrev(str);
return str;
}
int main()
{
char str[80];
long val;
printf("bir say giriniz : ");
scanf("%ld", &val);
puts(longtoa(val, str));
return 0;
}
Uygulama 2: byk harf kk harf duyarl ile (case sensitive) bir yaz iinde baka bir yazy arayan
mystrstr fonksiyonu. Fonksiyon aranan yazy aramann yaplaca yaz iinde bulursa bulduu yaznn
balang adresine, bulamazsa NULL adresine geri dnmektedir.
#include <stdio.h>
#include <conio.h>
#include <string.h>
char *mystrstr(char *s1, char *s2);
int main()
{
char s1[100];
char s2[100];
char *ptr;
clrscr();
printf("aramann yaplaca yazy girin : ");
gets(s1);
printf("aranacak yazy girin :");
gets(s2);
ptr = mystrstr(s1, s2);
if (ptr)
puts(ptr);
else
puts("aradnz yaz bulunamad\n");
getch();
GSTERCLER
int i, j;
int lens1, lens2;
lens1 = strlen(s1);
lens2 = strlen(s2);
for (i = 0; lens1 - i >= lens2; ++i, ++s1) {
for (j = 0; s1[j] == s2[j]; ++j)
if (s2[j + 1] == '\0')
return s1;
}
return NULL;
}
Uygulama 3: klavyeden girilen bir yaz ierisindeki trke karakterlerin
saysn bulan fonksiyon.
#include
#include
#include
#include
<stdio.h>
<conio.h>
<string.h>
<ctype.h>
gets(s);
printf("\ntrke karakter says = %d", gettrknum(s));
Uygulama 4: Byk harf kk harf duyarl olmadan iki stringi karlatran fonksiyon.
#include
#include
#include
#include
<stdio.h>
<conio.h>
<string.h>
<ctype.h>
201
19
clrscr();
printf("1. yazy girin : ");
gets(s1);
printf("2. yazy girin :");
gets(s2);
result = mystricmp(s1, s2);
if (result == 0)
puts("s1 = s2");
else if (result > 0)
puts("s1 > s2");
else
puts("s1 < s2");
getch();
}
int mystricmp(char *s1, char *s2)
{
while (toupper(*s1) == toupper(*s2)) {
if (*s1 == '\0')
return 0;
++s1;
++s2;
}
return toupper(*s1) - toupper(*s2);
}
Uygulama 5 : Kendisine balang adresi gnderilen bir yaznn iindeki boluklar atan rem_space
fonksiyonu. Fonksiyon kendisine gnderilen adrese geri dnecektir.
#include <stdio.h>
char *rem_space(char *ptr)
{
int k;
int indis = 0;
for (k = 0; ptr[k] != '\0'; ++k)
if (ptr[k] != ' ' && ptr[k] != '\t')
ptr[indis++] = ptr[k];
ptr[indis] = '\0';
return ptr;
}
main()
{
char s[100];
printf("bir yaz giriniz ");
gets(s);
printf("bosluksuz yaz : %s", rem_space(s));
return 0;
}
202
GSTERCLER
#include <stdio.h>
#include <conio.h>
#include <string.h>
char *mystrstr(char *s1, char *s2);
int main()
{
char s1[100];
char s2[100];
char *ptr;
printf("aramann yaplaca yazy girin : ");
gets(s1);
printf("aranacak yazy girin :");
gets(s2);
ptr = mystrstr(s1, s2);
if (ptr)
puts(ptr);
else
puts("aradnz yaz bulunamadn");
getch();
return 0;
}
/*
trknum.c
klavyeden girilen bir yaz ierisindeki trke karakterlerin
saysn bulan fonksiyon
*/
#include
#include
#include
#include
<stdio.h>
<conio.h>
<string.h>
<ctype.h>
203
19
int counter = 0;
int i;
char trk[ ] = "";
for (i = 0; str[i] != '_; ++i)
if (strchr(trk, str[i]))
++counter;
return counter;
}
/*
stricmp.c
Byk harf kk harf duyarl olmadan iki stringi karlatran
bir fonksiyonun tasarm fonksiyon
*/
#include
#include
#include
#include
<stdio.h>
<conio.h>
<string.h>
<ctype.h>
/*
nowords.c
adresi verilen bir yazdaki kelime saysn bulan
int no_of_words(char *str);
fonksiyonunun tasarlanmas
*/
#include <stdio.h>
#include <ctype.h>
#define
OUT
0
204
GSTERCLER
#define
#define
IN
MAX_LEN
1
200
205
20
20 . BLM : STRINGLER
C programa dilinde iki trnak ierisindeki ifadelere string ifadeleri ya da ksaca stringler denir.
rnein:
"Kaan Aslan"
"x = %d\n"
"ltfen bir say giriniz : "
ifadelerinin hepsi birer stringdir.
Stringlerin tek bir atom olarak ele alndn nceki derslerden hatrlyoruz. C'de stringler
aslnda char trden bir adres olarak ele alnmaktadr. C derleyicileri, derleme aamasnda bir
stringle karlatnda, nce bu stringi bellein gvenli bir blgesine yerletirir, sonuna NULL
karakteri ekler ve daha sonra string yerine yerletirildii yerin balang adresini koyar. Bu
durumda string ifadeleri aslnda stringlerin bellekteki balang yerini gsteren char trden
birer adrestir. rnein:
char *p;
...
p = "Nuri Ylmaz";
gibi bir kodun derlenmesi srasnda, derleyici nce "Nuri Ylmaz" stringini bellein gvenli bir
blgesine yerletirir; daha sonra yerletirdii yerin balang adresini string ifadesi ile deitirir.
Stringler char trden bir adres olarak ele alndna gre char trden gstericilere
atanmalarnda error ya da uyar gerektiren bir durum sz konusu deildir.
206
STRINGLER
Derleyici derleme aamasnda iki stringi de bellekte gvenli bir blgeye yerletirir. alma
zaman srasnda strcpy fonksiyonu "Ali" stringini gsteren adresten balayarak "Kaan" stringini
gsteren adrese NULL karakter grene kadar kopyalama yapacana gre, bu ifadenin faydal
hibir anlam olmayacaktr. stelik bu ifade, ikinci string birinciden uzun olduu iin bir
gsterici hatasna da neden olur. imdi aadaki ifadeyi inceleyelim:
p = "Kaan" + "Necati";
Yukardaki rnekte aslnda "Kaan" stringinin balang adresi ile "Necati" stringinin balang
adresi toplanmaktadr. Peki bu toplamn yararl bir sonucu olabilir mi? Derleyiciler
anlamszlndan dolay iki adresin toplanmasna izin vermezler. Fakat bir gstericiden baka bir
gstericinin deerini karmann yararl gerekeleri olabilir. Bu yzden gstericilerin birbirinden
kartlmas derleyicilerin hepsinde geerli bir ilemdir. Gsterici aritmetiine gre bir adresten
ayn trden bir baka bir adres kartld zaman elde edilen sonu bir tamsaydr, ve bu say
iki adresin saysal bileenlerinin fark deerinin adresin tr uzunluuna blnmesiyle elde edilir:
#include <stdio.h>
int main()
{
char
char
long
long
*p = (char *) 0x1AA8;
*q = (char *) 0x1AA0;
*lp = (long *) 0x1AA8;
*lq = (long *) 0x1AA0;
207
20
int k;
...
for (k = 0; k < 10; ++k) {
p = "Necati Ergin";
printf("%p\n", p);
}
...
Eer yer ayrma ilemi alma zaman srasnda yaplsayd, o zaman farkl adresler baslabilirdi.
Stringlerin dorudan karlatrlmas yanl bir ilemdir.
...
if (Ankara == Ankara)
printf(dogru\n);
else
printf(yanl\n);
...
Yukardaki kodun altrlmas durumunda byk bir olaslkla ekrana yanl yazdrlacaktr.
nk derleyicinin if parantezi iindeki karlatrma ifadesindeki iki Ankara stringinin
bellekte ayr yerlere yerletirilmesi durumunda, bu iki string birbirinden farkl iki ayr char
trden adres olarak deerlendirilir. Benzer bir yanllk aadaki kod parasnda da yaplmtr.
char *str = Mavi ay;
char s[20];
printf(parolay giriniz : );
gets(s);
if (str == s)
printf(dogru parola\n);
else
printf(yanl parola\n);
s bir dizi ismidir ve derleyici tarafndan dizinin yerletirildii bloun balangc olan char trden
bir adres sabiti gibi ele alnr. str ise char trden bir gstericidir. str gstericisine Mavi ay
stringi atandnda, derleyici nce Mavi ay stringini bellekte gvenli bir yere yerletirir daha
sonra stringin yerletirildii yerin balang adresini str gstericisine atar. program kullanann
parola olarak Mavi ay girdiini varsayalm. Bu durumda if deyimi iinde yalnzca s adresiyle
str gstericisinin iindeki adresin eit olup olmad kontrol edilmektedir. Bu adresler de eit
olmadklar iin ekrana "yanl parola" yazlacaktr. ki yaznn birbirine eit olup olmad
strcmp fonksiyonu ile kontrol edilmeliydi:
char *str = Mavi ay;
char s[20];
printf(parolay giriniz : );
gets(s);
if (!strcmp(str, s))
printf(dogru parola\n);
else
printf(yanl parola\n);
Stringlerin mrleri
Stringler statik mrl nesnelerdir. Tpk global deikenler gibi programn yklenmesiyle
bellekte yer kaplamaya balarlar, programn sonuna kadar bellekte kalrlar. Dolaysyla stringler
alabilen kodu
bytr. Birok sistemde statik verilerin toplam uzunluunda belli bir
snrlama sz konusudur.
208
STRINGLER
Stringler derleyici tarafndan .obj modle linker tarafndan da .exe dosyasna yazlrlar.
Programn yklenmesiyle hayat kazanrlar.
Bir exe program 3 blmden olumaktadr:
kod
data
stack
Kod blmnde, fonksiyonlarn makine kodlar vardr. Data blmnde, statik mrl nesneler
bulunmaktadr, global deikenler ve stringler bu blmde bulunurlar. Stack blm yerel
deikenlerin sakland bellek alandr. Stack blm her sistemde snrl bir alandr. rnein
DOS iletim sisteminde 64K byklnde bir stack sz konusudur. Yani hi bir zaman yerel
deikenlerin bellekte kaplad alan 64K deerini geemez. WINDOWS iletim sisteminde
default stack snr 1 MBdr. Ancak bu snr istenildii kadar bytlebilir.
Daha nceki derslerimizde, bir fonksiyonun yerel bir deikenin adresi ile geri dnmemesi
gerektiini sylemitik. nk fonksiyon sonlandnda yerel deikenler bellekten boaltlaca
iin, fonksiyonun geri dndrd adres gvenli bir adres olmayacaktr. rnein aadaki
program hataldr:
char *getname(void)
{
char s[100];
int main()
{
char *ptr;
ptr = getname();
puts(ptr);
return 0;
}
Fonksiyon bir stringin adresiyle geri dnebilir, bu durumda bir yanllk sz konusu
olmayacaktr. nk stringler programn alma sresi boyunca bellektedir. rnein aadaki
programda hatasz olarak alr:
char *getday(int day)
{
char *ptr;
switch (day) {
case 0: p =
case 1: p =
case 2: p =
case 3: p =
case 4: p =
case 5: p =
case 6: p =
}
return p;
Sunday; break;
Monday; break;
Tuesday; break;
Wednesday; break;
Thursday; break;
Friday; break;
Saturday;
209
20
Stringlerin Birletirilmesi
Daha nce sylendii gibi stringler tek bir atom olarak ele alnmaktadr. Bir string aadaki
gibi paralanamaz:
char *ptr;
...
ptr = "Necati Ergin'in C Dersi
Notlarn okuyorsunuz";
/* error */
Ancak string ifadeleri bydke bunu tek bir satrda yazmak zorlaabilir. Ekrandaki bir satrlk
grntye smayan satrlar kaynak kodun okunabilirlirliini bozar. Uzun stringlerin
paralanmasna olanak vermek amacyla C derleyicileri yanyana yazlan string ifadelerini
birletirirler. rnein:
ptr = "Necati Ergin'in C Dersi"
"Notlarn okuyorsunuz";
geerli bir ifadedir. Bu durumda iki string birletirilerecek ve aadaki biime getirilecektir.
ptr = "Necati Ergin'in C Dersi Notlarn okuyorsunuz";
Derleyicinin iki stringi birletirmesi iin, stringlerin arasnda hibir operatrn bulunmamas
gerekmektedir. :
p = "Necati " "Ergin";
ifadesi ile
p = "Necati Ergin";
ifadesi edeerdir.
Birletirmenin yan sra, bir ters bl karakteri ile sonlandrlarak sonraki satra gei
salanabilir. rnein:
ptr = "Necati Ergin'in C Dersi \
Notlarn okuyorsunuz";
ifadesi ile
ptr = "Necati Ergin'in C Dersi Notlarn okuyorsunuz";
ifadesi edeerdir. Tersbl iaretinden sonra string aadaki satrn bandan itibaren devam
etmelidir. Sz konusu string aadaki ekilde yazlrsa:
ptr = "Necati Ergin'in C Dersi \
Notlarn okuyorsunuz";
satr bandaki boluk karakterleride stringe katlr ve sonu aadaki ifadeye edeer olur:
ptr = "Necati Ergin'in C Dersi
Notlarn okuyorsunuz";
Ancak ters bl karakteri ile sonraki satrn bandan devam etme standart olarak her C
derleyicisinde geerli olmayabilir. atmal bir durumla karlatnzda altnz
derleyicilerin referans kitaplarna bavurmalsnz.
210
STRINGLER
20
elemanlarna tek tek char trden sabitlerle ilk deer verme ilemi zahmetli olduu iin,
programcnn iini kolaylatrmak amac ile dile bu ilk deer verme sentaks eklenmitir.
Yani
char s[10] = "Deneme";
aslnda
char s[10] = {'D', 'e', 'n', 'e', 'm', 'e', '\0'};
ile ayn anlamdadr.
cinde Yaz Tutan char Trden Dizilerle Bir Stringi Gsteren char Trden
Gstericilerin Karlatrlmas
imdiye kadar alm olduumuz bilgileri deerlendirdiimizde, C dilinde bir yazy saklamak iki
ayr ekilde salanabilir:
1. Yazy char trden bir dizi iinde saklamak:
...
char s1[100] = Necati Ergin;
char s2[100];
char s3[100];
gets(s2);
strcpy(s2, s3);
2. Yazy bir string olarak saklayarak char trden bir gstericinin bu stringi gstermesini
salamak .
char *str = Necati Ergin;
ki yntem birbirinin tamamen alternatifi deildir ve aadaki noktalara dikkat edilmesi
gerekmektedir:
stringler statik nesneler olduklar iin programn sonlanmasna kadar bellekte yer kaplarlar.
Yani bir gstericinin bir stringi gsterirken daha sonra baka bir stringi gsterir duruma
getirilmesi , daha nceki stringin bellekten silinmesi anlamna gelmeyecektir.
char *s = Bu string programn sonuna kadar bellekte kalacak.;
s = artk yukardaki string ile bir balantmz kalmayacak...;
Yaznn char trden bir dizi iinde tutulmas durumunda bu yazy deitirmemiz mmkndr.
Dizi elemanlarna yeniden atamalar yaparak yazy istediimiz gibi deitirebiliriz ama
stringlerin deitirilmesi tanabilir bir zellik deildir. Stringler iinde bulunan yazlar
deitirilmemelidir. Aadaki kod paralar tanabilir deildir:
char *s = Metin;
char *str = Ankara;
s[1] = ;
strcpy(str, Bolu);
Derleyicilerin zde stringleri ayn adreste saklamalar konusunda bir garanti yok. zde
stringler ayn adreste tek kopya olarak ya da farkl adreslerde tutuluyor olabilir. Daha nce
sylediimiz gibi derleyiciler bu konuda birbirinden farkl davranabilirler. Yani yukardaki
rneklerde biz Metin ya da Ankara stringini deitirdiimizde, bu stringleri program iinde
212
STRINGLER
baska yerlerde de kullanmsak, bunlarn hepsinin deitirilmi olmas gibi bir tehlike sz
konusudur.
char *s = "dosya alamyor"; /* birinci string */
char a[] = "dosya alamyor";
...
printf("%s", s);
...
printf("dosya alamyor");
...
strcpy(s, "Dosya Ald");
...
/* ikinci string */
"dosya alamyor" stringinin derleyici tarafndan ayn adreste tek kopya olarak saklandn
farsayalm. s adresinde bulunan stringe yeni bir yaz kopyalannca hem birinci string hemde
ikinci string deimi olur.
213
21
214
GSTERC DZLER
...
for (k = 0; k < 10; ++k)
free(s[k]);
...
gsterici dizilerine ilk deer verilmesi
Normal dizilere ilkdeer nasl veriliyorsa gsterici dizilerine de ilk deer ayn biimde verilir. rnein:
int *p[] = {
(int *) 0x1FC0,
(int *) 0x1FC2,
(int *) 0x1FC4,
(int *) 0x1FC6,
(int *) 0x1FC8
}
Kukusuz ki, gsterici dizisine atanan adreslerin bir ama dorultusunda kullanlabilmesi iin gvenli
blgeleri gstermesi gerekir. Bu nedenle uygulamada karakter gsterici dizisi dndaki gsterici dizilerine ilk
deer verilmesi durumuna pek raslanmaz. Gsterici dizilerine ilk deer verme ilemi genellikle karakter
gsterici dizilerine string ifadeleriyle ilk deer verilmesi biiminde karmza kmaktadr.
char trden gsterici dizileri
Uygulamalarda en sk grlen gsterici dizileri char trden olan gsterici dizilerdir.
Daha nce stringler konusunda da grdmz gibi, stringler C derleyicisi tarafndan char trden adresler
olarak ele alndna gre, char trden bir gsterici dizisine stringler araclyla ilk deer verilebilir:
char *aylar[] = {Ocak",
"ubat",
"Mart",
"Nisan",
"Mays",
"Haziran",
"Temmuz",
"Austos",
"Eyll",
"Ekim",
"Kasm",
"Aralk"
};
aylar dizisinin her bir eleman char trden bir gstericidir. Ve bu gsterici dizisine stringler ile ilk deer
verilmitir. Baka bir deyile char trden bir gsterici dizisi olan aylar dizisinin her bir eleman bir yazy
gstermektedir.
char trden gsterici dizilerinin kullanlma nedenleri
1. Program iinde sk kullanlacak yazlarn her defasnda yazlmas yerine bir gsterici dizisinin
elemanlarnda saklanmas. Aadai rnekte err dizisinin her bir elemannda hata mesajlarna ilikin yazlar
saklanmtr.
char *err[] = {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 istenirse, yazdrlacak olan yalnzca gsterici
dizisinin herhangi bir elemannda balang adresi tutulan yazdr :
...
215
21
if (fp == NULL) {
printf("%s\n", err[5]);
return 5;
}
....
2. Baz yazlarn bu ekilde bir algoritmaya bal olarak kullanlmas :
#include <stdio.h>
int dayofweek(int day, int month, int year);
char *aylar[] = {Ocak",
"ubat",
"Mart",
"Nisan",
"Mays",
"Haziran",
"Temmuz",
"Austos",
"Eyll",
"Ekim",
"Kasm",
"Aralk"
};
char *gunler[] = {"Pazar",
"Pazartesi",
"Sal",
"aramba",
"Perembe",
"Cuma",
"Cumartesi"
};
void display_date(int day, int mon, int year)
{
printf("%02d ", day);
puts(aylar[mon - 1]);
printf(" %d ", year);
}
Bir yaznn belirli bir yazyla ayn olup olmadn, strcmp fonksiyonuyla saptayabiliriz. Peki bir yaznn bir
grup yaz iinde var olup olmadn nasl tespit edebiliriz? Aada tanmlanan getmonth fonksiyonu
kendisine balang adresi gnderilen bir yaznn ingilizce ay isimlerinden biri olup olmadn test etmekte,
eer byle ise bu ayn kanc ay olduu bilgisiyle geri dnmektedir. (1 - 12) Fonksiyon, kendisine gnderilen
argumanda balang adresi tutulan yaz bir ay ismine karlk gelmiyor ise 0 deeriyle geri dnmektedir.
#include <stdio.h>
#include <string.h>
int getmonth(char *str)
{
char *months[] = {"Jan", Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
int k;
for (k = 0; k < 12; ++k)
if (!stricmp(months[k], str)
return k + 1;
return 0;
216
GSTERC DZLER
}
main()
{
char s[20];
int n = 20;
int result;
while (n-- > 0) {
printf("bir ay ismi giriniz .");
gets(s);
result = getmonth(s);
if (result)
printf("%s yln %d. aydr\n", s, result);
else
printf("%s gecerli bir ay ismi deildir\n");
}
return 0;
}
stricmp fonksiyonunun iki yaznn karlatrmasn byk harf kk harf duyarll olmadan yapmas
dnda, strcmp fonksiyonundan baka bir fark bulunmadn hatrlayalm.
Gsterici dizileri de tpk dier diziler gibi yerel ya da global olabilecektir. Eer dizinin global olmas
durumunda dizi elemanlarnn hepsinin iinde 0 deerleri olurken, yerel bir gsterici dizisinin iinde rasgele
deerler olacaktr. Dizinin her bir eleman iinde bir adres bilgisi olduuna gre, atama yaplmam global
gsterici dizilerinin her bir eleman iinde 0 adresi (NULL adresini) bulunurken, atama yaplmam yerel
gsterici dizilerinin elemanlar iinde rasgele deerler bulunmaktadr.
Bir gsterici hatasna neden olmamak iin nce gsterici dizisi elemanlarna gvenli adresler yerletirmek
gerekmektedir. Stringler statik nesneler gibi ele alndklar iin bir gsterici dizisi elemanlarna stringlerle
deer vermek bir gsterici hatasna enden olmayacaktr. Zira stringler, daha nce de belirtildii gibi nce
derleyici tarafndan bellekte gvenli bir blgeye yerletirilirler, daha sonra ise yerletirildikleri bloun
balang adresi olarak ele alnrlar.
217
22
218
malloc fonksiyonu
malloc fonksiyonu programn alma zaman srasnda bellekten dinamik tahsisat yapmak iin
kullanlr. Fonksiyonun prototipi aadaki gibidir :
void *malloc(size_t nbyte);
size_t trnn derleyiciye yazanlarn seimine bal olarak unsigned int ya da unsigned long
trlerinden birinin yeni tr ismi olarak tanmlanmas gerektiini, ve sistemlerin hemen hemen
hepsinde size_t trnn unsigned int tr olduunu hatrlayalm.
Fonksiyona gnderilecek arguman tahsis edilmek istenen bloun byte olarak uzunluudur.
Tahsis edilen alann srekli (contigous) olmas garanti altna alnmtr. malloc fonksiyonunun
geri dn deeri tahsis 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 tahsis edilen blok gsterici yardmyla bir dizi gibi
kullanlabilir. malloc fonksiyonunun istenilen blou tahsis etmesi garanti altnda deildir. Birok
219
23
nedenden dolay malloc fonksiyonu baarsz olabilir. Bellekte tahsis edilmek istenen alan kadar
bo bellek bulunmamas sk grlen baarszlk nedenidir. malloc fonksiyonu baarsz
olduunda NULL adresine geri dner. malloc fonksiyonu bellekten yer ayrdktan sonra
ileminin baarl olup olmad mutlaka kontrol edilmelidir. malloc fonksiyonu ile bellekte bir
blok tahsis edilmesine ilikin aada bir rnek verilmitir.
char *ptr;
ptr = (char *) malloc(30);
if (ptr == NULL) {
printf("cannot allocate memory\n");
exit(EXIT_FAILURE);
}
/* baarszlk durumunda program sonlandrlyor */
printf("please enter the name : ");
gets(ptr);
/* tahsis edilen alana klavyeden giri yaplyor */
...
phesiz, malloc fonksiyonu baarsz olduunda program sonlandrmak zorunlu deiliz.
Atama ve kontrol bir defada da yaplabilir.
if ((ptr = (char *) malloc(30)) == NULL) {
printf("cannot allocate memory\n");
exit(EXIT_FAILURE); /* baarszlk durumunda program sonlandrlyor */
}
malloc fonksiyonu ile yaplan dinamik tahsisatn baarl olup olmad mutlaka kontrol
edilmelidir. Fonksiyonun baarsz olmas durumunda, geri dn deerinin aktarld gsterici
aracl ile bellege birey yazlmaya allrsa, atama NULL adrese yaplm olur. (NULL pointer
assignment). Programn yanl almas kanlmazdr.
Programclar ou kez, kk miktarlarda ve ok sayda bloun tahsis edilmesi durumunda,
kontrol gereksiz bulma eilimindedir. Oysa kontrolden vazgemek yerine daha kolaylatrc
yntemler denenmelidir. rnein p1, p2, p3, p4, p5 gibi 5 ayr gsterici iin 10'ar byte alan
tahsis edilmek istensin. Bu durumda kontrol mantksal operatrler ile tek hamlede yaplabilir.
char *p1, *p2, *p3, *p4, *p5;
...
p1
p2
p3
p4
p5
=
=
=
=
=
(char
(char
(char
(char
(char
*)malloc(10);
*)malloc(10);
*)malloc(10);
*)malloc(10);
*)malloc(10);
220
Yukardaki kod parasnda int tr uzunluunun 2 byte olduu varsaylmtr. Kaynak kod int
tr uzunluunun 4 byte olduu bir sistemde (rnein UNIX) derlenirse problemler ortaya
kacaktr. Bu tanabilirlik problemi sizeof operatrnn kullanlmasyla zlr.
ptr = (int *) malloc(number * sizeof(int));
Artk allan sistem ne olursa olsun number sayda tamsay eleman iin alan tahsis edilmi
olacaktr.
malloc fonksiyonu birden fazla arlarak birden fazla alan tahsis edilebilir. malloc fonksiyonun
farkl armlaryla tahsis edilen bloklarn bellekte ardl olmas garanti altna alnm deildir.
Bu yzden fonksiyonun geri dn deeri olan adres mutlaka bir gstericide saklanmaldr.
Aadaki kod paras ardk olarak arlan malloc fonksiyonlarnn ardk bellek bloklar
tahsis edeceini varsayd iin yanltr.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int * ptr;
int i;
ptr = malloc(sizeof(int) * 10);
malloc(sizeof(int) * 10);
/* tahsis edilen alan daha nce tahsis edilen alann hemen
altnda olmak zorunda deildir */
for (i = 0; i < 20; ++i)
ptr[i] = 5;
return 0;
}
malloc fonksiyonu ile tahsis edilen bloun iinde rasgele deerler vardr. Aadaki kod paras
ile bunu test edebiliriz.
221
23
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *ptr;
int i;
ptr = (int *) malloc(10 * sizeof(int));
if (ptr == NULL) {
printf("yetersiz bellek!..\n");
exit(1);
}
for (i = 0; i < 10; ++i)
printf("ptr[%d] = %d\n", i, ptr[i]);
return 0;
}
Dinamik bellek fonksiyonlar kullanlarak tahsis edilebilecek bellek blgesi heap olarak
isimlendirilmitir. heap alan donanmsal bir kavram olmayp sistemden sisteme
deiebilmektedir. (C++ dilinde bu alan free store olarak isimlendirilmektedir.)
malloc fonksiyonunun parametre deikeni unsigned int (size_t) trnden olduuna gre,
DOS altnda en fazla 65535 byte (64K) ardl tahsisat yaplabilir. Oysa UNIX, WINDOWS ve
dier 32 bitlik sistemlerde unsigned int tr 4 byte uzunluund olduuna gre, bu
sistemlerde teorik olarak, malloc fonksiyonu ile 4294967295 byte (4 MB) uzunluunda ardl
bir tahsisat yaplabilir.Tabi bu durum, tahsisatn yaplabilecei anlamna gelmez.
calloc fonksiyonu
calloc fonksiyonu malloc fonksiyonuna ok benzer. Prototipi aadaki gibidir.
void *calloc(size_t nblock, size_t block_size);
calloc fonksiyonu kedisine gnderilen birinci arguman ile ikinci arguman arpm kadar ardl
byte' heap alanndan tahsis etmek iin kullanlr.
Elemanlar int trden olan 100 elemanl bir dizi iin dinamik bellek tahsisat calloc fonksiyonu
ile aadaki ekilde yaplabilir:
int *ptr;
...
ptr = (int*) calloc(100, sizeof(int));
if (ptr == NULL) {
printf("cannot allocate memory\n");
exit(EXIT_FAILURE);
}
...
phesiz yukardaki kod parasnda calloc fonksiyonu u ekilde de arlabilirdi:
ptr = (int*) calloc( sizeof(int), 100);
calloc fonksiyonunun malloc fonksiyonundan baka bir fark da tahsis ettii bellek blounu
sfrlanmasdr. calloc fonksiyonu tarafndan tahsis edilen blounun tm byte'larnda sfr
deerleri vardr. malloc fonksiyonu calloc fonksiyonuna gre ok daha sk kullanlr. Tahsis
edilen blok sfrlanacaksa malloc fonksiyonu yerine calloc fonksiyonu tercih edilmelidir.
222
realloc fonksiyonu
realloc fonksiyonu daha nce malloc ya da calloc fonksiyonlaryla tahsis edilmi bellek blounu
byltmek ya da kltmek amacyla kullanlr. Prototipi dier dinamik bellek fonksiyonlarnda
olduu gibi stdlib.h balk dosyas iindedir.
void *realloc(void *block, unsigned newsize);
realloc fonksiyonuna gnderilen birinci arguman, daha nce tahsis edilen bellek blounun
balang adresi, ikinci arguman ise bloun toplam yeni uzunluudur.
realloc fonksiyonu daha nce tahsis edilmi bloun hemen altnda sreklilii bozmayacak
ekilde tahsisat yapamaya alr. Eer daha nce tahsis edilmi bloun aasnda istenilen
uzunlukta srekli yer bulamazsa realloc, bu sefer bloun tamam iin bellekta baka bo yer
aratrr. Eer istenilen toplam uzunlukta ardl (contigious) bir blok bulunursa buray tahsis
eder, eski bellek bloundaki deerleri yeni yere tar ve eski bellek blounu iletim sistemine
iade eder. stenen uzunlukta srekli bir alan bulunamazsa NULL adresiyle geri dner.
Aadaki programda yaplan dinamik bellek tahsisat ilemlerini inceleyelim:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *ptr;
ptr = (int *) malloc(sizeof (int) * 5);
if (ptr == NULL) {
printf("bellek yetersiz!..\n");
exit(EXIT_FAILURE);
}
/* 1
}
return 0;
223
*/
23
}
1. malloc fonksiyonu ile 5 int lik yer tahsis ediliyor. Eer tahsisat ilemi baarl deilse exit
fonksiyonuyla program sonlandrlyor.
1A00
1A01
?
?
1A02
1A03
1A04
1A05
1A06
1A07
1A08
1A09
?
?
?
?
?
?
?
?
<--ptr
1A02
1A03
1A04
1A05
1A06
1A07
1A08
1A09
<--ptr
2
3
4
3. realloc fonksiyonuyla tahsis edilen alan 10 int saylk rnein DOS altnda alyorsak 20
byte'a kartlyor.
Eer realloc fonksiyonu baarsz olursa program sonlandrlyor. realloc fonksiyonu baarl
olmusa iki ihtimal sz konusudur.
1. realloc fonksiyonu daha nce tahsis edilen alann altnda boalan bularak ilave tahsisat
buradan yapmtr :
ptr----->
1A00
1A01
1A02
1A03
1A04
1A05
1A06
1A07
1A08
1A09
1A0A
1A0B
1A0C
1A0D
1A0E
1A0F
1A10
1A11
1A12
1A13
0
1
2
3
4
?
?
?
?
?
2. realloc fonksiyonu daha nce tahsis edilen bloun altnda bo yer bulamam ve heap
alannda toplam 20 bytelk baka bir bo yer bulmu olabilir. Bu durumda realloc fonksiyonu
daha nce tahsis edilmi alandaki deerleri de bu alana kopyalamtr :
224
1F00
1F01
1F02
1F03
1F04
1F05
1F06
1F07
1F08
1F09
1F0A
1F0B
1F0C
1F0D
1F0E
1F0F
1F10
1F11
1F12
1F13
0
1
2
3
4
?
?
?
?
?
23
Byle bir durumda geici bir gsterici kullanmak uygun olacaktr:
temp = realloc(ptr, 100);
if (temp == NULL)
printf("cannot allocate memory!..\n);
Bu durumda ptr gstericisi halen daha nce tahsis edilen bloun balang adresini
gstermektedir.
C standartlar realloc fonksiyonu ile ilgili olarak aadaki kurallar getirmitir:
Bir bellek blounu genletmesi durumunda, realloc fonksiyonu bloa ilave edilen ksma
herhangi bir ekilde deer vermez. Yani eski bloa eklenen yeni blok iinde rasgele deerler
(garbage values) bulunacaktr.
realloc fonksiyonu eer daha nce tahsis edilmi belelk blounu bytemez ise NULL adresi ile
geri dnecektir ancak tahsis edilmi olan (bytlemeyen) bellek bloundaki deerler
korunacaktr.
Eer realloc fonksiyonuna gnderilen birinci arguman NULL adresi olursa, realloc fonksiyonu
tamamen malloc fonksiyonu gibi davranr. Yani:
realloc(NULL, 100);
ile
malloc(100);
tamamen ayn anlamdadr.
(Buna neden gerek grlmtr? Yani neden malloc(100) gibi bir arm yapmak yerine
realloc(NULL, 100) eklinde bir arm tercih edelim?
Aadaki program inceleyelim :
#include
#include
#include
#include
<stdio.h>
<conio.h>
<ctype.h>
<stdlib.h>
226
}
if (counter == 0) {
printf("hibir not girii yapmadnz!..\n");
return 0;
}
printf("toplam %d tane not girdiniz\n", counter);
printf("girdiiniz notlar aada listelenmektedir :\n");
display_array(ptr, counter);
printf("\nen buyuk not : %d\n", find_max(ptr, counter));
printf("en kk not : %d\n", find_min(ptr, counter));
printf("notlarn ortalamas : %lf\n", find_ave(ptr, counter));
printf("notlarn standart sapmas . %lf\n", find_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 fonksiyonu
malloc gibi davranacak ve int trden 1 adet nesnelik yer tahsis edecektir. Ancak dngnn
daha sonraki turlarnda realloc fonksiyonuna gnderilen adres NULL adresi olmayacandan,
daha nce tahsis edilen blok dng iinde srekli olarak bytlm olacaktr.
Tahsis edilen bloun serbest braklmas
malloc ya da dier dinamik bellek fonksiyonlar "heap" diye isimlendirilen bir bellek blgesinden
tahsisat yaparlar. Ancak heap alan da snrldr ve srekli bu fonksiyonlarn arlmas
durumunda, belirli bir noktadan sonra fonksiyonlar baarsz olarak NULL adresine geri
dnecektir. heap alannn bykln aadaki kod ile test edebiliriz :
#include <stdio.h>
#include <stdlib.h>
#define BLOCK_SIZE
512
int main()
{
long total = 0;
char *ptr;
for (;;) {
ptr = (char *) malloc(BLOCK_SIZE);
if (ptr == NULL)
break;
total += BLOCK_SIZE;
}
printf("toplam heap alan = %ld byte\n", total);
return 0;
227
23
}
Dinamik bellek fonksiyonlaryla tahsis edilen bir blok free fonksiyonu kullanlarak sisteme iade
edilebilir. free fonksiyonunun prototipi de dier dinamik bellek fonksiyonlarnnkiler gibi stdlib.h
balk dosyas iindedir:
void free(void *ptr);
free fonksiyonuna gnderilecek olan arguman, daha nce malloc, calloc ya da realloc
fonksiyonlaryla tahsis edilmi olan bellek blounun balang adresidir. Bu blok heap alanna
iade edilmi olur. Bylece malloc, calloc ya da realloc fonksiyonunun bundan sonraki bir
armnda iade edilen blok, tekrar tahsis edilme potansiyelindedir.
free fonksiyonuna arguman olarak daha nce tahsis edilen bir bellek blounun balang adresi
yerine baka bir adres gnderilmesi pheli kod oluturur (undefined behaviour)
yaplmamaldr.
char *p1;
char s[100];
ptr = (char *)malloc(20);
....
free(ptr) /* Legal */
free(p1) /* Bu adreste dinamik bellek fonksiyonlar ile tahsis edilmi bir alan yok. Hata. */
free(s)
/* Hata s dizisi iin tahsisat dinamik bellek fonksiyonlar ile yaplmamtr. */
free fonksiyonu ile daha nce tahsis edilen blok sisteme iade edilir, ama bu bloun balang
adresini tutan gsterici herhangi bir ekilde deitirilmez. Bloun balang adresini tutan, ve
free fonksiyonuna arguman olarak gnderilen gsterici, free fonksiyonun arlmasndan sonra
artk gvenli olmayan bir adresi gstermektedir.
char *ptr = malloc(100);
...
free(ptr);
...
strcpy(ptr, "Necarti Ergin");
Eer realloc fonksiyonuna gnderilen ikinci arguman 0 olursa, realloc fonksiyonu tamamen free
fonksiyonu gibi davranr.
realloc(ptr, 0);
ile
free(ptr);
tamamen ayn anlamdadr.
(Buna neden gerk grlmtr? Yani neden free(ptr) gibi bir arm yapmak yerine
realloc(ptr, 0) eklinde bir arm tercih edelim?
Dinamik Olarak Tahsis Edilen Bir Alann Balang Adresine Geri Dnen
Fonksiyonlar
Dinamik olarak tahsis edilen bir blok, free fonksiyonuyla serbest braklarak sisteme iade
edilene kadar gvenli olarak kullanlabileceine gre , bir fonksiyon byle bir bloun balang
adresine geri dnebilir. Aadaki fonksiyon tasarmn inceleyelim :
#include <stdio.h>
#include <string.h>
228
229
23
strcpy(ptr, s1);
strcat(ptr, s2);
return ptr;
230
BELRLEYCLER
24 . BLM : BELRLEYCLER
Belirleyiciler (specifiers), bildirimler yaplrken kullanlan ve nesnelerin ikincil zellikleri
hakknda derleyicilere bilgi veren anahtar szcklerdir. Belirleyicileri yer belirleyicileri (storage
class specifiers) ve tr belirleyicileri (type qualifiers) olarak iki grupta inceleyeceiz.
Yer belirleyicileri genel olarak nesnelerin tutulduklar yerler hakknda bilgi verirler. Tr
belirleyicileri ise nesnelerin iindeki deerlerin deitirilip deitirilmeyeceine ilikin bilgi
verirler. C'de 4 tanesi yer belirleyici (auto, register, static, extern) ve 2 tane tr belirleyici
(const, volatile) vardr. Bu belirleyici isimleri C dilinin birer anahtar szcdr.
a;
a;
a;
a;
auto Belirleyicisi
auto yalnzca yerel deikenler iin kullanlabilecek bir yer belirleyicisidir. auto belirleyicisinin
global deikenlerin ya da fonksiyonlarn parametre deikenlerininin bildiriminde kullanlmas
derleme zamannda hata oluturur.
Bu anahtar szck, nesnenin faaliyet alan bittikten sonra kaybolacan, bellekte kaplad
yerin geerlilii kalmayacan gsterir. Yerel deikenler bulunduklar blok icra edilmeye
balandnda yaratlyorlar, sz konusu bloun icras bittikten sonra yok oluyorlard. te auto
belirleyicisi bu durumu vurgulamak iin kullanlmaktadr. 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;
}
auto yer belirleyicisi global deikenlerle ya da parametre deikenleriyle birlikte kullanlmaz.
rnein :
231
24
auto int a;
/* hata nk global bir deiken auto olarak bildirilemez */
function(auto int x) /* hata parametre deikeni auto biiminde bildirilemez */
{
auto int var;/* yereldeiken auto olabilir */
int x;
/*yerel deiken auto belirleyicisi kullanlmasa da auto olarak ele alnr*/
...
}
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 ierisinde tutulacan
belirten bir anahtar szcktr. Deikenlerin bellek yerine yazmalar ierisinde tutulmas
programn almasn hzlandrr.
Yazma (register) nedir? Yazmalar CPU (central processing unit) ierisinde bulunan tampon
bellek blgeleridir. CPU ierisindeki aritmetik ve mantksal ilemleri yapan birimin yazmalar ve
belleklerle ilikisi vardr. Genel olarak CPU tarafndan yaplan aritmetik ve mantksal ilemlerin
her iki operand da bellee ilikin olamaz. rnein bellekte bulunan sayi1 ve sayi2 ile
gsterdiimiz 2 sayiyi toplayarak sayi3 ile gsterdiimiz baka bir bellek blgesine yazmak
isteyelim. Bu Cdeki
sayi3 = sayi1 + sayi2;
ilemine karlk gelmektedir. 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 data3 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 gerekmektedir.
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
mesajlar vermezler. Yani derleyiciler, tutabilecekleri yazma saysndan fazla register
belirleyicisine sahip deikenlerle karlatklarnda bunlara ilikin register belirleyicilerini
dikkate almazlar.
register belirleyicileri ancak yerel ya da parametre deikenleri ile kullanlabilir global
deikenler ile kullanlamazlar. rnekler
register int x;
BELRLEYCLER
Sonu olarak register belirleyicisi hzn nemli olduu ok zel ve ksa kodlarda ancak birka
deiken iin kullanlmaldr. Modern derleyicilerin ou (seime bal) kod optimizasyonu
yaparak baz deikenleri yazmalarda saklayabilirler. Bu durum da ou zaman register
anahtar szcnn kullanlmasn gereksiz klar.
static Belirleyicisi
static belirleyicisine sahip deikenler programn alma sresince bellekten kaybolmazlar. Bir
bakma static belirleyicisi auto belirleyicisinin zt anlamlsdr. static belirleyicisi ancak yerel
ya da global deikenlere birlikte kullanlabilirler. static belirleyicisi parametre deikenleriyle
kullanlmazlar.
static anahtar szcnn global ve yerel deikenlerle birlikte kullanlmas farkl anlamlara
gelir bu yzden bu durumlar ayr ayr inceleyeceiz:
24
func(void)
{
static aylar[12] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
...
}
Yukardaki rnekte, func() fonksiyonu iinde aylar dizisi static anahtar szcyle tanmland
iin, bir kez ilk deer verildikten sonra her arld zaman bu deerleri koruyacak ve varln
programn sonlanmasna kadar devam ettirecektir. Oysa static anahtar szc
kullanlmasayd, bu dizi func() fonksiyonun her arlmasyla yeniden yaratlacak ve tm ilk
deer atamalar her defasnda yeniden yaplacakt. Bu da fonksiyonun her arlmasnda belirli
bir makine zamannn tekrar harcanmasna neden olacakt.
234
BELRLEYCLER
MOD2.C
int fonk2()
{
...
a = 300;
}
/* HATA */
main()
{
...
...
}
MOD1.C modlnde tanmlanm olan a deikeni global bir deikendir ve dosya faaliyet
alanna uyduu iin normal olarak proje iindeki dier modllerde de faaliyet gsterebilir.
MOD2.C modlnde de faaliyet gsterebilir. Fakat iki modln ayr ayr derlendii yukardaki
rnekte problemli bir durum sz konusudur. nk MOD2.C modlnn derlenmesi srasnda
derleyici a deikeninin MOD1.C modl ierisinde global olarak tanmlandn bilemez.
MOD2.C modln derlerken a deikeni hakknda bilgi bulamayan derleyici bu durumu hata
(error) olarak belirler. (C dilinde bir deiken ancak nceden bildirilmise kullanlabilir.) extern
belirleyicisi derleyiciye, ilgili global deikeninin kendi modl ierisinde deil de bir baka
modl ierisinde tanml olduunu bildirme amacyla kullanlr.
235
24
MOD2.C modlndeki a deikeninin extern olarak bildirilmesi durumunda sz konusu problem
ortadan kalkar.
MOD2.C
extern int a; /*extern bildirimiyle a deikeninin baka bir modlde tanmlanm olduu
belirtiliyor*/
int fonk2()
{
...
a = 300;
...
}
extern bildirimini gren derleyici deikenin projeye ait baka bir modlde tanmlandn
varsayarak hata durumunu ortadan kaldrr. Ancak derleyici makine kodu retirken extern
olarak bildirilmi bir deikenin bellekteki yerini tespit edemeyeceinden , bu ilemi btn
modlleri gzden geirecek olan balayc programa brakr. Bylece deikenin tanmland
modl bulup, extern olarak bildirilmi olanlarla ilikilendirme ilemi balayc (linker)
tarafndan yaplmaktadr. Yani extern belirleyicisi ile programc derleyiciye, derleyici ise
balaycya bildirimde bulunmaktadr.
extern belirleyicisini gren derleyici bellekte bir yer ayrmaz. extern bildirimi bir tanmlama
deildir,
bildirimdir.
Aslnda yalnz deikenler iin deil fonskiyonlar iin de extern belirleyicisinin kullanlmas sz
konusudur. C derleyicileri kendi modlleri ierisinde tanmlanmadklar halde arlan (standart
C fonksiyonlar gibi) fonksiyonlar otomatik olarak extern kabul ederler. Bu nedenle fonksiyon
prototiplerinde ayrca extern belirleyicisini yazmaya gerek yoktur. nk derleyici tarafndan
yazlm varsaylr.
rnein yukarda verilen rnekte MOD2.c modlnde bulunan y1 fonksiyonu ierisinde bulunan
x1 fonksiyonu arlyor olsun:
MOD1.c
int a;
float x1()
{
...
a = 100;
...
}
main()
{
...
}
MOD2.c
extern int a;
extern float x1(void);
int y1()
{
float f;
...
f = x1();
a = 300;
...
}
236
BELRLEYCLER
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 kacaktr.
extern belirleyicisinin tek bir modl sz konusu olduunda ama d bir kullanm vardr.
Aadaki rnekte main fonksiyonu ierisindeki global x deikeni, tanmlanmadan nce
kullanldndan hataya neden olmaktadr.
void main()
{
...
x = 100;
}
int x;
int fonk()
{
....
x
...
}
200;
200;
237
24
const belirleyicisi
const ilk deer atandktan sonra nesnenin ieriinin deitirilemeyeceini anlatan tr belirleyici,
bir anahtar szcktr. Yerel, global ve parametre deikenleriyle birlikte kullanlabilir.
rnein :
const double PI = 3.14159265
/*Geerli */
main()
{
const int i = 10;
i = 100;
/* hata */
}
Bir deiken const belirleyicisi ile tanmlanacaksa ilk deer verilmelidir. Aksi halde const
belirleyicisi kullanmann bir anlam kalmaz. Aadaki rnei inceleyiniz.
void sample (void)
{
const int a; /* anlamsz */
}
Bu rnekte a yerel bir deikendir, dolaysyla rastgele bir deere sahiptir. eriini bir daha
deitiremeyeceimize gre tanmlanmasnn da bir anlam olamaz.
const belirleyicisinin kullanm amac ne olabilir diye dnebilirsiniz? Sklkla u merak edilir:
Eer const belirleyicisi koruma amal olarak kullanlyorsa kim kime kar korunuyor? const
belirleyicisinin iki yararl ilevi vardr.:
Okunabilirlii artrr. nk program inceleyen bir kii const belirleyicisine sahip deikenin
deerinin bir daha deitirilemeyeceini dnerek daha fazla bilgi edinir.
Yanllkla nesnenin deerinin deitirilmesi engellenir.
const belirleyicisi deeri hi deimeyecek sabitler iin kullanlmaldr. const bildirimlerinin
nesne yarattna nesnenin yalnzca okunabildiine (read only) dikkat ediniz.
NOT : C++da const belirleyicisi zorunluluk olmadka nesne yaratmaz. (#define nilemci
komutu gibidir, ancak derleme aamasnda ilem grr)
const anahtar szcnn gsterici tanmlamalarnda kullanlmas :
const anahtar szcnn gstericilerle birlikte ayr kullanlma biimi vardr. Kullanlan her
biimde tanmlanan gstericinin zellii deiecektir :
1. const anahtar szcnn gsterici tanmlamasnda ilk szck olarak kullanlmas.
rnekler :
double dizi[20];
int k;
const char *str;
const int *ptr;
const
double
*dptr;
Bu durumda gstericinin gsterdii nesne (yani gsterici iindeki adreste yer alan nesne)
deitirilemez ancak gstericinin kendi deeri deitirilebilir. Bu tr bir tanmlamadan sonra
238
BELRLEYCLER
gstericinin gsterdii yerdeki nesnenin deitirilmeye allmas derleme zaman hatas ile
neticelenecektir:
*str = 'A';
/*
ptr[2] = 25;
/*
*dptr = 4.5;
/*
str = (char *)0x1FFF0;
ptr = &k;
/*
dptr = dizi;
/*
error */
error */
error */
/* legal */
legal */
legal */
/*legal */
/*legal */
/*legal */
239
24
const anahtar szcnn bu kullanm biiminde gsterici tanmlanrken ilk deer verilmelidir,
yoksa const anahtar szcnn kullanlmasnn bir anlam kalmaz.
3. const anahtar szcnn hem tanmlama ifadesinden nce hem de gsterici isminden nce
kullanlmas. rnekler :
...
char ch;
int k;
const char *const str = (char *) 0x1AAA;
const char *const ptr = (int *) 0x1FFF;
Bu durumda ne gstericinin ierii deitirilebilir ne de gstericinin gsterdii yerdeki nesne
deitirilebilir. Her iki durum da derleme zamannda error oluumuna yol aacaktr :
str = &ch;
*str = 'A';
ptr = &k;
*ptr = 12;
/*
/*
/*
/*
error
error
error
error
*/
*/
*/
*/
deikenlerinin
volatile belirleyicisi
Derleyiciler optimizasyon amacyla nesneleri geici olarak yazmalarda tutabilir. Yazmalardaki
bu eit geici barnmalar register belirleyicisi kullanlmasa da derleyiciler tarafndan yaplabilir.
rnein:
int kare (int a)
{
int x;
x = a * a;
return x;
Yukardaki fonksiyonda x geici bir deikendir, dolaysyla derleyici x 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 hzlandrmaktadr. Aadaki kodu inceleyiniz:
int a;
int b;
...
a = b;
if (a == b) {
...
}
Bu rnekte doal olarak ilk admda b deikeni a deikenine aktarlmak zere yazmalardan
birine ekilecektir. Ancak derleyici if ierisindeki ifadede a == b karlatrmasn yapmak iin
bellekteki b yerine yazmataki byi kullanabilir. Verdiimiz iki rnekte de derleyici birtakm
optimizasyonlarla program ilevi deimeyecek biimde daha hzl alr hale getirmek
istemitir. Ancak kimi uygulamalarda derleyicinin bu biimde davranmas hatalara neden
olabilmektedir. kinci rnekte :
240
BELRLEYCLER
a = b;
/* Bir kesme gelerek byi deitirebilir! */
if (a == b) {
...
}
Bir donanm kesmesi (rnein 8h gibi) byi deitiriyorsa, bu durum if deyimi tarafndan
farkedilmeyebilir. te bu tr durumlarda deikenlerin optimizasyon amacyla geici olarak
yazmalarda tutulmas arzu edilmeyen sonularn olumasna yol aabilmektedir. volatile
Deikenleri optimizasyon 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 olabilmektedir. Bu belirleyicinin bilinsizce kullanlmasnn
performans kt ynde etkileyebileceini unutmaynz.
Belirleyicilerin kullanllarn gsteren bir rnek :
#include <stdio.h>
int a;
extern int b;
static int c;
void func(int d, register int e)
{
auto int g;
int h;
static int i;
extern int j;
register int k;
}
yukardaki programda tanmlanan deikenlerin faaliyet alan, mr ve balant asndan
zellikleri aadaki tabloda belirtilmektedir :
(isim)
name
(mr)
storage duration
a
b
statik (static)
statik (static)
(faaliyet
alan)
scope
dosya (file)
dosya (file)
c
d
e
g
h
i
j
statik (static)
otomatik (automatic)
otomatik (automatic)
otomatik (automatic)
otomatik (automatic)
statik (static)
statik (static)
dosya (file)
blok (block)
blok (block)
blok (block)
blok (block)
blok (block)
blok (block)
(balant)
linkage
d (external)
d (external)
*
d (external)
yok (none)
yok (none)
yok (none)
yok (none)
yok (none)
d (external)
*
241
24
k
yok (none)
global
deiken
yerel
deiken
parametre deikeni
242
YAPILAR
25 . BLM : YAPILAR
Yaplar (structures) da diziler gibi birden fazla nesneyi ilerinde tutabilen bir veri trrdr.
Yaplarn da elemanlar bellekte ardl (contigious) bir biimde bulunur. Fakat yaplarn
dizilerden temel fark udur: Diziler ayn trden nesneleri iinde tutabilirken, yaplar farkl
trlerden nesneleri tutabilirler. Yaplarn kullanlmasnn ana nedeni budur. ou zaman, trleri
farkl bir takm nesneler, mantksal olarak bir btn oluturabilirler. sim, ya, departman,
cret, renim durumu gibi bilgileri farkl trden nesneler iinde saklayabiliriz ve bunlarn
tamam alan bir personele ait bilgiler olabilir. Bu gibi ayn konu ile ilgili farkl trden veriler
yaplar iinde saklanr.
25
struct POINT p1, p1; /* p1 ve p2 POINT yaps trnden nesnelerdir. */
struct SAMPLE sample;
/* sample SAMPLE yap trnden bir nesnedir. */
Yap deikenleri bileik nesnelerdir. Yani paralardan oluurlar. Zaten yap bildirimlerinin
yaplmasnn amac da bu paralarn isimleri ve trleri hakknda derleyiciye bilgi vermektir. Bir
yap bildirimini gren derleyici, daha sonra bildirimi yaplan yap trnden bir deiken
tanmlanmas durumunda, bu deiken iin bellekte ne kadar yer ayracan, ve ayrd yeri
ne ekilde organize edeceini bilir.
Bir yap deikeni (nesnesi) iin, yap bildiriminde belirtilen elemanlarn toplam uzunluu kadar
(byte olarak) yer ayrlr.
struct SAMPLE {
int a;
long b;
char ch;
};
void main()
{
struct SAMPLE x;
}
printf("%d\n", sizeof(x));
244
YAPILAR
rnek:
struct SAMPLE {
int a;
long b;
char c;
};
int main()
{
struct SAMPLE x;
x.a = 10;
x.b = 200000;
x.c = 'M';
printf("x.a = %d\nx.b = %ld\nx.c = %c\n", x.a, x.b, x.c);
return 0;
Yukardaki rnekte grld gibi x.a, x.b ve x.c yap elemanlar ayr birer nesne zellii
gsterirler. Bu elemanlara ayr ayr ulaabilir ve ayr ayr atamalar yapabiliriz. Bu nesneleri ++
ve -- operatrlerine ya da & operatrne operand yapabiliriz.
25
long b;
char c;
};
int main()
{
struct SAMPLE x;
}
printf("x.a adresi = %p\nx.b adresi = %p\n x.c adresi = %p\n", &x.a, &x.b, &x.c);
Dizilerde olduu gibi, yaplarda da yap elemanlarndan daha fazla sayda elemana ilk deer
vermek derleme zamannda hata oluumuna neden olacaktr.
x.name = "Necati";
x.no = 125;
printf("%s %d\n", x.name, x.no);
return 0;
Yukardaki rnekte yap elemanlarna ilk deer verme sentaksyla da (initialization) deer
atanabilirdi:
....
struct PERSON x = {"Necati", 125};
...
246
YAPILAR
247
25
rnek:
struct POINT_1 *p = &a;
YAPILAR
printf("%s %d\n", (*p).name, (*p).no);
}
int main()
{
struct PERSON x = {"Necati Ergin", 156};
disp(&x);
}
Ok Operatr
OK operatr - ve > karakterlerinin yanyana getirilmesiyle oluturulur. ki operand alan araek
konumunda bir operatrdr. (Binary infix ) Ok operatr ncelik tablosunun en yksek ncelik
seviyesindedir. -> operatrnn sol tarafndaki operand yap trnden bir adres olmaldr. ->
operatrnn sa tarafndaki operand ise ilgili yapnn bir eleman olmaldr. Sol tarfndaki
operand ile belirtilen yapnn (o adresteki yapnn) sa tarafnda belirtilen elemanna ulamak
iin kullanlr.
p, yap trnden bir nesnenin adresini tutuyor olsun. Aadaki iki ifade edeerdir.
(*)p.a
p->a
Yani nokta ve ok operatrlerinin her ikisi de elemana erimek iin kullanlr. Ancak nokta
operatr yap deikeninin kendisiyle ok operatr ise adresiyle eriim salar. Okunabilirlik
asndan ok operatrnn solunda ve sanda boluk braklmamasn tavsiye ediyoruz.
&p->a ifadesiyle p'nin gsterdii yapnn a elemannn adresi alnr. (Ok operatr adres
operatrne gre daha nceliklidir.)
249
25
rnek:
struct POINT {
int x, y;
};
struct POINT make_point(int x, int y);
int main()
{
struct POINT a;
a = make_point(3, 5);
...
return 0;
250
YAPILAR
a.x = 10;
b.x = 20;
p = dump_point(&a);
return 0;
"heap"
bellek
alanna
iade
edilmesi,
fonksiyonu
arann
251
25
Yap nesnelerinin hemen yap bildiriminden sonra tanmlanmas durumunda yap ismi kullanma
zorunluluu da bulunmamaktadr. 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;
eklinde yaplsa bile artk derleyici, eleman yaps ve elemanlarn trleri ayn olsa bile bu yapy
ayr bir yap tr olarak ele alacaktr. Dolaysyla
cdate = bdate;
gibi bir atama yap trlerinin farkl olmas nedeniyle geerli deildir.
Byle bir tanmlamann baka bir dezavantaj da bu yap tryle ilgili bir fonksiyon
yazlamaydr. nk yap trnn bir ismi yoktur, ve bir fonksiyonun parametre deikeni
tr bilgisi olmadan tanmlanamaz.
employee.birthdate.day = 10;
employee.birthdate.month = 12;
employee.birthdate.year = 2000;
strcpy(employee.name, "Necati Ergin");
employee.no = 1472;
printf("%d
%d
%d
%s
%d\n",
employee.birthdate.day,
employee.birthdate.month,
employee.birthdate.year, employee.name, employee.no);
return 0;
252
YAPILAR
2. Bu yntemde eleman olan yap deiken tanmlamas ile birlikte elemana sahip yapnn
ierisinde bildirilir.
rnek:
struct PERSON {
char name[30];
struct DATE {
int day, month, year;
} birthdate;
int no;
};
Burada ite bildirilen yap da sanki darda bildirilmi gibi ilem grr. yani ieride bildirilen
yap trnden deikenler tanmlanabilir. Burada dikkat edilmesi gereken bir noktada iie yap
bildiriminin yaplmasna ramen bir deiken tanmlamasnn yaplmam olmasdr. Yani
birthdate bir nesne deildir. Ancak struct PERSON trnden bir deiken tanmlandnda, bu
yap deikeninin bir alt eleman olacaktr:
struct PERSON X;
X.birthdate.day = 20;
253
25
Yap Dizileri
Yaplar da bir tr belirttiine gre yap trnden de diziler sz konusu olabilir. Yap dizilerine de
normal dizilere ilk deer verilmesine benzer ekilde ilk deer verilebilir. lk deer verme
srasnda kullanlan, iteki kme parantezleri okunabilirlii artrr. rnek:
struct DATE {
int day, month, year;
};
int main()
{
struct DATE birthday[5] = {{10, 10, 1958}, {04, 03, 1964},
{21, 6.1967}, {22. 8, 1956},
{11, 3, 1970}};
struct DATE *pdate;
int i;
pdate = birthdate;
for (i = 0; i < 5; ++i) {
printf("%02d / %02d / %04d\n", pdate->day, pdate->month, pdate->year);
++pdate;
}
254
YAPILAR
return 0;
255
25
free(person->bdate);
free(person);
Bir yapnn eleman kendi trnden bir yap deikeni olamaz. rnein:
struct SAMPLE {
struct SAMPLE a;
};
/* hata */
nk burada SAMPLE yapsnn uzunluu belirlenemez. Ancak bir yapnn eleman kendi
trnden bir gsterici olabilir. rnein:
struct LLIST {
int val;
struct LLIST *next;
};
Bu tr yaplar zellikle bal liste ve aa yaplarn (algoritmalarn) gerekletirmek amacyla
kullanlabilir. (Bu konu detayl olarak bal listeler dersinde ele alnacaktr.
256
Uygulama
#include <conio.h>
#include <time.h>
257
26
void showtime(void);
void delay(unsigned long n);
double keeptime(void);
double chrono(void);
int main()
{
int i = 10;
clrscr();
chrono();
while (i-- > 0) {
delay(3000000ul);
printf("%lf\n", chrono());
}
return 0;
void showtime(void)
{
time_t timer;
struct tm *tptr;
double keeptime(void)
{
static int flag = 0;
static clock_t start, end;
if (!flag) {
start = clock();
flag = 1;
return -1.;
}
end = clock();
flag = 0;
return (end - start) / CLK_TCK;
}
double chrono(void)
{
static int flag = 0;
static clock_t start, end;
if (flag == 0) {
start = clock();
flag = 1;
return -1.;
}
end = clock();
return (end - start) / CLK_TCK;
}
258
Uygulama
Tarihler ile ilgili lem Yapan fonksiyonlar.
/* INCLUDE FILES */
#include
#include
#include
#include
<stdio.h>
<stdlib.h>
<conio.h>
<time.h>
/* symbolic constants */
#define VALID
#define INVALID
1
0
#define FALSE
#define TRUE
0
1
#define
#define
#define
#define
#define
#define
#define
SUN
MON
TUE
WED
THU
FRI
SAT
0
1
2
3
4
5
6
/* type definitions */
typedef int BOOL;
typedef int DAYS;
typedef struct DATE {
int day, month, year;
}DATE;
/* function prototypes */
void setDate(int day, int month, int year, DATE *date);
void displayDate(const DATE *date);
void displayDate2(const DATE *date);
long totaldays(const DATE *date);
int dayofyear(const DATE *date);
int Datecmp(const DATE *date1, const DATE *date2);
int datedif(const DATE *date1, const DATE *date2);
BOOL isleap(int year);
BOOL validDate(const DATE *date);
BOOL isweekend(const DATE *date);
DAYS Dateday(const DATE *date);
DATE
DATE
DATE
DATE
26
/* global variables */
char *days[]
260
yap
nesnesindeki
tarihin
ilgili
yln
kanc
gn
switch (date->month
case 11: result
case 10: result
case 9: result
case 8: result
case 7: result
case 6: result
case 5: result
case 4: result
case 3: result
case 2: result
case 1: result
}
return result;
- 1) {
+= 30;
+= 31;
+= 30;
+= 31;
+= 31;
+= 30;
+= 31;
+= 30;
+= 31;
+= 28 + isleap(date->year);
+= 31;
/* Adresleri gnderilen
farkn bulur. */
yap
nesnelerinde
saklanan
tarihler
arasndaki
gn
26
}
result.month = i + 1;
result.day = totaldays;
return result;
}
/* Adresi gnderilen yap nesnesindeki tarihten n gn sonraki ya da nceki
tarihin ne oldugunu hesaplayarak bu tarihe geri dner. */
DATE nDate(const DATE *date, int n)
{
return totaltoDate(totaldays(date) + n);
}
/*
*/
}
/* 01.01. 1900 ve 31.12.2000 tarihleri arasnda rasgele bir tarih retir. */
DATE randomDate()
{
int months[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
DATE random;
Uygulama
Tekli bal liste oluturulmasna ilikin bir program.
#include
#include
#include
#include
#define
#define
#define
#define
#define
#define
<stdio.h>
<conio.h>
<stdlib.h>
<string.h>
ADD_BEGIN
ADD_END
DELETE_NAME
DELETE_NO
DISPLAY
EXIT_PROG
1
2
5
3
4
6
26
case DELETE_NAME : delete_name(); break;
case DELETE_NO : delete_no(); break;
case DISPLAY
: display_list(); break;
case EXIT_PROG
: goto EXIT;
default
: printf("geersiz seenek!..\n");
}
}
EXIT:
exit(EXIT_SUCCESS);
return 0;
}
/************************************************/
int get_option(void)
{
int option;
/************************************************/
void add_begin(void)
{
PERSON *new;
new = (PERSON *)malloc (sizeof(PERSON));
if (new == NULL) {
printf("cannot allocate memory!..\n");
exit(EXIT_FAILURE);
}
fflush(stdin);
printf("ismi giriniz : ");
gets((char *)new);
printf("No'yu giriniz : ");
scanf("%d", &new->no);
new->next = start;
start = new;
}
/************************************************/
void add_end(void)
{
PERSON *new, *cur;
new = (PERSON *)malloc(sizeof(PERSON));
if (new == NULL) {
printf("cannot allocate memory!..\n");
exit(EXIT_FAILURE);
}
fflush(stdin);
printf("ismi giriniz : ");
gets((char *)new);
printf("No'yu giriniz : ");
scanf("%d", &new->no);
if (start == NULL) {
start = new;
new->next = NULL;
264
for (prev = NULL, cur = start; cur != NULL && strcmp(cur->name, nametemp);
prev = cur, cur = cur->next)
;
if (cur == NULL) {
printf("silinecek kay t bulunamad \n");
return;
}
if (prev == NULL)
start = start->next;
else
prev->next = cur->next;
free(cur);
printf("kayt silindi!\n");
/************************************************/
void delete_no(void)
{
PERSON *cur, *prev;
int no;
printf("silinecek No'yu girin : ");
scanf("%d", &no);
for (prev = NULL, cur = start; cur != NULL && cur->no != no;
prev = cur, cur = cur->next)
;
if (cur == NULL) {
printf("kayt bulunamad\n");
return;
}
if (prev == NULL)
start = start->next;
else
prev->next = cur->next;
free(cur);
265
26
printf("kayt silindi!..\n");
}
Uygulama
Sral bal liste oluturulmasna ilikin bir program.
#include
#include
#include
#include
<stdio.h>
<conio.h>
<stdlib.h>
<string.h>
266
26
prev->next = cur->next;
printf("%s was deleted\n", name);
free(cur);
/************************************************/
void fill(void)
{
int i;
PERSON *_new, *prev, *cur;
PERSON a[7] = {{"ali",
-3, NULL}, {"erdem",
7, NULL},
{"kaan",
-1,
NULL}, {"necati", 5, NULL},
{"gurbuz", 9, NULL}, {"damla",
20, NULL},
{"metin", 15, NULL}
};
for (i = 0; i < 7; i++) {
if ((_new = (PERSON *) malloc(sizeof(PERSON))) == NULL) {
printf("not enough memory");
exit(EXIT_FAILURE);
}
*_new = a[i];
for (prev = NULL, cur = start;
cur != NULL && strcmp(_new->name, cur->name) > 0;
prev = cur, cur = cur->next)
;
if (cur != NULL && !strcmp(_new->name, cur->name)) {
printf("name already exists\n");
return;
}
_new->next = cur;
if (prev == NULL)
start = _new;
else
prev->next = _new;
}
}
/************************************************/
void search(void)
{
char name[50];
PERSON *p;
fflush(stdin);
printf("name: ");
gets(name);
if ((p = find_name(name)) == NULL)
printf("could not find\n");
else
printf("name: %-20s number: %d\n", p->name, p->no);
}
/************************************************/
void del_list(void)
{
PERSON *cur = start, *prev;
while (cur != NULL) {
prev = cur;
cur = cur->next;
268
free(prev);
}
start = NULL;
/************************************************/
PERSON *find_name(char *name)
{
PERSON *p;
for (p = start; p != NULL && strcmp(name, p->name) > 0; p = p->next)
;
if (p != NULL && !strcmp(name, p->name))
return p;
return NULL;
}
269
27
aadaki
kural
sentaks
asndan
hata
yaplmasn
typedef anahtar szc, her tr bildirimin nne gelir. typedef anahtar szc bir
bildirimin nne geldiinde typedef kullanlmam olsayd nesne olacak isimler, typedef
anahtar szc eklendiinde artk tr ismi olurlar. rnekler:
char * pstr;
bildirimi ile pstr char trden bir gsteri olur.
typedef char *pstr;
bir tr tanmlamasdr ve artk pstr bir tr olarak ele alnr. pstr char trden bir adres trnn
baka bir ismi olarak, geerli bir trdr.
Yani yukardaki tr tanmlamasndan sonra
pstr p;
270
271
27
ile
char *s[10];
tamamen ayn anlama gelecektir.
Bir tr ismi baka tr isimlerinin tanmlanmasnda da kullanlabilir.
typedef unsigned int WORD;
typedef WORD UINT;
Tr isimleri geleneksel olarak byk harfle yazlr ama bu C sentaks asndan bir zorunluluk
deildir.
27
olduklarn daha iyi anlayabiliriz. size_t tr ismi ile dinamik bellek fonksiyonlar ile alrken
karlamtk. Bu tr isminin bildirimi stdlib.h, alloc.h de dier baz balk dosyalar iinde
aadaki ekilde yaplmtr.
typedef unsigned size_t;
Bu tr aslnda gerekte ne olduu derleyicileri yazanlara braklm olan bir trdr. size_t tr
sizeof operatrnn rettii deerin trdr. ANSI standartlarnda bir ok fonksiyonun
parametrik yaps ierisinde size_t tr geer. rnein malloc fonksiyonunun gerek prototipi
alloc.h, mem.h balk dosyalarnn iinde
void *malloc (size_t size);
biiminde yazlmtr.
Yani malloc fonksiyonunun parametresi size_t trdendir ama bu trn gerekte ne olduu
derleyicileri yazanlara braklmtr. Ancak hemen hemen btn derleyicilerde size_t unsigned
int olarak belirlenmitir.
size_t tr gibi aslnda ne olduklar derleyiciye braklm olan (yani derleyici yazanlarn
typedef bildirimlerini yapacaklar) baka tr isimleri de C standartlar tarafndan
tanmlanmtr.
size_t
(sizeof operatrnn rettii deerin tr.) Derleyiciyi yazanlar unsigned int ya da
unsigned long trne typedef ederler. (Bir zorunluluk olmasa da derleyicilerin hemen hemen
hepsinde unsigned int tr olarak tanmlanmtr.)
time_t
(time fonksiyonunun geri dn deerinin tr, derleyiciyi yazanlar herhangi bir
scalar (birleik olmayan) default veri trne typedef edebilirler. (Bir zorunluluk olmasa da
derleyicilerin hemen hemen hepsinde long tr olarak tanmlanmtr.)
clock_t (clock fonksiyonunun geri dn deerinin tr, derleyiciyi yazanlar herhangi bir skalar
(bileik olmayan) default veri trne typedef edebilirler. (Bir zorunluluk olmas da
derleyicilerin hemen hemen hepsinde long tr olarak tanmlanmtr.)
ptrdiff_t (gsterici deerlerine ilikin fark deeri tr, (Bir zorunluluk olmas da derleyicilerin
hemen hemen hepsinde int tr olarak tanmlanmtr.)
/* hata */
Yukardaki programda
WORD x;
274
275
27
Bir C programnda deerleri 0 ile 50000 arasnda deiebilecek olan saya deikenler
kullanacamz dnelim. Bu ama iin long int trn seebiliriz, nk long int tr
bilindii gibi 2.147.483.647 ye kadar deerleri tutabilir. Ama long tr yerine int trn
kullanmak, aritmetik ilemlerin daha hzl yaplabilmesi asndan tercih edilecektir. Ayrca
int trden olan deikenler bellekte daha az yer kaplayabilecektir.
int trn kullanmak yerine bu ama iin kendi tr tanmlamamz yapabiliriz :
typedef int SAYAC;
SAYAC a, b, c;
Kaynak kodun int trnn 16 bit uzunluunda olduu bir sistemde derlenmesi durumunda
tr tanmlama ifadesini deitirebiliriz:
typedef long SAYAC;
Bu teknikle tanabilirlie ilikin btn problemlerimizin zlm olacan dnmemeliyiz.
rnein SAYAC trnden bir deiken printf ya da scanf fonksiyonu armlarnda arguman
olarak kullanlm olabilir :
typedef int SAYAC;
...
SAYAC a, b, c;
...
scanf("%d%d%d", &a, &b. &c);
...
printf("%d %d %d", a, b, c);
Yukardaki ifadelerde a. b. c deikenleri SAYAC trnden (int trden) tanmlanmlardr.
printf ve scanf fonksiyonlarnn arma ifadelerinde de bu deikenlere ilikin format
karakterleri doal olarak %d seilmitir. Ancak SAYAC trnn long tr olarak
deitirilmesi durumunda printf ve scanf fonkksiyonlarnda bu trden deikenlerin
yazdrlmasnda kullanlan format karakterlerinin de %d yerine %ld olarak deitirilmesi
gerekecektir.
0
1
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 kullanlmaktadr. Win16 sistemlerinde uzak ve yakn gsterici kavramlar vard.
Dolaysyla o zamanlar, P n ekli 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, Win16daki alkanlkla hala LP nekli typedef isimleri kullanlmaktadr. Windows.h
ierisinde her ihtimale kar (Win16 programlar alabilsin diye) near ve far szckleri
aadaki gibi silinmitir.
#define far
#define near
typedef char near *PSTR;
typedef char far *LPSTR;
277
27
PSTR ya da LPSTR Win32 sistemlerinde tamamen ayn anlama gelir ve char trden adres
trn belirtir.
typedef char *PSTR;
typedef char *LPSTR;
Gstericilerde constluk P ya da LPden 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;
Cnin doal trlerinin hepsinin byk harf normal, adres ve const adres versiyonlar vardr.
typedef long
LONG;
typedef int INT;
typedef char CHAR;
Windows programlamada H ile balayan, handle olarak kullanlan pek ok typede ismi vardr.
Bu typedef isimlerinin hepsi void * trndendir. rnein:
typedef void
typedef void
*HWND;
*HICON;
278
BRLKLER
28 . BLM : BRLKLER
Programc tarafndan tanmlanan (user defined) ve bileik bir veri yaps olan birlikler yaplara
ok benzer. Birliklerin de 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.
Birlik bildirimlerinin genel ekli yledir:
union [birlik ismi] {
tr <birlik eleman>;
tr <birlik eleman>;
tr <birlik eleman>;
...
};
rnein;
union DWORD {
unsigned char byte;
unsigned int word;
unsigned long dword;
};
Dier bir rnek:
union DBL_FORM {
double n;
unsigned char s[8];
};
279
28
union DWORD *p;
...
printf("%d", p->word);
p->word ifadesi ile p adresinde birlik nesnesinin word elemanna eriilmektedir.
Genel olarak unlar syleyebiliriz: Yaplarla birliklerin bildirilmesi, tanmlanmas ve yap
deikenlerinin kullanlmas tamamen ayn biimde yaplmaktadr. kisi arasnda tek fark yap
ve birlik elemanlarnn bellekteki organizasyonunda ortaya kar. Birlik elemanlarnn bellekteki
organizasyonu konusuna deinmeden nce bir
bytedan daha uzun bilgilerin bellekteki
grnmleri zerinde duralm.
1AOO
1A01
...
34
12
...
dk anlaml byte
yksek anlaml byte
ekilden de grld gibi x deikenini oluturan saylar dk anlaml byte deeri (34H)
dk anlaml bellek adresinde (1A00H) olacak biimde yerletirilmitir. imdi aadaki kodu
inceleyiniz :
...
unsigned long a = 0x12345678;
unsigned int *b;
b = (unsigned int*) &a;
printf(%x\n, *b);
ile eklrana hex sistemde 5678 saylar baslr. Aadaki ekli inceleyiniz. b deikeninin 1B10
adresinden balayarak yerletirildii varsaylmtr :
...
1B10
1B11
1B12
1B13
78
56
34
12
1B10 *b
...
280
BRLKLER
unsigned long a = 0x12345678;
unsigned int *b;
b = (unsigned int*) &a;
printf(%x\n, *b);
ekrana 1234 baslrd.
...
1B10
1B11
1B12
1B13
12
34
56
78
1B10 *b
...
Aadaki kod kullanlan sistemin little endian ya da big endian oldugunu test etmektedir :
int x = 1;
if (*(char *)&x == 1)
printf("little-endian\n");
else
printf("big-endian\n");
a.word
a.dword
union DBL_FORM {
double n;
unsigned char s[8];
};
...
union DBL_FORM x;
tanmlamas ile x deikeni iin ne kadar yer ayrlacaktr? DBL_FORM birliinin iki eleman
vardr. Birincisi 8 byte uzunluunda bir karakter dizisi, ikincisi de 8 byte uzunluunda double
281
28
trden bir deikendir. ki uzunluk da ayn olduguna gre x iin 8 byte yer ayrlacan
syleyebiliriz:
...
s[0] x.n
s[1]
s[2]
s[3]
s[4]
s[5]
s[6]
s[7]
...
282
BRLKLER
28
struct {
char desen[20];
int renk;
int size;
} tshort;
struct {
char isim[20];
int model;
} saat;
} cins;
};
Birlik kulanmnn ikinci nedeni herhangi bir veri trnn paralar zerinde ilem yapmak ya da
paralar zerinde ilem yaparak bir veri trnnden btnn oluturmaktr. Bunun iin int
trden bir saynn byte deerlerini ayrtrma rneini yineleyebiliriz :
struct WORD {
unsigned char low_byte;
unsigned char high_byte;
};
union WORD_FORM {
unsigned int x;
struct WORD y;
};
union word_form wf;
Tanmlamalarndan sonra wf.x elemanna deer atadmzda wf.y.low_byte ve wf.y.high_byte
ile yksek ve alak anlaml byte deerleri zerine kolaylkla ilem yapabiliriz.
284
BRLKLER
main()
{
union DEGER s[100];
s[0].i = 3;
s[1].d = 6.
s[2].l = 12L
...
}
Hangi trden bir deer tutmak istiyorsak, bu deeri s dizisinin eleman olan bir union DEGER
nesnesinin ilgili alt elemannda tutuyoruz. Ancak hala yle bir eksiimiz var : rnein dizinin
17. elemann gerek tryle ve deeriyle kullanmak istiyoruz. 17. eleman nesnesininin hangi
trden olduunu nereden bileceiz? Hangi dizi elemannn hangi trden deer iin kullanld
bilgisini de bir ekilde saklamalyz.
Bunun iin en iyi yntem bir yap bildirimi yapmak, ve DEGER birliini de bu yapnn alt eleman
olarak bildirmektir. Yapnn baska bir eleman da birliin hangi elemannn kullanlacag bilgisini
tutacaktr :
#define INT
0
#define LONG
1
#define DOUBLE 2
...
struct KARTIP {
char type;
union DEGER deger;
};
imdi struct KARTIP trnden bir dizi tanmlayabiliriz:
...
struct KARTIP s[100];
...
s[0].type = INT;
S[0].deger.i = 3;
s[1].type = DOUBLE;
s[1].deger.d = 6.;
s[2].type = LONG;
s[2].deger.d = 12L;
285
29
~
<<
>>
&
^
|
<<=
>>=
&=
^=
|=
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 bitwise
compound
operatrleri
operators
assignment
Yukardaki operatrler iinde yalnzca bitsel Deil (bitwise not) operatr nek konumunda tek
operand alan (unary prefix) bir operatrdr. Dier btn bitsel operatrler iki operand alrlar
ve operandlarnn arasnda bulunurlar. (binary infix)
imdi bu operatrleri tek tek tanyalm :
*/
y = ~x;
/* y = 1110 0101 0011 1100 */
printf("y = %x\n", y);
/* y = 0xE53C */
return 0;
286
BTSEL OPERATRLER
Bitsel sola kaydrma operatrnn rettii deer soldaki operand olan tamsaynn sadaki
operand olan tamsay kadar sola kaydrlm biimidir. Menzil 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;
z = x << y;
printf("z = %d\n", z)
return 0;
*/
}
Bir sayy sola bitsel olarak 1 kaydrmakla o saynn ikiyle arplm deeri elde edilir. Bir sayy
saa bitsel olarak 1 kaydrmakla o saynn ikiye blnm deeri elde edilir.
Bitsel kaydrma operatrlerinin yan etkileri yoktur. Yani soldaki operandlar bir nesne ise, bu
nesnenin bellekteki deerini deitirmezler. Kaydrma sonucu soldaki nesnenin deeri
deitirilmek isteniyorsa daha sonra inceleyeceimiz bitsel ilemli atama operatrleri
kullanlmaldr. (>>= ya da <<=)
Bitsel saa kaydrma operatrnn rettii deer soldaki operand olan tamsaynn sadaki
operand olan tamsay kadar saa kaydrlm biimidir. Soldaki operand iaretsiz (unsigned)
ya da pozitif iaretli (signed) bir tamsay ise menzil dna kan bitler yerine saynn solundan
besleme 0 biti ile yaplmas C standartlar tarafndan garanti altna alnmtr. Saa kaydrlacak
ifadenin negatif deerli, iaretli bir tamsay trnden olmas durumunda menzil dna kan
bitler iin soldan yaplacak beslemenin 0 ya da 1 bitleriyle yaplmas uygulama bamldr.
(implementation depended). Yani derleyiciyi yazanlar bu durumda saynn iaretini korumak
iin soldan yaplacak beslemeyi 1 biti ile yapabilecekleri gibi, saynn iaretini korumay
dnmeksizin 0 biti ile de yapabilirler. aretli negatif bir tamsaynn bitsel saa kaydrlmas
tanabilir bir zellik olmadndan dikkatli olunmaldr.
#include <stdio.h>
int main()
{
unsigned int x = 52;
unsigned int y = 2;
z = x >> y;
printf("z = %dn", z)
return 0;
deer
operandlarnn
287
karlkl
bitlerinin
ve
ilemine
29
#include <stdio.h>
int main()
{
unsigned int x = 0x1BC5;
unsigned int y = 0X3A0D
unsigned int z;
z = x & y;
/* z = 0x1A05 */
y
1
0
1
0
x^y
0
1
1
0
Yukardaki tablo yle zetlenebilir. Operandlardan ikisi de ayn deere sahip ise retilen deer
0 olacak, operandlardan biri dierinden farkl ise retilen deer 1 olacaktr.
#include <stdio.h>
int main()
{
unsigned int x = 0x1BC5;
unsigned int y = 0X3A0D
unsigned int z;
z = x ^ y;
printf("z = %xn", z);
return 0;
}
Bir sayya arka arka arkaya ayn deerle zel veya ilemi yaplrsa ayn deer elde edilir:
#include <stdio.h>
int main()
{
unsigned int x = 0x1BC5;
/* x = 0001 1011 1100 0101 */
unsigned int y = 0X3A0D
/* y = 0011 1010 0000 1101 */
x = x ^ y;
/* x = 0010 0001 1100 1000 x = 0x21C8 */
x = x ^ y;
/* x = 0001 1011 1100 0101 x = 0x1BC5 */
printf("x = %xn", x);
/* x = 0x0x1BC5 */
return 0;
}
288
BTSEL OPERATRLER
y
1
0
1
0
x|y
1
1
1
0
Bitsel veya operatrnn rettii deer operandlarnn karlkl bitlerinin veya ilemine
sokularak elde edilen deerdir.
#include <stdio.h>
int main()
{
unsigned int x = 0x1BC5;
unsigned int y = 0X3A0D
unsigned int z;
z = x | y;
/* z = 0x3BCD */
289
29
x
x
x
x
x
=
=
=
=
=
x
x
x
x
x
<< y yerine
>> y yerine
&y
yerine
^y
yerine
| yyerine
x <<= y
x >>= y
x &= y
x ^= y
x |= y
kullanlabilir.
Bir Saynn Belirli Bir Bitinin 1 Yaplmas (birlenmesi ) (set a bit / turn a bit
on)
Buna saynn belirli bir bitinin set edilmesi de denebilir. Bir saynn belirli bir bitini set etmek
iin, sz konusu say, ilgili biti 1 olan ve dier bitleri 0 olan bir sayyla veya ilemine tabi
tutulmaldr. nk bitsel veya ileminde 1 yutan eleman 0 ise etkisiz elemandr.
Aadaki rnekte bir saynn 5. biti set edilmektedir.
#include <stdio.h>
#include <conio.h>
int main()
{
int ch = 0x0041;
int mask = 0x0020;
/* ch = 65
/* mask = 32
ch |= mask;
/* ch =
0000 0000 0110 0001
printf("ch = %d\n", ch); /* ch = 97 */
getch();
return 0;
*/
*/
*/
x bir tamsay olmak zere, bir saynn herhangi bir bitini set edecek bir ifadeyi u ekilde
yazabiliriz:
x |=1 << k
Bir Saynn Belirli Bir Bitinin 0 Yaplmas (sfrlanmas) (clear a bit / turn the
bit off)
Buna saynn belirli bir bitinin temizlenmesi de denebilir. Bir saynn belirli bir bitini sfrlamak
iin, sz konusu say, ilgili biti 0 olan ve dier bitleri 1 olan bir sayyla bitsel ve ilemine tabi
tutulmaldr. nk bitsel ve ileminde 0 yutan eleman 1 ise etkisiz elemandr. Bir bitin
sfrlanmas iin kullanlacak bu sayya maske (mask) denir.
Aadaki rnekte bir saynn 5. biti sfrlanmaktadr.
#include <stdio.h>
#include <conio.h>
int main()
{
int ch = 0x0061;
/* ch = 97
0000 0000 0110 0001 */
int mask = ~0x0020;
/* mask = ~32
1111 1111 1101 1111 */
ch &= mask;
/* ch
0000 0000 0100 0001 */
printf("ch = %dn", ch);
/* ch = 65 */
getch();
290
BTSEL OPERATRLER
return 0;
x bir tamsay olmak zere, bir saynn herhangi bir bitini set edecek bir ifadeyi u ekilde
yazabiliriz
x &= ~(1 << k);
x &= 0xFC7F;
Bu gibi tamsaylarn bitleri zerinde yaplan ileri fonksiyonlara yaptrmaya ne dersiniz?
void clearbits(int *ptr, int startbit, int endbit);
clearbits fonksiyonu adresi gnderilen ifadenin
startbit ve endbit aralndaki bitlerini
sfrlayacaktr.
rnein x isimli int trden bir nesnenin 7. 8. 9. bitlerini sfrlamak iin fonksiyon aadaki
ekilde arlacaktr:
clearbits(&x, 7, 9);
void clearbits(int *ptr, int startbit, int endbit)
{
int k;
291
29
Peki rnein 16 bitlik bir alann iindeki belirli bitleri birden fazla deeri tutacak ekilde
kullanabilir miyiz?
rnein 4 bitlik bir alan ierinde (negatif saylar kullanmadmz dnrsek 0 15
aralndaki deerleri tutabiliriz. O zaman yalnzca bu aralktaki deerleri kullanmak istiyorsak
ve bellek (ya da dosya) bykl asndan kstlamalar sz konusu ise 16 bitlik bir alan
iinde aslnda biz 4 ayr deer tutabiliriz deil mi?
Bir saynn belirli bir bit alannda bir tamsay deerini tutmak iin ne yapabiliriz? nce saynn
ilgili bitlerini sfrlar (rnein yukarda yazdmz clearbits fonksiyonuyla) daha sonra sayy,
sfrlanm bitleri yerletireceimiz saynn bit paternine eit dier bitleri 0 olan bir say ile bitsel
veya ilemine tabi tutarz, deil mi? Aadaki fonksiyon prototip bildirimine bakalm:
void putvalue(int *ptr, int startbit, int endbit, int value);
putvlaue fonksiyonu adresi gnderilen nesnenin startbit endbit deerleri arasndaki bitlerine
value saysn yerletirecektir. Fonksiyon aadaki gibi arlabilir :
putvalue(&x,
putvalue(&x,
putvalue(&x,
putvalue(&x,
0, 3, 8);
4, 7, 12);
8, 11, 5);
12, 15, 3);
Peki yukardaki fonksiyonlar ile rnein 16 bitlik bir saynn belirli bit alanlar iinde saklanm
deerleri nasl okuyacaz. Bu ii de bir fonksiyona yaptralm :
int getvalue(int x, int startbit, int endbit);
getvalue fonksiyonu startbit ve endbit ile belirlenen bit alanna yerletirilmi deer ile geri
dnecektir.
int getvalue(int number, int startbit, int endbit)
{
int temp = number >>= startbit;
292
BTSEL OPERATRLER
Uygulama
int trden bir saynn bit bit ekrana yazdrlmas
include <stdio.h>
void showbits(int x)
{
int i = sizeof(int) * 8 - 1;
Uygulama
int trden bir saynn bitlerini ters eviren reverse_bits fonksiyonunun yazlmas:
#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;
Uygulama
int trden bir deerin ka adet bitinin set edilmi olduu bilgisine geri dnen no_of_setbits
fonksiyonunun yazlmas :
#include <stdio.h>
293
29
int main()
{
int number;
294
BT ALANLARI
30 . BLM : BT ALANLARI
konu eklenecek
295
31
296
31
<stdio.h>
<conio.h>
<stdlib.h>
<math.h>
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 '+'
: printf("%d\n", op1 + op2); return 0;
case '-'
: printf("%d\n", op1 - op2); return 0;
case '/'
: printf("%lf\n", (double)op1 / op2); return 0;
case '*'
: printf("%d\n", op1 * op2); return 0;
case '%'
: printf("%lf\n", (double)op1 * op2 / 100); return 0;
case 'k'
: printf("%lf\n", pow(op1, op2)); return 0;
default
: printf("hatal operatr\n");
}
return 0;
298
DOSYALAR
32 . BLM : DOSYALAR
kincil bellekte tanmlanm blgelere dosya denir. Her dosyann bir ismi vardr. Ancak
dosyalarn isimlendirme kurallar sistemden sisteme gre deiebilmektedir. Dosya ilemleri
tamamen iletim sisteminin kontrol altndadr.
letim sistemi de ayr ayr yazlm fonksiyonlarn birbirlerini armas biiminde alr.
rnein komut satrnda ismi yazlm olan bir programn altrlmas birka sistem
fonksiyonunun arlmas ile yaplmaktadr. Komut satrndan yazy alan, diskte bir dosyay
arayan, bir dosyay RAMe ykleyen, RAMdeki program altran fonksiyonlar dzenli olarak
arlmaktadr.
letim sisteminin almas srasnda kendisinin de ard, sistem programcsnn da
dardan arabildii iletim sistemine ait fonksiyonlara sistem fonksiyonlar denir. Bu tr
fonksiyonlara Windows sisteminde API (Application Proggramming Interface) fonksiyonlar,
UNIX iletim sisteminde ise sistem armalar (system calls) denir.
Aslnda btn dosya ilemleri, hangi programlama dili ile allrsa allsn, iletim sisteminin
sistem fonksiyonlar tarafndan yaplr. Sistem fonksiyonlarnn isimleri ve parametrik yaplar
sistemden sisteme deiebilmektedir.
AUTOEXEC.BAT
Dosyann
Diskteki Yeri
Dosyann
zellikleri
Dierleri
...
...
...
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. Kapatlmamas eitli problemlere yol aabilir.
299
32
fopen fonksiyonu
FILE *fopen (const char *fname, const char *mode)
Fonksiyonun 1. Parametresi alacak dosyann ismidir. 2. Parametre a modudur. Dosya ismi
path ierebilir. Dizin geileri iin / de konulabilir. A modu unlar olabilir :
Mode
"w"
"w+"
"r"
"r+"
"a"
"a+"
Anlam
Dosyay yazmak iin aar. Dosyadan okuma yaplamaz. Dosyann mevcut olamas
zorunlu deildir. Dosya mevcut deilse yaratlr. Dosya mevcut ise sfrlanr.
Dosyay yazma ve okuma iin aar. Dosyann mevcut olamas zorunlu deildir.
Dosya mevcut deilse yaratlr. Dosya mevcut ise sfrlanr.
Dosyay okuma iin aar. Dosyaya yazma yaplamaz. Dosya mevcut deilse
alamaz.
Dosyay okuma ve yazma iin aar. (Dosyann pozisyon gstericisi dosyann
bandadr). Dosya mevcut deilse alamaz.
Dosyay sonuna ekleme iin aar. Dosyadan okuma yaplamaz. Dosyann mevcut
olamas zorunlu deildir. Dosya mevcut deilse yaratlr.
Dosyay sonuna ekleme ve dosyadan okuma iin aar. Dosyann mevcut olamas
zorunlu deildir. Dosya mevcut deilse yaratlr.
Fonksiyonun geri dn deerine ilikin FILE yaps stdio.h ierisinde bildirilmitir. Fonskiyonun
geri dn deeri FILE yaps trnden bir adrestir. Bu yapnn elemanlar standart deildir.
Sistemden sisteme deiiklik gsterebilir. Zaten programc bu yapnn elemanlarna gereksinim
duymaz. fopen fonksiyonu iletim sisteminin dosya a sistem fonksiyonunu ararak dosyay
aar ve dosyaya ilikin baz bilgileri bu FILE yaps ierisine yazarak bu yapnn balang
adresini geri dndrr. rnein "file handle" deeri de bu yapnn ierisindedir. Tabi fopen
fonksiyonunun geri verdii FILE trnden adres gvenli bir adrestir. Dosya eitli sebeplerden
dolay alamayabilir. Bu durumda fopen NULL gsterici dndrr. Fonksiyonun geri dn
deeri kesinlikle kontrol edilmelidir. Tipik bir kontrol ilemi aadaki gibi yaplabilir:
if ((f = fopen(data, r)) == NULL) {
300
DOSYALAR
printf(cannot open file...\n);
exit(1);
}
Dosya ismi dosyann yeri hakknda bilgi (src, path gibi) ierebilir. Dosya ismi string ile
veriliyorsa path bilgisi verirken dikkatli olmak gerekecektir. path bilgisi \ karakteri ierebilir.
string iinde \ karakterinin kullanlmas, \ karakterininin onu izleyen karakterle birlikte nceden
belirlenmi ters bl karakter sabiti olarak yorunlanmasna yol aabilecektir. rnein :
fopen("C:\source\new.dat", "r");
fonksiyon armnda derleyici \n karakterini "newline" karakteri olarak yorumlayacak \s
karakterini ise "undefined" kabul edecektir. Bu problemden saknmak \ yerine \\ kullanlmasyla
mmkn olur:
fopen("C:\\source\\new.dat", "r");
Append modlar ("a", "a+") ok kullanlan modlar deildir. Dosyaya yazma durumunda "w"
modu ile "a" modu arasnda farkllk vardr. "w" modunda dosyada olan ofsetin 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 stringde '+' karakterinin kullanlmas durumunda dikkatli olmak gerekir.
Okuma ve yazma ilemleri arasnda mutlaka ya dosya pozisyon gstericisinin
konumlandrlmas (mesela fseek fonksiyonu ile) ya da dosyaya iliken tampon bellek alannn
(buffer) tazelenmesi gerekecektir.
Bir dosyann alp alamayacan aadaki ekilde test edebiliri:
Program komut satrndan
canopen dosya.dat
eklinde altrldnda ekrana "xxxxx dosyas alabilir" ya da "xxxxx dosyas alamaz"
yazacaktr.
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *fp;
if (argc != 2) {
printf("usage: canopen filename\n");
return 2;
}
if ((fp = fopen(argv[1], "r")) == NULL) {
printf("%s dosyas alamaz\n", argv[1]);
return 1;
}
printf("%s dosyas alabilir\n", argv[1]);
fclose(fp);
return 0;
}
fclose fonksiyonu
int fclose(FILE *stream);
Bu fonksiyon alm olan bir dosyay kapatr. Fonksiyon fopen ya da fropen fonksiyonundan
elde edilen FILE yaps trnden adresi parametre olarak alr ve ak olan dosyay kapatr.
301
32
Fonksiyonun geri dn deeri 0 ise dosya baarl olarak kapatlmtr. Fonksiyonun geri dn
deeri EOF ise dosya kapatlamamtr. EOF stdio.h iinde tanmlanan bir sembolik sabittir ve
derleyicilerin ounda (-1) olarak tanmlanmtr. Fonksiyonun baars ancak phe altnda
test edilmelidir. Normal artlar altnda dosyann kapatlmamas iin bir neden yoktur.
int main()
{
FILE *f;
fgetc fonksiyonu
int fgetc(FILE *f);
letim sisteminin dolaysyla Cnin yazma ve okuma yapan fonksiyonlar yazlan ve okunan
miktar kadar dosya gstericisini ilerletirler. fgetc fonksiyonu dosya gstericisinin gsterdii
yerdeki byte okur ve geri dn deeri olarak verir. Fonksiyon baarsz olursa , stdio.h
dosyas ierisinde sembolik sabit olarak tanmlanm EOF deerine geri dner. Pek ok derleyici
de EOF sembolik sabiti aadaki gibi tanmlanmtr.
#define EOF (-1)
fgetc fonksiyonunun geri dn deerini char trden bir deikene atamak yanl sonu
verebilir, bu konuda dikkatli olunmal ve fonksiyonun 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' kaybedilecek
ve ch deikenine 0xFF deeri atanacaktr. Bu durumda ch deikeni iaretli char trden
olduundan ch deikeni iinde negatif bir saynn tutulduu anlam kar.
if (ch == EOF)
gibi bir karlatrma deyiminde, if parantezi ierisindeki karlatrma ileminin yaplabilmesi
iin otomatik tr dnm yaplr. Bu otomatik tr dnmnde iaretli int trne evrilecek
ch deikeni FF byte' ile beslenecektir. (negatif olduu iin). Bu durumda eitlik karlatrmas
doru netice verecek, yani dosyann sonuna gelindii (ya da baka nedenden dolay okumann
yaplamad) yorumu yaplacaktr.
Oysa ch deikeni int trden olsayd, ch deikenine atanan deer 0x00FF olacak ve bu
durumda karlatrma yapldnda ch deikeni ile EOF deerinin (0xFFFF) eit olmad
sonucuna varlacaktr.
Bir dosyann ieriini ekrana yazdran rnek program:
302
DOSYALAR
#include <stdio.h>
int main()
{
FILE *f;
char fname[MAX_PATH];
int ch;
printf(Dosya ismi : );
gets(fname);
if (f = fopen(fname, r)) == NULL) {
printf(cannot open file...\n);
exit(1);
}
while (ch = fgetc(f)) != EOF)
putchar(ch);
fclose(f);
return 0;
}
not : maximum path uzunluu DOSda 80 UNIX ve WINDOWSda 256 karakteri geemez.
fputc Fonksiyonu
int fputc(int ch, FILE *p);
Bu fonksiyon dosya gstericisinin bulunduu yere 1 byte bilgiyi yazar. Fonksiyonun 1.
parametresi yazlacak karakter, 2. parametresi ise yazlacak dosyaya ilikin FILE yaps
adresidir. Fonksiyonun geri dn deeri EOF ise ilem baarszdr. Deilse fonksiyon yazlan
karakter ile geri dner.
fgetc ve fputc fonksiyonlar kullanlarak bir dosyay kopyalayan rnek program:
#include <stdio.h>
#include <stdlib.h>
#define MAX_PATH
80
int main()
{
FILE *fsource, *fdest;
char source[MAX_PATH], dest[MAX_PATH];
int ch;
printf(kopyalanacak dosya : );
gets(source);
printf(kopya dosya : );
gets (dest);
if ((fsource = fopen(source, r)) == NULL) {
printf(cannot open file...\n);
exit(EXIT_FAILURE);
}
if ((fdest = fopen(dest, w)) == NULL) {
printf(cannot create file...\n);
exit(EXIT_FAILURE);
}
while ((ch = fgetc(fsource)) != EOF)
fputc(ch, fdest);
fclose(fsource);
fclose(fdest);
printf(1 file copied...\n);
return 0;
303
32
fprintf Fonksiyonu
Bu fonksiyon tpk printf fonksiyonu gibidir. Ancak ilk parametresi yazma ileminin hangi
dosyaya yaplacan belirtir. Dier parametreleri printf fonksiyonun da olduu gibidir. zetle
printf fonksiyonu ekrana yazar ancak fprint fonksiyonu 1. parametre deikeninde belirtilen
dosyaya yazar.
#include <stdio.h>
#include <stdlib.h>
#define MAX_PATH
80
int main()
{
FILE *f;
int i;
if ((f = fopen(data, w)) ==NULL) {
printf(cannot open file...\n");
exit(1);
}
for (i = 0; i < 10; ++i)
fprintf(f, sayi = %d\n, i);
fclose(f);
}
return 0;
fgets fonksiyonu
char *fgets(char *buf, int n, FILE *f);
Bu fonksiyon dosya gstericisinin gsterdii yerden 1 satrlk bilgiyi okur. Fonksiyon dosyadan
'\n' karakterini okuyunca onu da birinci parametresinde verilen adrese yazarak ilemini
sonlandrr.
Fonksiyonun 1. parametresi okunacak bilginin RAM'de yerletirilecei yerin adresidir. 2.
parametresi ise okunacak maksimum karakter saysdr. fgets en fazla n 1 karakteri okur.
Okuduu karakterlerin soonuna null karakteri ekler ve ilemini sonlandrr. Eer satr zerindeki
karakter says n- 1'den az ise tm satr okur ve ilemini sonlandrr. rnein bu parametreyi
10 olarak girdiimizi dnelim. Satr zerinde 20 karakter olsun. Fonksiyon 9 karakteri okur,
sonuna NULL karakteri ekler. Ancak satr zerinde \n dahil olmak zere 5 karakter olsayd
fonksiyon bu 5 karakteri de okuyarak sonuna da NULL karakter ekleyerek ilemini
sonlandracakt. Bir dng ierisinde fgets fonksiyonu srekli olarak arlarak btn dosya
okunabilir.
Fonksiyonun geri dn deeri, en az 1 karakter okunmu ise 1. parametresi ile belirtilen
adresin ayns, hi okunmamsa NULL adresidir.
rnek : Bir dosyay fgets fonksiyonu ile satr satr olarak ekrana yazan program:
#define MAX_PATH
#define MBUFSIZE
80
100
int main()
{
FILE *f;
char s[MAX_PATH];
char buf[BUFSIZE];
printf(Dosya : );
gets(s);
304
DOSYALAR
if ((f = fopen(s, r)) == NULL) {
printf(cannot open file...\n);
exit(1);
}
while (fgets(buf, BUFSIZE, f) != NULL)
printf(%s, buf);
fclose(f);
return 0;
}
305
32
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 olmayacaktr.
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
modda aldn dnelim. Bu dosyada 10 numaral ve 13 numaral ASCII karakterleri
yanyana bulunduunda dosyadan yalnzca 1 byte okunacaktr. Ayn ekilde dosyadan 26
numaral ASCII karakteri okunduunda dosyadan artk baka bir okuma yaplamayacaktr.
(Dosyann sonuna gelindii varsaylacaktr.)
/*
textmode.c program
DOS altnda text modu ile binary mod arasndaki
fark gsteren bir program
*/
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
main()
{
FILE *fp;
int k, ch;
clrscr();
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
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
306
dosya
text
modunda
alarak
DOSYALAR
10
*/
10
10
10
10
fclose(fp);
307
dosya
text
modunda
alarak
32
0
1
2
308
DOSYALAR
negatif deere sahip olabilir. Pozitif bir deer ileri, negatif bir deer geri anlamna gelecektir.
rnein dosya gstericisi 10. offsette olsun.
fseek(f, -1, SEEK_CUR);
armas ile dosya gstericisi 9. offset'e konumlandrlr.
fonksiyonun 3. parametre deikenine geilen deer 2 ise (SEEK_END), konumlandrma EOF
durumundan itibaren yani dosya sonunu referans alnarak yaplr. Bu durumda ikinci parametre
<= 0 olmaldr. rnein dosya gstericisini EOF durumuna ekmek iin :
fseek(f, 0, SEEK_END);
armasn yapmak gerekir. Ya da baka bir rnek:
fseek(f, -1, SEEK_END);
armas ile dosya gstericisi son karakterin offsetine ekilir. Fonksiyonun geri dn deeri
ilemin baars hakknda bilgi verir. Geri dn deeri 0 ise ilem baarldr. Geri dn deeri
0 d bir deer ise ilem baarszdr. Ancak problemli durumlarda geri dn derinin test
edilmesi tavsiye edilir.
Yazma ve okuma ilemleri arasnda dosya gstericisinin fseek fonksiyonu ile konumlandrlmas
gerekir.Konumlandrma gerekirse bo bir fseek armas ile yaplabilir. rnein dosyadan bir
karakter okunup , bir sonraki karaktere bu karakterin 1 fazlasn yazacak olalm.
ch = fgetc(f);
fputc(ch + 1, f);
ilemi hataldr. Yazmadan
konumlandrlmaldr.
okumaya,
okumadan
yazmaya
geite
dosya
gstericisi
feof fonskiyonu :
bu fonksiyon dosya gstericisinin EOF durumunda olup olmadn (EOF indikatrnn set edilip
edilmediini) test etmek amacyla kullanlr. Prototipi:
int feof(FILE *f);
Eer dosya gstericisi dosya sonunda ise (EOF indikatr set edilmise) fonksiyon 0 d bir
deere , deilse (EOF indikatr set edilmemise) 0 deeri ile geri dner.
Ancak feof fonksiyonunun 0 d bir deere geri dnebilmesi iin dosya gstericisinin dosyann
sonunda olmasnn yan sra en son yaplan okuma ileminin de baarsz olmas gerekir. daha
nce sylendii gibi baz fonksiyonlar (fopen, fseek, rewind, clearerr) EOF indikatorn clear
ederler, yani EOF indikatrnn 0 deerinde olmas (clear edilmi olmas) dosyann sonunda
olunmadnn bir garantisi deildir.
fread ve fwrite fonksiyonlar
Bu iki fonksiyon C dilinde en ok kullanlan dosya fonksiyonlardr. Genel olarak dosya ile RAM
arasnda transfer yaparlar. Her iki fonskiyonun da prototipleri ayndr.
size_t fread(void *adr, size_t size, size_t n, FILE *);
size_t fwrite (const void *adr, size_t size, size_t n, FILE *);
size_t trnn derleyiciyi yazanlar tarafndan unsigned int ya da unsigned long trnn
typedef edilmi yeni ismi olduunu hatrlayalm.
309
32
310
DOSYALAR
okunan byte says 2. parametresi ile belirtilen say olur. rnein DOS altnda alyor olalm.
Dosyada 10 byte bilgi kalm olsun.
n = fread(a, sizeof(int), 10, f);
ile fonksiyon 5 saysna geri dnecektir.
Aadaki iki ifadeyi inceleyelim:
fread(str, 100, 1, f);
fread(str, 1, 100, f);
her iki fonksiyon arma ifadesi de RAM'deki str adresine FILE trnden f gstericisi ile
ilikilendirilen dosyadan 100 byte okumak amacyla kullanlabilir. Ancak birinci armada geri
dn deeri ya 0 ya 1 olabilecekken, ikinci fonksiyon armasnda geri dn deeri 0
100(dahil) herhangi bir deer olabilecektir.
Blok blok kopyalama ilemi
Aadaki rnekte bir grup byte fread fonskiyonu ile bir dosyadan okunmu ve fwrite
fonksiyonu ile dier bir dosyaya yazlmtr.
#define
#define
BLOCK_SIZE
MAX_PATH
1024
80
int main()
{
FILE *fs, *fd;
char s[MAX_PATH], d[MAX_PATH];
unsigned n;
remove fonksiyonu
Bu fonksiyon bir dosyay silmek iin kullanlr. Fonksiyonun prototipi :
int remove (const char *filename);
311
32
eklindedir. Fonksiyona arguman olarak silinecek dosyann ismi gnderilir. Fonksiyonun geri
dn deeri, dosyann baarl bir ekilde silinebilmesi durumunda 0 aksi halde (yani dosya
silinememise) 0 d bir deerdir. Ak olan bir dosyann silinmesi "implementation depended"
(derleyiciye bal) olduundan, yazlan kodun tanabilirlii asndan, silinecek bir dosya ak
ise nce kapatlmaldr.
rename fonksiyonu
Bu fonksiyon bir dosyann ismini deitirmek iin kullanlr. Fonksiyonun prototipi :
int rename (const char *old, const char *new);
eklindedir.
Fonksiyona 1. arguman olarak dosyann eski ismi ikinci arguman olarak ise dosyann yeni ismi
gnderilmelidir. Fonksiyonun geri dn deeri, isim deitirmen ileminin baarl olmas
durumunda 0, aksi halde (dosyann ismi deitirilemiyorsa 0 d bir deerdir. (rnein ak
olan bir dosyann isminin deitirilmeye allmas baarl olamayacandan fonksiyon bu
durumda 0 d bir deere geri dnecektir.)
tmpfile fonksiyonu
Fonksiyon geici bir dosya amak amacyla kullanlr. Fonksiyonun prototipi :
FILE * tmpfile(void);
tmpfile fonksiyonu at geici dosyay "wb" modunda aar. Alan dosya fclose fonksiyonu ile
kapatldnda ya da (kapatlmazsa), program sona erdiinde otomatik olarak silinecektir.
Fonksiyonu geri dn deeri, alan geici dosya ile iliki kurulmasna yarayacak, FILE yaps
trnden bir adrestir. Herhangi bir nedenle dosya geici dosya alamyorsa fonksiyon NULL
adresine geri dnecektir.
tmpnam fonksiyonu
Geici olarak kullanlacak bir dosya iin bir isim retilmesi amacyla kullanlr. Fonksiyonun
prototipi :
char *tmpnam(char *s);
eklindedir. Fonksiyon rettii dosya ismini kendisine gnderilen char trden adrese yerletirir.
Eer fonksiyona arguman olarak NULL adresi gnderilirse, fonksiyon retilen dosya ismini
statik bir dizi iinde tutarak bu dizinin adresiyle geri dnecektir. Fonksiyona char trden bir
dizinin adresi gnderildiinde bu dizinin boyutu ne kadar olmaldr. Baka bir deyile tmpnam
fonksiyonu ka karakter uzunluunda bir dosya ismi retecektir. te bu deer stdio.h dosyas
iinde tanmlanan L_tmpnam sembolik sabitiyle belirtilmektedir.
tmpnam fonksiyonunun rettii dosya isminin daha nce kullanlmayan bir dosya ismi olmas
garanti altna alnmtr. Yani retilen dosya ismi tektir. (unique file name) Bir programda daha
sonra silmek zere bir dosya aacamz ve bu dosyaya birtakm bilgileri yazacamz
dnelim. Bu durumda dosyay yazma modunda aacamza gre, aacamz dosyaya olan
bir dosyann ismini veremeyiz. Eer verirsek , var olan dosya sfrlanaca iin bu dosyay
kaybederiz. Bu riske girmemek iin, geici olarak kullanlacak dosya tmpfiel fonksiyonu
kullanlarak almaldr. Ancak tmpfile fonksiyonunun kullanlmas durumunda, alan dosya
kalc hale getirilemez. Yani herhangi bir nedenden dolay geici dosyann silinmemesini
istersek, (dosyay kalc hale getirmek istersek) dosyay fopen fonksiyonuyla amalyz. te bu
durumda geici dosyay baka bir dosyay riske etmemek iin tmpnam fonksiyonunun rettii
isim ile amalyz. Peki tmpnam fonksiyonuyla en fazla ka tane "unique file name " retebiliriz.
te bu say stdio.h iinde tanmlanan TMP_MAX sembolik sabiti ile belirlenmitir.
312
DOSYALAR
C dilinde baz giri ve k birimleri(klavye, ekran gibi) dorudan bir dosya gibi ele alnrlar. C
standartlar herhangi bir giri k birimini "stream" olarak isimlendirmektedir. Bir stream bir
dosya olabilecei gibi, dosya olarak ele alnan bir giri k birimi de olabilir. rnein kk
programlar genellikle girdilerini genellikle tek bir stream,den alp (mesela klavye) ktlarn da
tek bir streame (mesela ekran) iletirler.
freopen fonksiyonu
freopen fonksiyonu daha nce alm bir dosyay, fropen fonksiyonu ile alan dosyaya
ynlendirir. Fonksiyonun prototipi :
FILE *freopen(const char *filename, const char *mode, FILE *stream);
eklindedir.
Uygulamalarda daha ok standart dosyalarn (stdin, stdout, stderr) baka dosyalara
ynlendirilmesinde kullanlr. rnein bir programn ktlarnn data.dat isimli dosyaya
yazlmasn istersek :
if (freopen("data.dat", "w", stdout) == NULL) {
printf("data.dat dosyas alamyor\n");
exit(EXIT_FAILURE);
}
yukardaki fonksiyon armyla stdout dosyasnn ynlendirildii dosya kapatlarak (bu
ynlendirme ilemi komut satrndan yaplm olabilecei gibi, freopen fonksiyonunun daha
nceki arm ile de yaplm olabilir.) stdout dosyasnn data.dat dosyasna ynlendirilmesi
salanr.
freopen fonksiyonunun geri dn deeri fonksiyona gnderilen nc arguman olan FILE
yaps trnden gstericidir. freopen dosyas ynlendirmenin yaplaca dosyay aamazsa NULL
adresine geri dner. Eer ynlendirmenin yapld eski dosya kapatlamyorsa, freopen
fonksiyonu bu durumda bir iaret vermez.
dosya buffer fonksiyonlar
kincil belleklerle (disket, hard disk vs.) yaplan ilemler RAM'de 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 performans bufferlama yoluyla artrlmaktadr. Bir dosyaya yazlacak data ilk nce
bellekteki bir buffer alannda saklanr. Bu buffer alan dolduunda ya da yazlmann yaplaca
dosya kapatldnda bufferdaki data alannda ne varsa dosyaya yazlr. Buna bufferin
boaltlmas (to flush the buffer) denir.
Giri dosyalar da benzer ekilde bufferlanabilir. Giri biriminden alnan data (rnein
klavyeden) nce buffera yazlr.
dosyalarn bufferlamas erimlilikte ok byk bir arta neden olur. nk bufferdan (RAM'den)
bir karakter okunmas ya da buffera bir karakter yazlmas ihmal edilecek kadar kk bir
zaman iinde yaplr. Buffer ile dosya arasndaki transfer phesiz yine vakit alacaktr ama bir
defalk blok transferi, kk kk transferlerin toplamndan ok daha ksa zaman alacaktr.
stdio.h balk dosyas iinde prototipi bildirimi yaplan ve dosyalarla ilgili ilem yapan
fonksiyonlar tamponlamay otomatik olarak gerekletirirler. Yani dosyalarn tamponlanmas
iin bizim birey yapmamza gerek kalmadan bu i geri planda bize sezdirilmeden
yaplmaktadr. Ama baz durumlarda tamponlama konusunda programc belirleyici durumda
olmak isteyebilir. te bu durumlarda programc dosya tamponlama fonksiyonlarn (fflush,
setbuf, setvbuf) kullanacaktr:
fflush fonksiyonu
313
32
Bir program ktsn bir dosyaya yazarken (rnein stdout dosyasna) yazlan dosya ilk nce
RAM'deki tamponlama alanna gider. Dosya kapatldnda ya da tamponlama alan
dolduunda, tamponlama alan boaltlarak dosyaya yazlr. fflush fonksiyonunun
kullanlmasyla, dosyann kapatlmas ya da tamponlama alannn dolmas beklenmeksizin,
tamponlama alan boatlarak dosyaya yazlr. Bu ilem istenilen sklkta yaplabilir.
Fonksiyonun prototipi :
int fflush (FILE *stream);
eklindedir.
fflush(fp);
arm ile FILE yaps trnden fp gstericisi ile ilikilendirilen dosyann tamponlama alan
(buffer) boaltlr. Eer fflush fonksiyonuna NULL adresi gnderilirse, ak olan btn dosyalarn
tamponlama alanlar boaltlacaktr.
Tamponlama alannn boaltlmas ilemi baarl olursa fflush fonksiyonu 0 deerine geri
dnecek aksi halde EOF deerine geri dnecektir.
setvbuf fonksiyonu
setvbuf fonksiyonu bir dosyann tamponlanma eklinin deitirilmesi ve tampon alannn yerinin
ve boyutunun deitirilmesi amacyla kullanlr. Fonksiyonun prototipi aadaki ekildedir :
int setvbuf(FILE *stream, char *buf, int mode, size_t size);
Fonksiyona gnderilen nc arguman tamponlama eklini belirler. nc argumann deeri
stdio.h balk dosyas iinde tanmlanan sembolik sabitlerle belirlenir.
_IOFBF (full buffering - tam tamponlama)
data 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 fonksiyonuna gnderilen ikinci arguman RAM'de tamponlamann yaplaca bloun
balang adresidir. Tamponlamann yaplaca alan statik ya da dinamik mrl olabilecei
gibi, dinamik bellek fonksiyonlaryla da tahsis edilebilir.
Fonksiyona gnderilen son arguman tamponlama alannda tutulacak bytelarn saysdr.
setvbuf fonksiyonu dosya aldktan sonra, fakat dosya zerinde herhangi biri ilem yaplmadan
nce arlmaldr. Fonksiyonun baarl olmas durumunda fonksiyon 0 deerine geri
dnecektir. Fonksiyona gnderilen nc argumann geersiz olmas durumunda ya da
fonksiyonun ilgili tamponlamay yapamamas durumunda, geri dn deeri 0 d bir deer
olacaktr.
Fonksiyona
gnderilen
buffer
alannn
geerliliinin
bitmesinden
nce
(mrnn
tamamlanmasndan nce) dosya kapatlmamaldr.
dosya ilemleri ile ilgili rnek uygulamalar:
Uygulama 1 : Dosya zerinde sral veri taban tutulmas
#include <stdio.h>
#include <stdlib.h>
314
DOSYALAR
#include <conio.h>
#include <string.h>
/* symbolic constants */
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
MAX_PATH
ADDREC
LISTREC
FINDREC
DELREC
EDITREC
PACKRECS
SORTREC
EXITPROG
DELETED
NORMALREC
INVALID
80
1
2
3
4
5
6
7
8
0
1
0
/* structure declarations */
typedef struct _PERSON {
char name[30];
int no;
int delflag;
} PERSON;
/* function prototypes */
int
void
void
void
void
void
void
void
GetOption(void);
AddRec(void);
ListRec(void);
FindRec(void);
DelRec(void);
EditRec(void);
SortRec(void);
Pack(void);
/* global variables */
FILE *f;
char fname[MAX_PATH];
/* function definitions */
void AddRec(void)
{
PERSON per;
void FindRec(void)
{
PERSON per;
315
32
char name[30];
void ListRec(void)
{
PERSON per;
putchar('\n');
fseek(f, 0L, SEEK_SET);
while (fread(&per, sizeof(PERSON), 1, f) > 0) {
printf("\n%20s
%5d", per.name, per.no);
if (per.delflag == DELETED)
printf("\tDELETED");
}
putchar('\n\n');
void DelRec(void)
{
char name[30];
PERSON per;
printf("Silinecek kaytn ad ve soyad : ");
fflush(stdin);
gets(name);
fseek(f, 0, SEEK_SET);
while (fread(&per, sizeof(PERSON), 1, f) > 0) {
if (!stricmp(per.name, name)) {
per.delflag = DELETED;
fseek(f, -(long)sizeof(PERSON), 1);
fwrite(&per, sizeof(PERSON), 1, f);
printf("Record deleted!..\n");
return;
}
}
printf("silinecek kayt bulunamad");
}
void EditRec(void)
{
char name[30];
PERSON per;
printf("Deitirilecek kaytn ad ve soyad : ");
fflush(stdin);
gets(name);
fseek(f, 0, SEEK_SET);
while (fread(&per, sizeof(PERSON), 1, f) > 0) {
if (per.delflag == NORMALREC && !stricmp(per.name, name)) {
printf("Ad soyad : ");
316
DOSYALAR
fflush(stdin);
gets(per.name);
printf("No : ");
scanf("%d", &per.no);
fseek(f, -(long)sizeof(PERSON), 1);
fwrite(&per, sizeof(PERSON), 1, f);
printf("Record updated!..\n");
return;
}
}
printf("deitirilecek kayt bulunamad\n");
}
int GetOption(void)
{
int option;
void SortRec(void)
{
PERSON per[2], tmp;
int i, count, chgFlag;
fseek(f, 0, SEEK_END);
count = ftell(f) / sizeof(PERSON);
do {
chgFlag = 0;
for (i = 0; i < count - 1; ++i) {
fseek(f, (long)i * sizeof(PERSON), SEEK_SET);
if (fread(per, sizeof(PERSON), 2, f) != 2) {
printf("cannot read from the file!..\n");
exit(EXIT_FAILURE);
}
if (per[0].no > per[1].no) {
chgFlag = 1;
tmp = per[0];
per[0] = per[1];
per[1] = tmp;
fseek(f, (long)i * sizeof(PERSON), SEEK_SET);
if (fwrite(per, sizeof(PERSON), 2, f) != 2) {
printf("cannot read from the file!..\n");
exit(EXIT_FAILURE);
}
}
}
} while (chgFlag);
317
32
}
void Pack(void)
{
FILE *fnew;
PERSON per;
void main()
{
char dfname[MAX_PATH];
int option;
printf("Data File : ");
gets(dfname);
if ((f = fopen(dfname, "r+b")) == NULL)
if ((f = fopen(dfname, "w+b")) == NULL) {
printf("Cannot open database file!..\n");
exit(EXIT_FAILURE);
}
strcpy(fname, dfname);
for (;;) {
option = GetOption();
switch (option) {
case ADDREC
: AddRec(); break;
case LISTREC : ListRec(); break;
case FINDREC : FindRec(); break;
case DELREC
: DelRec(); break;
case EDITREC : EditRec(); break;
case PACKRECS : Pack(); break;
case SORTREC : SortRec(); break;
case EXITPROG : goto EXIT;
case INVALID : printf("Geersiz Seenek!..\n");
}
}
EXIT:
fclose(f);
}
318
DOSYALAR
#include
#include
#include
#include
#include
<stdio.h>
<stdlib.h>
<string.h>
<io.h>
<errno.h>
#define GOOD
#define FAIL
0
(-1)
#define FBUFSIZ
char
char
(63*512)
/* Buffer size */
if (c1 == EOF)
break;
return GOOD;
}
int filecopy(FILE *fi, FILE *fo)
{
int c, nbytes;
rewind(fi);
rewind(fo);
for (;;) {
c = fread(Buffer, 1, FBUFSIZ, fi);
if (c == 0) {
break;
}
nbytes = fwrite(Buffer, 1, c, fo);
if (nbytes != c) {
return FAIL;
}
}
return GOOD;
}
319
32
int main(int argc, char *argv[])
{
FILE *fi, *fo;
char *ptr;
int i;
printf("*GA Developer's Backup Utility. Version 1.0\n"
"(C) *GA, 1995\n\n");
if (argc != 2) {
fprintf(stderr, "Usage: BK <filename>\n");
return 1;
}
if ((Buffer = malloc(FBUFSIZ)) == NULL ||
(in_buf = malloc(FBUFSIZ)) == NULL ||
(out_buf = malloc(FBUFSIZ)) == NULL) {
fprintf(stderr, "Not enough memory\n");
return 2;
}
if ((fi = fopen(argv[1], "rb")) == NULL) {
ptr = argv[1];
OPN_ERR:
fprintf(stderr, "File could not be opened: '%s'\n", ptr);
return 3;
}
setvbuf(fi, in_buf, _IOFBF, FBUFSIZ);
strcpy(CmpFile, argv[1]);
ptr = strchr(CmpFile, '.');
if (ptr == NULL)
ptr = strchr(CmpFile, '\0');
for (i = 1; i <= 999; ++i) {
sprintf(ptr, ".%03d", i);
if (access(CmpFile, 0))
break;
}
if (i == 1000) {
fprintf(stderr, "Backup operation failed: File limit!\n");
return 3;
}
strcpy(OutFile, CmpFile);
if (i > 1) {
sprintf(ptr, ".%03d", i-1);
if ((fo = fopen(CmpFile, "rb")) == NULL) {
ptr = CmpFile;
goto OPN_ERR;
}
setvbuf(fo, out_buf, _IOFBF, FBUFSIZ);
if (!filecmp(fi, fo)) {
printf("No differences encountered: '%s'\n", CmpFile);
return 0;
}
fclose(fo);
}
printf("File being copied: %s ---> %s\n", argv[1], OutFile);
320
DOSYALAR
return 0;
/*******bol.c *******************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define
MAX_LEN
80
32
if (fd == NULL) {
fd = fopen(fdname, "wb");
if (fd == NULL) {
printf(" %s dosyasi yaratilamiyor!\n", fdname);
exit(EXIT_FAILURE);
}
no_of_files++;
printf("%s dosyasi yaratildi!\n", fdname);
}
fputc(ch, fd);
no_of_chars++;
if (no_of_chars % chunk == 0) {
fclose(fd);
printf("%s dosyasi kapatildi!\n", fdname);
fd = NULL;
sprintf(fdname, "dos%04d.xxx", no_of_files + 1);
}
}
fclose(fs);
if (no_of_chars % chunk != 0) {
fclose(fd);
printf("%s dosyasi kapatildi!\n", fdname);
}
return 0;
/*******bir.c *******************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define
MAX_LEN
80
322
%d
adet
dosyaya
DOSYALAR
printf("%s dosyasi yaratildi!\n", fdname);
while (fs = fopen(fsname, "rb")) {
no_of_files++;
printf("%s dosyasi acildi!\n", fsname);
while ((ch = fgetc(fs)) != EOF) {
fputc(ch, fd);
no_of_chars++;
}
fclose(fs);
printf("%s dosyasi kapatildi!\n", fsname);
sprintf(fsname, "dos%04d.xxx", no_of_files + 1);
}
fclose(fd);
printf("%s dosyasi kapatildi!\n", fdname);
printf("%d
adet
dosya
%ld
uzunlugunda
%s
ismli
birlestirildi!\n", no_of_files, no_of_chars, fdname);
for (k = 1; k <= no_of_files; ++k) {
sprintf(fsname, "dos%04d.xxx", k);
remove(fsname);
printf("%s dosyasi silindi!\n", fsname);
}
}
return 0;
323
dosya
altinda\
33
renk = 1;
dezavantaj,
int renk;
tanmlama ifadesini grd zaman, renk deikeninin yalnzca 4 farkl deer alabileceini
bilemedii gibi,
renk = 1;
eklinde bir atama yapldn grdnde de renk deikenine "karo" deerinin atanm
olduunu anlayamaz.
Sembolik sabitlerin kullanlmas ile okunabilirlik byk lde artrlabilir. Yukardaki rneimiz
iin aadaki sembolik sabitlerin tanmlanm olduunu dnelim:
#define
#define
#define
#define
#define
KARTRENK
SINEK
KARO
KUPA
MACA
int
1
2
3
4
KARTRENK renk;
renk = KARO;
Artk ifade daha okunabilir bir hale getirilmitir. Bu yntem ilk kullanlan teknikten phesiz
daha iyidir, ama yine de en iyi zm olduu sylenemez. Yukardaki sembolik sabit
tanmlamalarnn ayn tre ait olduunu program okuyan kiiye gsterecek bir ibare yoktur.
Trn alabilecei deer says daha fazla sayda ise her biri iin bir sembolik sabit tanmlamak
zahmetli olacaktr. KARO, KUPA vs. olarak isimlendirdiimiz sembolik sabitler programn
derlenmesinden nce, nilemci aamasnda tamsay sabitlerle yer deitireceinden, hata
ayklama (debug) aamasnda artk bu sabitlere ulalamayacaktr.
C dili, tasarm yaplan tr iin yalnzca belirli deerlerin alnabilmesini salayan bir tre
sahiptir. Bu tr enum anahtar szcyle belirtilir. Trn alabilecei belirli deerleri gsteren
isimlere ise enum sabitleri (enumeration constants) denir.
324
Sample rst;
MONTHS this_month;
RENK kart1, kart2, kart3;
BOOL flag1, openflag, endflag, flag2;
325
33
326
#define komutu nilemciye ilikindir fakat enum sabitlerini ele alarak ileme sokmak derleme
modlne ilikindir. Yani #define ve enum farkl aamalarda ele alnrlar. enum sabitleri ok
sayda ve ardl tanmlamalar iin tercih edilirler ve bir tr ismi olarak da okunabilirlii
artrrlar. rnein:
BOOL isprime(int x);
gibi bir prototipi gren programc isprime fonksiyonunun yalnzca doru ya da yanl
deerlerinden birini rettiini, bylelikle fonksiyonun test amacyla yazldn anlar.
enum sabitleri C dilinin faaliyet alan kurallarna uyarlar. Eer bir enum tr bir fonksiyon
iinde bildirilmise bu tre ilikin enum sabitleri szkonusu fonksiyonun dnda tannmazlar.
Derleyicilerin standart balk dosyalarnda bir ok enum tr ve bu trlere ilikin sembolik
sabitler tanmlanmtr. rnein aadaki enum bildirimi 80x86 sistemlerinde alan bir
Borland derleyicisinin GRAPHICS.H dosyasndan alnmtr.
enum COLORS {
BLACK,
BLUE,
GREEN,
CYAN,
RED,
MAGENTA,
BROWN,
LIGHTGRAY,
DARKGRAY,
LIGHTBLUE,
LIGHTGREEN,
LIGHTCYAN,
LIGHTRED,
LIGHTMAGENTA,
YELLOW,
WHITE
};
enum tr isimleri de yap ve birliklerde olduu gibi, typedef anahtar szc yardmyla tip
isimlerine dntrlebilirler. rnein:
typedef enum {Sinek, Karo, Kupa, Maca} renk;
bildiriminden sonra artk enum anahtar szc kullanlmadan
renk kart1, kart2, kart3, kart4;
gibi bir tanmlama yaplabilir. artk renk bir tip ismi belirtmektedir. enum tr iin ok
kullanlan bir typedef rnei de:
typedef enum {FALSE, TRUE} BOOL;
(C++ dilinde struct, union ve enum trne ilikin isimler ayn zamanda trn genel ismi
olarak kullanlabilecei iin yukardaki gibi bir typedef bildirimine gerek kalmayacaktr. )
33
tanmlamasnda
flag1 = FALSE;
yerine
flag1 = 1; eklinde atama yapabiliriz?
Verilen rnekte flag1 enum BOOL trnden bir deikendir, ve derleyici enum trnden bir
deiken ile int trden bir deiken aarsnda fark gzetmez. Ancak derleyicilerin ou,
programcnn bunu bilinsizce ya da yanllkla yaptn dnerek bir uyar mesaj verirler.
Yukarda verilen rnek iin verilebilecek tipik bir uyar mesaj :"assigning int to BOOL" eklinde
olacaktr.
enum trden bir deikene ablonda belirtilen snrlar dnda kalan deerleri de atayabiliriz.
Yukardaki rnek iin:
flag1 = 10;
eklinde atama yapabiliriz. (Bu durumda doal olarak yine ayn uyar mesajn alrz.)
Dahas enum trden bir deikene baka trden bir deiken ya da sabit de atayabiliriz. Bu
durumda tr dnm kurallar gerei atamadan nce otomatik tr dnm yaplarak sa
taraf ifadesi int trne dntrlecektir.
double x = 5.6;
flag1 = x;
Bu durumda x deikenine 5 deeri atancaktr.
Unutulmamas gereken udur: enum trnn kullanlmasnn nedeni ncelikle okunabilirlii
artrmaktr. Yukardaki atamalar yapmamz teknik olarak mmkn olmakla birlikte, bu rnekler
okunabilirlii kt ynde etkilediklerinden ancak bilinsiz kullanma rnek olabilir. deal durum,
enum trden nesnelere ilgili enum tr iin nceden belirlenmi enum sabitlerini atamaktr.
Bir enum nesnesini operatrler ileme sokabiliriz. rnein:
Derleyici enum trnden nesneleri ayn int tr gibi ele alacandan enum trnden nesneler
de int trden nesneler gibi operatrler yardmyla yeni ifadelerin oluturulmasnda
kullanlabilirler.
enum sabitlerinin kendisi sol taraf deeri gerektiren durumlarda
kullanlamazlar.
enum {Sunday = 1, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday} day1, day2,
day3;
Yukardaki tanmlamadan sonra
++Sunday;
gibi bir ifade geersiz olacaktr. nk enum sabitleri bir soltaraf deeri deildir.
++day1;
ifadesi ise geerlidir. ++day1 ifadesi day1 + 1 anlamna geleceinden, sonuta day1'e (enum
trnden deiken) int trden bir say atanm olacandan baz derleyiciler bu durum iin bir
uyar verebilirler.
328
MAKROLAR
34 . BLM : MAKROLAR
nilemci komutlarndan, #define nilemci komutunun sembolik sabit tanmlamalarnda
kullanln daha nce grmtk. Makrolar #define nilemci komutunun paremetreli
kullanm ile elde edilen yaplardr.
#define nilemci anahtar szcn izleyen isim parametreli olarak kullanlabilir. Bu durum
sentaks olarak isime bitiik olarak yazlan alan parantez ile belirtilir. Bu parantezin iinde
tanmlanan makroya ilikin parametre(ler) yer alr. Kapanan parantezi izleyen yaz ise makroya
ilikin deitirme listesidir. nilemci makro parametrelerine ilikin deitirme listesini bir
ablon olarak kabul eder ve kaynak kod iinde makronun arldn tespit ettiinde makro
armnda kullanlan argumanlar, ablona uygun olarak aar.
Basit bir rnekle balayalm:
#define Alan(x, y)
((x) * (y))
int main()
{
int a = 10;
int b = 5;
int c;
c = Kare_fark(a, b);
printf("c = %d\n", c);
return 0;
}
329
34
Yukardaki kaynak kodu alan nilemci iini bitirdikten sonra derleyicinin ele alaca kaynak
kod aadaki ekilde olacaktr :
stdio.h dosyasnn ierii
int main()
{
int a = 10;
int b = 5;
int c;
c = (((a) - (b)) * ((a) + (b)));
printf("c = %d\n", c);
return 0;
}
Bir yln artkyl olup olmadn test etmek iin kullanlacak baka bir makro:
#define is_leap(y)
ISUPPER(c)
ISLOWER(c)
ISDIGIT(c)
ISEVEN(x)
MAKROLAR
#define getchar()
getc(stdin)
Yukardaki makro yerine sembolik sabit de kullanlabilirdi. Ancak fonksiyon yapsna benzetmek
amacyla parametresi olmayan bir makro olarak tanmlanmtr.
331
34
Aadaki makrolar gz nne alalm:
#define KARE(a)
((a) * (a))
int x = 10, y;
y = KARE(x++)
ifadesi makro tanmlamasna uygun olarak aldnda
y = ((x++) * (x++))
ifadesi oluacaktr ki bu ifade de, operatrler konusunda grdmz gibi "undefined behavior"
zellii gsterecektir. Oysa KARE bir fonksiyon olsayd bu fonksiyonun
KARE(x++);
eklinde arlmas bir probleme neden olmayacakt. x++ ifadesi x deikeninin (artmayan)
deerini reteceinden, KARE fonksiyonu 10 deeri ile arlm olacakt.
5. Makrolarda makrolarn argumanlar ile parametreleri arasnda tr dntrlmesi sz
konusu deildir.
Bir fonksiyon arlma ifadesini grdnde derleyici fonksiyona gnderilen arguman ile
fonksiyonun ilgili parametre deikeni arasndaki tr uyumunu kontrol eder. Eer bu trler
arasnda bir farkllk varsa, mmknse, tr dntrme kurallar gerei arguman olan ifdadenin
trn parametre deikeninin trne evirir. Makro argumanlarnn nilemci tarafndan
makronun parametrelerine gre tr uyumunun kontrol edilmesi ya da tr dntrme ilemine
tabi tutulmas sz konusu deildir.
C++ dilinde makrolarn kullanm C diline gre ok daha azalmtr. Zira C++ dilinde bir ok
durumda makrolar yerine inline fonksiyonlar kullanlmaktadr.
6. Bir gsterici bir makroyu gsteremez.
leride greceimiz gibi C dilinde bir fonksiyonu gsteren gsterici tanmlanabilir. Ve bu
gstericilerden C programclnda eitli biimlerde faydalanmak mmkndr. Ancak makrolar
nilemci aamasnda ele alndndan bir gstericini bir makroyu gstermesi sz konusu
deildir.
# ve ## nilemci operatrleri
Makro tanmlamalar iki zel operatr ierebilirler. Bu operatrler derleyiciyi deil nilemciyi
ilgilendirmektedir. Yani nilemcinin kts derleyici modlne verildiinde artk kaynak kod bu
operatr atomlarndan arndrlm olacaktr.
# atomu makronun yer deitirme listesinde (replacement list) yer alabilecek bir operatrdr.
Operand makro parametresidir. Makronun alm srasnda #operandna alnan arguman string
haline getirilir. Yani ift trnak iine alnr. Bu yzden bu atoma stringe dntrme operatr
de denir. (stringizing operator)
#atomunun kullanlabilecei
inceleyelim :
#define PRINT_INT(x)
bir
ka
tema
aada
332
verilmektedir.
Aadaki
makroyu
MAKROLAR
eklinde makronun arldn dnelim. Makro aldnda derleyiciye giden kaynak kod
aadaki ekilde olacaktr :
int result = 5;
printf("result" " = %d\n", result);
Aralarnda boluk karakterleri dnda baka bir karakter bulunmayan stringlerin derleyici
tarafndan tek bir string olarak birletirildiklerini anmsarsak, yukardaki ifadenin derleyici
asndan aadaki ekilde yorumlanacan grebiliriz :
printf("result = %d\n", result);
Bylece yukardaki deyimin icra edilmesiyle ekrana aadaki ekilde bir yaz yazdrlabilecektir :
result = 5;
## nilemci operatr iki operand alan araek konumunda bir operatrdr. Makronun almas
srasnda Operand olan atomlar birletirerek tek bir atom haline getirir. Bu yzden atom
birletirme operatr diye de isimlendirilir. (Token pasting operator),
Atom birletirme operatrnn operandlarndan biri eer bir makro parametresi ise, birletirme
ilemi parametre ilgili argumanla yer deitirdikten sonra yaplacaktr. Atom birletirme
operatr ##, string yapma atomu kadar sk kullanlan bir operatr deildir. Sadece ok zel
durumlarda kullanlmaktadr.
a*a
Yulardaki makro
x = ALAN(y);
eklinde arlrsa nilemci kodu
x = y * y;
eklinde aacandan bir problem olumayacaktr. Ancak makronun
int y = 1;
x = ALAN(y + 5)
eklinde arldn dnelim. Bu durumda derleyici kodu
x = y + 5 * y + 5;
eklinde aacaktr. Ve bu durumda y deikenine 36 yerine 11 deeri atanacaktr.
Bu tr problemlerin nlenebilmesi iin makro tanmlamalarnda makro alm ifadesinde yer
alan makro parametreleri parantez iine alnmaldr.
Yukardaki makro
#define ALAN(a)
(a) * (a)
333
34
x = (y + 5) * (y + 5);
ifadesi oluacaktr ki, deyimin icras sonucunda x deikenine 36 deeri atanacaktr.
Peki ya makro aadaki ekilde arlrsa
x = 72 / ALAN(y + 5);
x deikenine 2 deerinin atanmas gerekireken, makro aadaki gibi alacandan
x = 72 / (y + 5) * (y + 5) ;
x deikenine 72 deeri atanacaktr.
Makro tanmlamalarnda makro alm ifadeleri en dardan parantez ierisine alnmaldr.
Sz konusu makro
#define ALAN(a)
((a) * (a))
((a) * (a))
nilemci artk yukardaki tanmlamay bir makro deil bir sembolik sabit olarak ele alacaktr.
nilemci kaynak kodun geri kalan ksmnda grd ALAN yazlarn (a)
((a) * (a)) ile
yer deitirecektir. rnein :
ALAN(x + 3);
gibi bir ifadenin var olduunu dnelim. nilemci bu kodu aadaki ekilde aacaktr :
(a)
gibi bir makronun tanmlandn ve kaynak kod ierisinde aadaki fonksiyon tanmnn da yer
aldn dnelim.
int max(int number1, int number2)
{
return x > y ? x : y;
}
Kaynak kod ierisinde rnein
334
MAKROLAR
c = max(a, b);
eklinde bir deyimin yer aldn dnelim. Bu durumda ne olacaktr?
Tabi ki nilemci makroyu aacaktr. Zira makrolarn almas, yani metinsel yer deitirme
ileminin yaplmas,
daha derleyici kaynak kodu ele almadan nilemci tarafndan
yaplacandan, derleyici modlne sra geldiinde derleyici artk yukardaki arm ifadesi
yerinde
c = a > b ? a : b;
ifadesini grecektir.
Ayn isimli makro ve fonksiyon tanmlamalarnn var olmas durumunda, makro almn
yaplmas yerine fonksiyonunu arlmas isteniyorsa ne yaplabilir?
Bu durumda fonksiyon arma ifadesinde fonksiyon ismi parantez iine alnrsa, nilemci artk
bir yer deitirme yapmaz ve derleyici fonksiyon arma kodu retir.
(gets(s), puts(s))
{ gets(s); puts(s); }
Makro yukardaki gibi tanmlandnda baz problemler oluabilir. rnein makronun aadaki
gibi bir if deyimi iinde arldn dnelim :
if (echo_flag)
ECHO(str);
else
gets(str);
nilemci makroyu aadaki gibi aacaktr :
335
34
if (echo_flag)
{ gets(str); puts(str); };
else
gets(str);
Kod derleyici modlne geldiinde aadaki gibi yorumlanacandan
if (echo_flag)
{ gets(str); puts(str); }
;
else
gets(str);
if ksm olmayan bir else olmas gerekesiyle derleme zamannda bir error oluacaktr. Oluan
problemi nasl zebiliriz? Makronun arlmas durumunda sonlandrc ";" at0munu
koymayarak? Bu irkin bir tarz olurdu...
Bu durumda iki yntem kullanabiliriz :
1. Makro almnda do while dng yapsn kullanmak:
#define ECHO(s)
do {
gets(s);
puts(s);
} while (0)
\
\
\
\
karakterinin
\
\
\
\
\
yukardaki makro
ECHO(str);
eklinde arlp nilemci tarafndan aldnda makro arma ifadesinin sonundaki
sonlandrc (;) if deyiminin yanl ksmna ilikin (else ksmna ilikin) bo deyim olacaktr.
336
35
#define MAX
100
...
#if MAX > 50
...
#else
#if MAX < 1
...
#endif
#endif
yerine
#elif nilemci komutu da kullanlabilir. Ancak bu durumda #elif nilemci komutuna ilikin
#endif ile dardaki #if komutuna ilikin #endif ortak olacaktr.
#define MAX 100
...
#if max > 50
...
#elif MAX > 30
...
#else
...
#endif
Koullu derleme ilemi kaynak kodun belirli blmlerini belli durumlarda derleme ilemine
sokmak iin kullanlr.phesiz bu durum programc tarafndan da kodun eklenip silinmesiyle
salanabilirdi. Ancak #if komutu buna daha kolay olanak salamaktadr.
338
#ifdef nilemci komutu ayn balk dosyasn kullanan ve birka modlden oluan
programlarda yaygn olarak kullanlr. rnein dosya1.c, dosya2.c ve dosya3.c modllerinden
oluan bir projede project.h isimli bir balk dosyas ortak olarak kullanlyor olsun. Bu durumda
global deikenlerin yalnzca bir modlde global dierlerinde extern olarak kullanlmas
gerekecektir. Bu aadaki gibi salanabilir.
/*
project.h*/
#ifdef
GLBVAR
#define EXTRN
#else
#define EXTRN extern
#endif
/* Global deikenler */
EXTRN int x;
EXTRN int y;
...
imdi modllerin birinde, bu balk dosyasnn include edilmesinden nce, GLBVAR adl bir
sembolik sabit tanmlanrsa, nilemci EXTRN szcn sileceinden (onun yerine boluk
karakteri kopyalayacandan) o modl iin global tanmlama yaplm olur. Deilse EXTRN
yerine extern anahtar szc nilemci tarafndan yerletirilecektir. #ifdef nceden
tanmlanm sembolik sabitlerle tanabilirlii salamak amacyla da sklkla kullanlmaktadr.
#ifndef komutu #ifdef komutunun tam tersidir. Yani sembolik sabit tanmlanmamsa #else
ksmna kadar olan blm, tanmlanmsa #else ile #endif arasndaki ksm derleme ilemine
dahil edilir. rnein :
#ifndef BLINK
#define
BLINK
#endif
0x80
Burada BLINK sembolik sabiti ancak daha nce tanmlanmamsa tanmlanmas yaplmtr.
Daha nce tanmlanmsa tanmlanma ilemi yaplmamtr.
339
35
__STDC__
Yukarda nilemci komutlar ile derleyicinin standart C derleyicisi olup olmadna baklarak
belirli kaynak kod paralar derlemeye dahil ediliyor.
4. Bir Balk Dosyasnn Bir Kereden Daha Fazla Kaynak Koda Dahil
Edilmesini nlemek Amacyla. (multiple inclusion)
Ayn balk dosyas kaynak koda #include nilemci komutuyla iki kez eklenmemelidir. Bir
balk dosyas bir kaynak koda birden fazla eklenirse ne olur? Balk dosyalar iinde ne
oldugunu hatrlayalm :
1.
Fonksiyon prototip bildirimleri
Hatrlayacamz gibi fonksiyon prototip bildirimlerinin zde olarak birden fazla
yaplmas bir error oluumuna neden olmaz.
2.
Sembolik sabit ve makro tanmlamalar
zde sembolik sabit ve makro tanmlamalar kaynak kodun nilemci tarafndan ele
alnmas srasnda bir hataya neden olmaz.
3.
typedef bildirimleri (tr tanmlamalar)
typedef anahtar szc ile yaplan tr tanmlamalar zde olmalar durumunda yine
derleme zamannda bir hata oluumuna neden olmazlar.
4.
Yap, birlik, bit alan, enum tr bildirimleri
Bir zde olarak bile birden fazla yaplrsa derleme zamannda hata oluumuna neden
olur. Bu yzden bir balk dosyas kaynak koda birden fazla dahil edilirse ve o balk
340
#ifndef GENERAL_H
...
#define GENERAL_h
...
#endif
Yukardaki kod parasnda balk dosyas #ifndef ve #endif nilemci komutlarnn
arasna alnmtr. Eer GENERAL_H sembolik sabiti tanmlanmsa, bu general.h balk
dosyasnn kaynak koda daha nce dahil edildii anlamna gelecek ve #ifndef ile #endif
arasndaki kaynak kod paras kaynak koda eklenmeyecektir. Eer GENERAL_H sembolik
sabiti tanmlanm ise, #ifndef ile #endif arasndaki kaynak kod paras kaynak koda
eklenecektir. Eklenen kod paras iinde #define GENERAL_h nilemci komutu da
bulunmaktadr.
Bu standart yntemle, yani balk dosyalarnn bir sembolik sabitin tanmlanmasna bal
olarak kaynak koda eklenip eklenmemesi salanr bylece bir kaynak kodun birden fazla
kaynak koda eklenmesi engellenmi olur.
Koullu derlemeye ilikin nilemci komutlarnn kullanlmasna ilikin bir program paras
rnei aada verilmitir :
#if DLEVEL > 5
#define SIGNAL 1
#if STACKUSE == 1
#define STACK
#else
#define STACK
#endif
#else
#define SIGNAL 0
#if STACKUSE ==
#define STACK
#else
#define STACK
#endif
#endif
#if DLEVEL == 0
#define STACK 0
#elif DLEVEL == 1
#define STACK
#elif DLEVEL > 5
display(debugptr);
#else
#define STACK 200
#endif
200
50
0
200
50
100
Yukardaki rnekte birinci #if blounun altnda iki ayr #if #else yaps bulunmaktadr. DLEVEL
sembolik sabitinin 5'den byk olup olmamasna gre deerine gre nilemci tarafndan doru
ksm ya da yanl ksm ele aacaktr.
341
35
#elif nilemci komutunun da yer ald ikinci #if blounda ise DLEVEL sembolik sabitinin
deerine gre 4 seenekten biri ele alnacaktr. DLEVEL sembolik sabitinin deerine bal olarak
STACK sembolik sabiti 0, 100 ya da 200 olarak tanmlanmaktadr. DLEVEL sembolik sabitinini
deerinin 5'den byk olmas durumunda ise
display(debugptr);
deyimi derleyiciye verilmekte ve bu durumda STACK sembolik sabiti tanmlanmamaktadr.
__TINY__
Bu program tiny modelde derlenmez!..
#error direktifi
error nilemci komutunun yannda (boluk karakteri ile ayrlm) bir hata mesaj yer alr.
Derleyici error direktifini grnce bu hata mesajn yazarak deleme ilemine son verecektir.
#ifdef __TINY__
#error bu program tiny modelde derlenemez
#endif
NCEDEN TANIMLANMI SEMBOLK SABTLER
342
nilemci bu sabit yerine kaynak koddaki o anda bulunan satr numaralarn yerletirir. Bu zel
durumlar test edilerek eitli seenekler deerlendirilmektedir. Bu ksmda nceden
tanmlanm sembolik sabitlerin standart olanlarndan bir ksmn inceleyeceiz.
__LINE__
nilemci bu sabit yerine kaynak koddaki o anda bulunulan satr numarasn yerletirir.
#include dosyalarnn ii bu ileme dahil edilmez. Aadaki kodu inceleyiniz:
#include <stdio.h>
int main()
{
printf("satr no . %d\n", __LINE__)
return 0;
}
__FILE__
nilemci bu sabit yerine iki trnak ierisinde kaynak dosyann ismini yazar. Aadaki rnekte
kaynak dosyann ismi ekrana yazdrlyor. string ifadelerinin karakteri gsteren birer adres
olduunu anmsaynz.
#include <stdio.h>
int main()
{
printf("dosya ismi : %s\n", __FILE__);
return 0;
}
__DATE__ ve __TIME__ : nilemci bu sabitlerin yerine derlemenin yapld tarih ve zaman
yazar. __DATE__ "aaa gg yyyy", __TIME __ ise ss:dd:ss biiminde yazlmaktadr.
Tanabilirlie ilikin sembolik sabitler
__STDC__
C'de kullandmz kimi anahtar szckler tam anlamyla standart deildir. Bu anahtar
szckler sistemler aras farkllklara karlk verebilmek iin kullanlmaktadr.
rnein 8086 sistemlerinde kullandmz far ve near standart olarak her sistemde bulunmayan
iki anahtar szcktr. Derleyiciniz eger yalnzca C'nin anahtar szcklerini destekliyorsa
__STDC__
sembolik sabiti tanmlanm varsaylr.
erisinde standart olmayan anahtar szckler geen programlar bu sembolik sabit kullanlarak
daha tanabilir bir hale getirilebilir :
#ifdef
#define
#endif
__STDC__
far
Yukardaki rnekte eer yalnzca standart C'nin anahtar szcklerini kullanan bir derleyici ile
alyorsanz __STDC__ tanmlanm olacandan far anahtar szc silinecektir.
__TINY__
__SMALL__
__MEDIUM__
343
35
__COMPACT__
__LARGE__
__HUGE__
Borland derleyicilerinde aktif olarak kullanlan bellek modeline gre bu sembolik sabitlerden bir
tanesi tanmlanm saylr. rnein o anda LARGE modelde allyorsa yalnzca __LARGE__
SEMBOLK SABT TANIMLANMI SAYILIR.
__MSDOS__
DOS ile UNIX arasndaki tanabilirlik problemlerini zmek iin kullanlr. Eer MSDOS
altndaki bir derleyici ile alyorsanz __MSDOS__ sembolik sabiti tanmlanm kabul
edilmektedir.
#ifndef
#define
#endif
__MSDOS__
far
Yukardaki rnekte eer MSDOS ile allmyorsa far anahtar szc silinmektedir.
__TURBOC__
Borland firmasnn turbo C uyarlamalaerndan bir tanesinde alyorsanz bu sembolik sabit
derleyiciniz tarafndan tanmlanm varsaylr. Sembolik sabitin tanmlanan deeri (test iin
nemli olamaz) uyarlamadan uyarlamaya deiebilmektedir.
__BORLANDC__
Borland firmasnn BORLAND C uyarlamalaerndan bir tanesinde alyorsanz bu sembolik
sabit derleyiciniz tarafndan tanmlanm varsaylr. Sembolik sabitin tanmlanan deeri (test
iin nemli olamaz) uyarlamadan uyarlamaya deiebilmektedir.
__cplusplus
C++ ismiyle piyasaya kan derleyiciler standart C yi de destekler. Bu durumda derleyicilerin
hangi C uyarlamasnda altklar bu sembolik sabit yardmyla renilebilir.
344