You are on page 1of 344

PROGRAMLAMA VE C

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.

Programlama Dillerinin Snflandrlmas


Programlama dillerini eitli alardan snflandrabiliriz. En sk kullanlan snflandrmalar:
1. Seviyelerine gre snflandrma.
2. Uygulama alanlarna gre snflandrma.

Bilgisayar Dillerinin Seviyelerine Gre Snflandrmas ve Seviyelerine Gre


Bilgisayar Dillerinin Geliimi
Bir programlama dilinin seviyesi deyince o programlama dilinin insan algsna olan yaknlnn
derecesini anlyoruz. Bir programlama dili insan alglasna ne kadar yaknsa o kadar yksek
seviyeli demektir (high level). Yine bir programlama dili bilgisayarn elektronik yapsna ve
alma biimine ne kadar yaknsa o kadar dk seviyeli (low level) demektir. Yksek seviyeli
dillerle almak programc asndan kolaydr. Algoritma yoktur. Bu dillerde yalnzca nelerin
yaplaca programa bildirilir ama nasl yaplaca bildirilmez. Genel olarak programlama dilinin
seviyesi ykseldike , o dilin renilmesi ve o dilde program yazlmas kolaylar.

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

Uygulama Alanlarna Gre Snflandrma


1. Bilimsel ve mhendislik uygulama dilleri:
Pascal, C (C programlama dili niversitelerdeki akademik almalarda da youn olarak
kullanlyor.), FORTRAN
2. Veri taban dilleri:
XBASE, (Foxpro, Dbase, CA-Clipper), Oracle Forms, Visual Foxpro.
3. Genel amal programlama dilleri:
Pascal, C, Basic.
4. Yapay zeka dilleri:
Prolog, Lisp.
5. Simulasyon dilleri
GPSS, Simula 67
6. Makro Dilleri (Scripting languages)
awk, Perl, Python, Tcl, JavaScript.
7. Sistem programlama dilleri:
Sembolik makine dilleri, BCPL, C, C++, occam.
Gnmzde sistem yazlmlarn neredeyse tamamnn C dili ile yazldn syleyebiliriz.
rnek vermek gerekirse UNIX iletim sisteminin % 80'i C dili ile geri kalan ise sembolik
makine dili ile yazlmtr. Bu iletim sistemi ilk olarak BELL labaratuarlarnda
oluturulmutur. Kaynak kodlar gizli tutulmam, bylece eitli kollardan gelitirilmesi
mmkn olmutur. Daha sonra gelitirilen UNIX bazl iletim sistemi uygulamalarna deiik
isimler verilmitir.

PROGRAMLAMA VE C

C bilimsel ve mhendislik alanlarna kullanlabilen genel amal bir sistem programlama dilidir.

Programlama Dillerinin Deerleme ltleri


Kaynaklar u an halen kullanmda olan yaklak 1000 - 1500 programlama dilinin varlndan
sz ediyor. Neden bu kadar fazla programlama dili var? Bu kadar fazla programlama dili
olmasna karn neden halen yeni programlama dilleri tasarlanyor? Bir programlama dilini
dierine ya da dierlerine gre daha farkl klan zellikler neler olabilir? Bir programlama dilini
tanmlamak istesek hangi sfatlar kullanabiliriz? Programlama dilleri hakkndaki bu sorulara
yant verebilmemiz iin elimizde deerlendirme yapmamza olanak salayacak ltler
olmaldr. Bu ltleri ksaca inceleyelim:

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.

Veri trleri ve yaplar (data types and structures)


eitli veri trlerini (tamsay, gerek say, karakter...) ve veri yaplarn (diziler, yaplar vs.)
destekleme yeteneidir. Veri yaplar, veri trlerinin oluturduu mantksal birliklerdir. rnein
C ve Pascal dilleri veri yaplar bakmndan zengin dillerdir.

Alt programlama yetenei (Modularity)


Bir btn olarak zlmesi zor olan problemlerin paralara ayrlmas ve bu paralarn ayr ayr
zmlenmesinden sonra paralar arasndaki koordinasyonun salanmas programada sk
bavurulan bir yntemdir. Bir programlama dili buna olanak salayacak aralara sahipse alp
programlama yetenei vardr diyebilirriz. Alt programlama yetenei bir programlama dilinin,
program paralar halinde yazmay desteklemesi anlamna gelir. (C modlaritesi ok yksek bir
dildir)
Alt programlama Yapsal Programlama teknii'nin de ayrlmaz bir parasdr. Alt
programlamann getirdii baz nemli avantajlar vardr. Alt programlar kodu kltr. ok
tekrarlanan ilemlerin alt programlar kullanlarak yazlmas alabilir programn kodunu
kltr. nk alt programlar yalnzca bir kere alabilir kod iine yazlrlar. Ama program
kodu alt programn olduu yere atlatlarak bu blgenin defalarca altrlmas salanabilir.
Alt programlama alglamay kolaylatrr, okunabilirlii artrr. Alt programlama kaynak kodun
test edilebilirliini artrr. Kaynak kodun daha kolay gncelletirilmesi ve yeniden kullanlabilme
olanan artrr. Alt programlamann en nemli avantajlarndan biri de genel amal kodlar
yazarak bu yazlan kodlar birden fazla projede kullanabilmektir. (reusability)
C alt programlama yetenei yksek bir dildir. C'de alt programlara fonksiyon denir.
Fonksiyonlar C Dili'nin yaptalardr.

Yapsallk (structural programming support)


Yapsallk bir programlama tekniidir. Bugn artk hemen hemen btn programlama dilleri
yapsal programlamay az ok destekleyecek bir ekilde gelitirilmitir. Yapsal Programlama
fikri 1960'l yllarda gelitirilmitir. Yapsal programlama teknii drt ana ilke zerine
kurulmutur :
1. Bl ve stesinden gel (divide and conquer)
Yapsal programlama tekniinde, tek bir btn olarak zm getirmek zor olan programlar,
daha kk ve stesinden daha kolay gelinebilecek paralara blnrler. Bu paralar
fonksiyon, prosedr, subroutine, alt program vs. olarak isimlendiriler. Alt program yapsnn
getirdii avantajlar modularite konusunda yukarda aklanmtr.
2. Veri gizleme (Data hiding)

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.

renme ve retme kolayl (pedagogy)


Her programlama dilini renmenin ve renilen programlama dilinde uygulama
gelitirebilmenin
zorluu ayn deildir. Genel olarak programlama dillerinin seviyesi
ykseldike, renme ve bu programlama dilini bakalarna retme kolaylar, renme iin
harcanacak aba ve zaman azalr. Bugn yaygn olarak kullanlan yksek seviyeli programl
dillerinin bu derece popler olmasnn nemli bir nedeni de bu dillerin ok kolay
renilebilmesidir. Ne yazk ki C renimi zor ve zahmetli bir dildir.

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.

Giri / k (input / output, I / O facility) kolayl


Sral, indeksli ve rasgele dosyalara erime, veritaban kaytlarn geri alma, gncelletirme ve
sorgulama yeteneidir. Veritaban programlama dillerinin (DBASE, PARADOX vs.) bu
yetenekleri dierlerinden daha stndr ve bu dillerin en tipik zelliklerini oluturur. Fakat C
giri k kolayl kuvvetli olmayan bir dildir. C'de veri tabanlarnn ynetimi iin zel
ktphanelerin kullanlmas gerekir.

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.

Nesne Ynelimlilik (object orientation)


Nesne ynelimlilik de bir programlama tekniidir.
Yapsal programlama Teknii 1960 ylarnda gndeme
Programlama Teknii 1980'li yllarda popler olmutur.

gelmiken,

Nesne

Ynelimli

Bu teknik kaynak kodlarn ok bymesi sonucunda ortaya kan gereksinim yznden


gelitirilmitir. C dilinin gelitirildii yllarda, akla gelebilecek en byk programlar ancak onbin
satrlar mertebesindeydi, ancak kullanclarn bilgisayar programlarndan beklentilerinin artmas
ve grafik arayznn artk etkin olarak kullanlmasyla, bilgisayar programlarnn boyutu ok
bym, yzbin satrlarla hatta milyon satrlarla llebilir hale gelmitir.
Nesne ynelimli programlama Teknii, hereyden nce byk programlarn yazlmas iin
tasarlanm bir tekniktir. C dilinin yaratld yllarda byle bir tekniin ortaya kmas sz
konusu deildi, nk zaten programlar bugnk llere gre ok kkt.
Nesne ynelimli programlama Tekniinin yaygn olarak kullanlmaya balanmasyla birlikte bir
ok programlama dilinin bnyesine bu tekniin uygulanmasn kolaylatrc aralar eklenek,
yeni versiyonlar oluturulmutur. rnein C'nin
nesne ynelimli programlama tekniini
uygulayabilmek iin Bjarne Stroustrup tarafndan gelitirilmi haline C++ denmektedir. C++
dili C dili baz olarak alnp, gelitirilmi yeni bir programlama dilidir. C++ dilini iyi renebilmek
iin ncelikle C dilini ok iyi renmek gerekir.
Pascal diline eklemeler yaplarak Delphi dili, Cobol dilinden yenilemesiyle OOCobol, Ada dilinin
yenilenmesiyle ise ADA 95 dilleri gelitirilmitir.
Baz programlama dilleri ise dorudan N.Y.P.T'ni destekleyecek ekilde tasarlanarak
gelitirilmitir. rnein JAVA dili C++ dilinin basitletirilmi biimi olup daha ok Internet
uygulamalarnda kullanlmaktadr. Baka bir rnek olarak da Eiffel dili verilebilir.

C Nasl bir Programlama Dilidir?


Btn bunlardan sonra yukarda akladmz kavramlar da kullanarak C dilini aadaki
ekilde tanmlayabiliriz :
C orta seviyeli bir programlama dilidir. Yapsal dier programlama dillerine gre C dilinin
seviyesi daha dktr. C dili hem yksek seviyeli dillerin, kontrol deyimleri, veri yaplar gibi
avantajlarn bnyesinde barndryor, ayn zamanda bitsel operatrler gibi makine kodu
deyimlerini yanstan operatrlerlere sahip. Yani hem makinaya yakn hem de insan
alglamasna. Zaten ok tercih edilmesinin en nemli nedenlerinden biri de bu.
C bir sistem programlama dilidir. Sistem Programlama ne anlama geliyor? Donanmn
ynetilmesi, kontrolu ve denetimi iin yazlan, dorudan donanmla ilikiye giren programlara
sistem program diyoruz. rnein, iletim sistemleri, derleyiciler, yorumlayclar, aygt
srcleri (device drivers), bilgisayarlarn iletiimine ilikin programlar, otomasyon
programlar, sistem programlardr. Dier uygulama programlarna destek veren yazlmlar da
ounlukla sistem programlar olarak ele alnrlar.
C'den nce sistem programlar assembly dillerle yazlyordu.Sistem programlarnn
yazlmasnda hemen hemen alternatifsiz olduunu syleyebiliriz. Bugn cep telefonlarndan,
uaklara kadar her yerde C kodlar almaktadr. rnein Boeing uaklarnda 100.000 satrdan
fazla C kodu alt bilinmektedir.

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.

C Programlama Dili'nin Tarihi


C dilinin tarihini incelediimizde C dilinin UNIX iletim sisteminin bir yan rn olarak
doduunu syleyebiliriz. UNIX iletim sisteminin orjinal ilk versiyonunu
Bell
Labaratuarlar'nda alan Ken Thompson tek bana yazmt ve UNIX'in bu ilk versiyonu DEC
PDP-7 isimli bilgisayarda alyordu. DEC PDP-7 ilk mini bilgisayarlardan biriydi ve ana bellei
yalnzca 16 K (16 MB deil!). Yllardan 1969'du.
Zamannn dier iletim sistemleri gibi UNIX de assembly dilinde yazlmt. Assembly dilinde
yazlan programlar gelitirmek ok zor ve zahmetli olduundan, Thompson UNIX iletim
sistemini daha gelitirebilmek iin, makine dilinden daha yksek seviyeli bir dile gereksinim
duydu. Bu amala kk bir programlama dili tasarlad. Kendi dilini tasarlarken Thompson,
1960 yllarnn ortalarnda Martin Richards tarafndan gelitirilmi BCPL dilinden yola kt.
(BCPL = Business Common Programming Language. Bu dil de CPL = Cambridge Programming
Language'den tretilmitir. CPL'in kayna da tm zamanlarn en eski ve en etkili dillerinden
biri olan ALGOL 60'dr. ALGOL 60 Pascal, ADA, Modula2 dillerinin de atasdr, bu dillere bu
yzden C dilinin kuzenleri de diyebiliriz. Aada ALGOL 60 dil ailesi grlmektedir:
Algol 60

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

2 . BLM : SAYI SSTEMLER


Gnlk hayatta 10luk say sistemini kullanyoruz. 10 luk sistemde bir saynn deeri aslnda her bir basamak
deerinin 10 saysnn ilgili kuvvetiyle arpmlarnn toplanmasyla elde edilir.
rnein 1273 = (3 * 1) + (7 * 10 ) + (2 * 100) + (1 * 1000)
Ancak bilgisayar sistemlerinde btn bilgiler ikilik sistemde(binary system) ifade edilir.
Genel olarak say sistemi kalksa o say sisteminde o kadar sembol bulunur.
rnein 10luk sistemde 10 adet sembol vardr ve bu semboller 0, 1, 2, 3, 4, 5, 6, 7, 8, 9dur.
Ayn ekilde ikilik say sisteminde yalnzca iki adet sembol bulunur. Yani yalnzca 0 ve 1.
Bir sayy baka bir say sisteminde ifade etmek o saynn deerini deitirmez. Yalnzca saynn gsterili
biimi deiir. rnein onluk say sisteminde saysal deeri 32 olan bykl eitli farkl say sistemlerinde
farkl biimlerde gsterebiliriz ama saynn bykln deitirmi olmayz.
kilik sistemde her bir basamaa 1 bit denir. Bit kelimesi binary digit szcklerinden
tretilmitir.
rnein 1011 says 4 bittir. (Ya da 4 bit uzunluundadr).
11011001 says 8 bittir.
8 bitlik bir byklk bir byte olarak isimlendirilir.
1 kilobyte 1K = 1024 byte dr. (yani 210 byte)
1 mega byte 1 MB = 1024 Kilo byte dr. (yani 220 byte)
1 gigabyte 1 GB = 1024 MB dr. (yani 230 byte)
1 terabyte 1 TB = 1024 GB dr. (yani 240 byte)
1 petabyte 1PB = 1024 TB dr. (yani 250 byte)
1 exabyte 1EB = 1024 PB dr. (yani 260 byte)
1 zettabyte 1ZB = 1024 EB dir.( yani 270 byte)
1 yottabyte 1YB = 1024 ZB dr.( yani 280 byte)
Kilo byklk olarak 1000 kat anlamna gelmektedir, ancak bilgisayar alannda Kilo 2'nin 1000'e en yakn
kuvveti olan 210 yani 1024 kat olarak kullanlr.
4 bit 1 Nybble (Nibble eklinde de yazlr)
8 bit 1 byte
16 bit
1 word
32 bit
1 double word
64 bit
1 quadro word
olarak da isimlendirilmektedir.
ikilik sisteme ilikin genel ilemler
i. kilik sistemdeki bir saynn 10 luk sistemde ifade edilmesi:
ikilik say sisteminde ifade edilen bir saynn 10luk sistemdeki karln hesaplamak iin en sadan
balayarak btn basamaklar tek tek 2nin artan kuvvetleriyle arplr. rnein :
1 0 1 1 = 1 * 20 + 1 * 21 + 0 * 22 + 1 * 23 = 11
0010 1001 = (1 * 1) + (1 * 8) + (1 * 32) = 41
Bu arada sk kullanlan iki terimi de aklayalm. kilik say sisteminde yazlan bir saynn en solundaki bit,
yukardaki rnekten de grld gibi en yksek saysal deeri katyor. Bu bite en yksek anlaml bit (most
significant digit) diyeceiz ve bu bit iin bundan sonra MSD ksaltmasn kullanacaz.
kilik say sisteminde yazlan bir saynn en sandaki bit, yine yukardaki rnekten de grld gibi en
dk saysal deeri katyor. Bu bite en dk anlaml bit (least significant digit) diyeceiz ve bu bit iin
bundan sonra LSD ksaltmasn kullanacaz.
rnek :
0101 1101 says iin
MSD = 0
LSD = 1
11

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!

16lk say sistemi (hexadecimal numbering system) ve 8lik say


sistemi (octal system)
Bilgisayarlarn tamamen 2lik sistemde altn sylemitik, ama yukarda grld gibi 2lik sistemde
saylarn ifade edilmesi hem ok uzun hem de zahmetli. Bu yzden, yazm ve alglama kolayl salamak
iin 16lk ve 8lik say sistemleri de kullanlmaktadr.
16'lk ve 8lik say sistemlerinde saylar daha youn olarak kodlanp kullanabilir.
Bata da sz edildii gibi 10 luk sistemde 10, 2lik sistemde ise 2 sembol bulunmaktadr. Bu durumda 16lk
say sisteminde de 16 sembol bulunur.
ilk 10 sembol 10'luk sistemde kullanlan sembollerle tamamen ayndr :
1, 2, 3, 4, 5, 6, 7, 8, 9,
Daha sonraki semboller
A
B
C
D
E
F

= 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

Bu durumda 2ADFH = 0010 1010 1101 1111


2lik sistemden 16lk sisteme yaplacak dnmler de benzer ekilde yaplabilir :
nce saylar sadan balayarak drder drder ayrrz (en son drt eksik kalrsa sfr ile tamamlarz.) Sonra
her bir drtlk grup iin dorudan 16'lk say sistemindeki karln yazarz.
1010 1110 1011 0001
0010 1101 0011 1110

= 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

Aadaki formle gre saynn deeri hesaplanabilir :


V saynn deeri olmak zere:
E = 255 ise ve F 0 d bir deer ise V = NaN (Not a number) bir gerek say olarak kabul edilmez. rnek :
0 11111111 00001000000100000000000
1 11111111 00010101010001001010101

= Say deil
= Say deil

E = 255 ise ve F = 0 ise ve S = 1 ise V = -sonsuz


E = 255 ise ve F = 0 ise ve S = 1 ise V = +sonsuz
0 < E < 255 ise
V = (-1)S * 2(E -127) * (1.F)
nce saynn fraction ksmnn bana 1. eklenir. Daha sonra bu say 2(E-127) ile arplarak noktann yeri
ayarlanr. Noktadan sonraki ksm 2'nin artan negatif kuvvetleriyle arplarak elde edilecektir. rnekler :
0 10000000 00000000000000000000000 = +1 * 2 (128 - 127) * 1.0
= 2 * 1.0
= 10.00
=2

0 10000001 10100000000000000000000 = +1 * 2 (129 - 127) * 1.101


= 22 * 1.101
= 110.100000
= 6.5
1 10000001 10100000000000000000000 = -1 * 2 (129 - 127) * 1.101
= -22 * 1.101
= 110.100000
= -6.5
0 00000001 00000000000000000000000 = +1 * 2 (1 - 127) * 1.0
= 2-126
E = 0 ve F sfr d bir deer ise
V = (-1)S * 2(-126) * (0.F)
rnekler :
0 00000000 10000000000000000000000 = +1 * 2-126 * 0.1
=
0 00000000 00000000000000000000001 = +1 * 2-126 0. 00000000000000000000001
16

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

3 . BLM : GENEL KAVRAMLAR


ATOM KAVRAMI VE ATOM TRLER
Bir programlama dilinde yazlm program en kk paralara blmeye alalm. yle bir noktaya geleceiz
ki, artk bu paralar daha da blmeye altmzda anlamsz paralar oluacak. te bir programlama
dilinde anlam tayan en kk birime atom (token) denir.
Atomlar daha fazla paraya blnemezler.
Yazdmz kaynak kod (program) derleyici tarafndan ilk nce atomlarna ayrlr. (Tokenizing). Atom
yalnzca C diline ilikin bir kavram deildir. Tm programlama dilleri iin atom kavram sz konusudur, ama
farkl programlama dillerinin atomlar birbirlerinden farkl olabilir.
Atomlar aadaki gibi gruplara ayrabiliriz :

1. Anahtar Szckler (keywords, reserved words)


Bu atomlar dil iin belli bir anlam tarlar. Deiken olarak kullanlmalar yasaklanmtr. Yani programc bu
anahtar szckleri kendi tanmlayaca deikenlere isim olarak veremez.
Standard ANSI C dilinde 32 tane anahtar szck bulunmaktadr.(Derleyici yazan firmalar kendi yazdklar
derleyiciler iin ilave anahtar szckler tanmlayabilmektedir.)
auto break case char const continue default do double else enum extern float for
int
long
register return short signed sizeof static struct switch typedef union
unsigned void volatile while

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.

5. Stringler (String literals)


ki trnak iindeki ifadelere string denir. Stringler programlama dillerinin ounda tek bir atom olarak alnrlar,
daha fazla paraya blnemezler.
STRNGLER DE BRER ATOMDUR ifadesi bir stringdir.

20

GENEL KAVRAMLAR

6. Ayralar ya da noktalama iaretleri (Separators, Punctuators,


Delimiters)
Yukarda saylan atom snflarnn dnda kalan tm atomlar bu gruba sokabiliriz. Genellikle dier atomlar
birbirinden ayrma amacyla kullanldklar iin ayra olarak isimlendirilirler.

rnek bir C programnn atomlarna ayrlmas:


Aada 1 den kullancnn klavyeden girdii bir tamsayya kadar olan tamsaylar toplayan ve sonucu ekrana
yazdran bir C program grlyor. Bu kaynak kodu atomlarna ayralm. Amacmz sz konusu program
aklamak deil, atomlar hakknda gerek bir programdan rnek vermek.
#include <stdio.h>
main()
{
int number, k, total = 0;

printf("ltfen bir say giriniz\n");


scanf("%d", &number);
for(k = 1; k<= number; ++k)
total += k;
printf("toplam = %d\n", toplam);
return 0;

programda yer alan atomlardan


anahtar szckler
include int
for

return

isimlendirilenler (identifiers / variables)


main n k
toplam
printf
scanf
operatrler
= <= ++
sabitler
0
1

+=

stringler
("ltfen bir say giriniz\n"

"%d"

"toplam = %d\n"

ayralar noktalama iaretleri


< > ( ) , ; {
}

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 :

1. nceden tanmlanm veri trleri (default types)


Bu trler programlama dilinin tasarmnda var olan veri trleridir. rnein C dilinde nceden
tanmlanm 11 ayr veri tr vardr.

2. Programc tarafndan tanmlanan veri trleri (user defined types)


Programlama dillerinin ounda programcnn tr tanmlamasna izin vermektedir. rnein C dilinde yaplar,
birlikler, bit alanlar, C++ dilinde de snflar programc tarafndan tanmlanan veri trleridir.
Programlama dillerindeki tr tanmlamalar birbirlerinden farkl olabilir. rnein baz programlama dillerinde
Boolean isimli (Mantksal Doru ya da Yanl deerlerini alan) bir trdr tanmlanmtr. Ama C dilinde byle
bir tr dorudan tanmlanmamtr.

Faaliyet alanlar (scope / visibility) :


Nesnenin, dilin derleyicisi ya da yorumlaycs tarafndan tannabildii program alandr. (ileride detayl
inceleyeceiz)

mrleri (storage duration / lifespan) :


Programn altrlmas srasnda nesnenin varln srdrd zaman parasdr. (leride detayl
inceleyeceiz)

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.

SOL TARAF DEER (Left Value)


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

SA TARAF DEER (Rigth Value)


Daha az kullanlan bir terimdir. Nesne gstermeyen ifadeler sa taraf deeri olarak isimlendirilirler. Tipik
olarak, atama operatrnn sol tarafnda bulunamayan yalnzca sa tarafnda bulunabilen ifadelerdir.
Sabitler her zaman sa taraf deeri olutururlar.
(Bir ifade sol taraf deeri deilse sa taraf deeridir. Sa taraf deeri ise sol taraf deeri
deildir.Her ikisi birden olamaz. Yani atama operatrnn sa tarafna gelebilen her ifade sa
taraf deeri olarak isimlendirilmez.) Sa taraf deeri, genellikle bir ifadenin nesne
gstermediini vurgulamak iin kullanlr.

23

4 . BLM : VER TRLER


Nesne (Object) kavramn incelediimiz zaman, nesnelerin en nemli zelliklerinden birinin nesnenin tr
olduunu belirtmitik. Tr (type) nesnenin olmazsa olmaz bir zelliidir ve tr olmayan bir nesneden sz
etmek mmkn deildir. Derleyiciler nesnelerle ve verilerle ilgili kod retirken, tr bilgisinden faydalanrlar.
Tr bilgisinden, sz konusu veriyi bellekte ne ekilde tutacaklarn, verinin deerini ne ekilde
yorumlayacaklarn, veriyi hangi ilemlere tabi tutabileceklerini renirler.
Programlama dilleri asndan baktmz zaman trleri iki ayr gruba ayrabiliriz.
1. nceden tanmlanm veri trleri (Doal veri trleri)
(Basic tpes, default types, built-in types, primitive types)
Programlama dilinin tasarmndan kaynaklanan ve dilin kurallarna gre varl garanti altna alnm olan
trlerdir. Her programlama dili programcnn dorudan kullanabilecei, eitli zelliklere sahip veri trleri
tanmlar. C dilinde de nceden tanmlanm 11 adet veri tr vardr.
2. Programcnn tanmlanm olduu veri trleri (user defined types)
Programlama dillerinin ou, nceden tanmlanm veri trlerine ek olarak, programcnn da yeni trler
tanmlanmasna izin vermektedir. Programcnn tanmlayaca bir nesne iin nceden tanmlanm veri
trleri yetersiz kalyorsa, programc kendi veri trn yaratabilir. C dilinde de programc yeni bir veri trn
derleyiciye tantabilir ve tantt veri trnden nesneler tanmlayabilir.
Farkl programlama dillerindeki nceden tanmlanan veri trleri birbirlerinden farkl olabilir. Daha nce
renmi olduunuz bir programlama dilindeki trlerin aynsn C dilinde bulamayabilirsiniz.
C dilininin nceden tanmlanm 11 veri tr vardr. Bu veri trlerinden 8 tanesi tamsay trnden verileri
tutmak iin, kalan 3 tanesi ise gerek say trnden verileri tutmak iin tasarlanmtr. Biz bu trlere srasyla
"Tamsay veri trleri" (integer types) ve "gerek say veri trleri" (floating types) diyeceiz.

tamsay veri trleri (integer types)


C dilinin toplam 4 ayr tamsay veri tr vardr ancak her birinin kendi iinde iaretli ve iaretsiz biimi
olduundan, toplam tamsay tr 8 kabul edilir.
aretli (signed) tamsay trlerinde pozitif ve negatif tam say deerleri tutulabilirken, iaretsiz (unsigned) veri
trlerinde negatif tamsay deerleri tutulamaz.
Bu trleri srasyla inceleyelim:

iaretli ve iaretsiz char veri tr :


phesiz char szc ingilizce character szcnden ksaltlmtr ve trke "karakter" anlamna
gelmektedir. Ancak bu trn ismini, bundan sonraki derste C dilinin bir anahtar szc olduunu
reneceimiz char szc ile zdeletirip, "char tr" (ar diye okuyunuz) diye syleyeceiz. aretli
char trnden bir nesnenin bir byte'lk bir alanda tutulmas C standartlarnca garanti altna alnmtr.
1 byte'lk bir alan iaretli olarak kullandmzda yazabileceimiz deerlerin -128 / 127 deerleri arasnda
deiebileceini say sistemleri dersimizden hatrlayalm.
iaretsiz char veri trnn iaretli olandan fark 1 byte'lk alann iaretsiz olarak, yani yalnzca 0 ve pozitif
saylarn ifadesi iin kullanlmasdr. Bu durumda iaretsiz char trnde 0 - 255 arasndaki tamsay deerleri
tutulabilir.

iaretli ve iaretsiz short int veri tr (iaretli ksa tamsay tr - iaretsiz


ksa tamsay tr) :
Yine bundan sonraki derste reneceimiz gibi, short ve int szckleri C dilinin anahtar szcklerinden
olduu iin bu trn ismini genellikle short int, ya da ksaca short tr olarak telaffuz edeceiz.

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.

iaretli int (signed int) tr ve iaretsiz int (unsigned int) tr :


iaretli ve iaretsiz int veri trnden bir nesne tanmland zaman, nesnenin bellekte ka byte yer
kaplayaca sistemden sisteme deiebilir. ounlukla 16 bitlik sistemlerde, int veri , 32 bitlik sistemlerde ise
int veri tr 4 byte yer kaplamaktadr.
16 bitlik sistem, 32 bitlik sistem ne anlama geliyor.
16 bitlik sistem demekle ilemcinin yazma (register) uzunluunun 16 bit oldugunu anlatyoruz.
int veri trnn 2 byte uzunluunda olduu sistemlerde bu veri trnn say snrlar, iaretli int tr iin
-32768 - +32767, iaretsiz int veri tr iin 0 - +65535 arasnda olacaktr.

iaretli ve iaretsiz long int veri tr (iaretli uzun tamsay tr - iaretsiz


uzun tamsay tr)
Bu trn ismini genellikle long int, ya da ksaca long tr olarak telaffuz edeceiz.
iaretli ve iaretsiz long int veri trnden biriyle tanmlanan bir nesnenin bellekte ka byte yer kaplayaca
sistemden sisteme deiebilir. Sistemlerin ounda, long int veri trnden yaratlan nesne bellekte 4 byte'lk
bir alan kaplayacaktr. aretli long int veri trnden bir nesne -2147483648 - +2147483647 aralndaki
tamsay deerlerini tutabilirken, iaretsiz long int tr sz konusu olduundan tutulabilecek deerler 0 +4.294.967.296 aralnda olur.

GEREK SAYI TRLER


C dilinde gerek say deerlerini tutabilmek iin 3 ayr veri tr tanmlanmtr. Bunlar srasyla, float, double
ve long double veri trleridir. Gerek say veri trlerinin hepsi iaretlidir. Yani gerek say veri trleri iinde
hem pozitif hem de negatif deerler tutulabilir. Gerek saylarn bellekte tutulmas sistemden sisteme
deiebilen zellikler ierebilir. Ancak sistemlerin ounda IEEE 754 sayl standarda uyukmaktadr.
Sistemlerin hemen hemen hepsinde float veri trnden bir nesne tanmland zaman bellekte 4 byte yer
kaplayacaktr. 4 byte'lk yani 32 bitlik alana zel bir kodlama yaplarak gerek say deeri tutulur. IEEE 754
sayl standartta 4 byte'lk gerek say format "single precision " (tek hassasiyet) olarak isimlendirilmitir.
Bu standartta 32 bitlik alan 3 blme ayrlmtr.
1 bitlik alan (sign bit): gerek saynn iaret bilgisini yani pzoitif mi negatif mi olduu bilgisini tutar.
8 bitlik alan (exponential part) :
23 bitlik alan (fraction part) : saynn ondalk ksmn tutar.
Sistemlerin hemen hemen hepsinde double veri trnden bir nesne tanmland zaman bellekte 8 byte yer
kaplayacaktr. Gerek saylarn bellekte tutulmas sistemden sisteme deiebilen zellikler ierebilir. Ancak
sistemlerin ounda IEEE 754 sayl standarda uyulmaktadr.
long double veri trnden bir nesne tanmland zaman bellekte 10 byte yer kaplayacaktr.
C dilinin doal veri trlerine ilikin bilgileri aada bir tablo eklinde veriyoruz:

25

C DLNN NCEDEN TANIMLANMI


(DEFAULT ) VER TRLER

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

GEREK SAYI TRLER


(FLOATING TYPES)
TR SM

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.

C Dilinde Bildirim leminin Genel Biimi

C programlama Dili'nde bildirim ilemi aadaki ekilde yaplmaktadr :


<tr> <nesne ismi> <;>
Burada noktal virgl karakterine sonlandrc karakter diyoruz. Noktal virgl ayra trnden
bir atomdur ve C'de btn ifadeler noktal virgl ile birbirlerinden ayrlrlar.
ifadelerinde bulunan noktal virgller bunlarn ayr birer ifade olduklarn gsterirler. Eer bir
tek noktal virgl olsayd derleyici iki ifadeyi tek bir ifade gibi yorumlayacakt.
Yukardaki ifade tek bir ifade gibi yorumlanr ve derleyici buna bir anlam veremez.
Tr belirten anahtar szckler, C dilinin nceden tanmlanm veri trlerine ilikin anahtar
szcklerdir. Bu szckleri bildirim sentaksnda kullanarak, daha nce renmi olduumuz 11
temel veri trnden hangisinden deiken tanmlamak istediimizi derleyiciye bildirmi
oluyoruz. C dilinin nceden tanmlanm veri trlerine ilikin, bilidirim ileminde kullanlabilecek
anahtar szckler unlardr :
signed, unsigned, char, short, int, long, float, double
Bu szcklerin hepsi anahtar szck olduundan kk harf ile yazlmaldr, C dilinin byk
harf kk har duyarl (case sensitive) bir dil olduunu hatrlayalm. C dilinin tm anahtar
szckleri kk harf ile tanmlanmtr.
Tr belirten anahtar szckler aadaki tabloda listelenen seeneklerden biri olmaldr. Keli
parantez ierisindeki ifadeler kullanlmas zorunlu olmayan, yani seime bal olan anahtar
szckleri gstermektedir. Ayn satrdaki tr belirten anahtar szckler tamamen ayn anlamda
kullanlabilmektedir.
1
2
3

char
unsigned char
short

[signed ] char
[signed] short

short [int]

28

[signed] short [int]

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]

Yukardaki tablodan da grld


mmkndr.
char a;
int a;
signed char a;
signed int a;
signed a;

signed
long [int]

[signed] long [int]

gibi, belirli trleri birden fazla ekilde ifade etmek


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

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.

C Dilinin simlendirme Kurallar


simlendirmede yalnzca 63 karakter kullanlabilir.
Bunlar: ngiliz alfabesinde yer alan 26 karakter, (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r,
s, t, u, v, w, x, y, z, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z)
rakam karakterleri (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) ve alttire (underscore) karakteridir. (_)
simlendirmelerde yukarda belirtilen karakterlerin dnda baka bir karakterin kullanlmas
derleme zamannda hata oluumuna yol aar. (mein boluk karakterinin kullanlmas Trke
karakterlerin kullanlmas, +, -, /, *, & ya da $ karakterinin kullanlmas gibi).
Deiken isimleri rakam karakteriyle balayamaz. Rakam karakteri dnda, yukarda geerli
herhangi bir karakterle balayabilir.
C'nin anahtar szckleri isimlendirme amac ile kullanlamaz.
simler boluk ieremeyecei iin uygulamalarda genellikle boluk hissi vermek iin alttire
(underscore) karakteri kullanlr.
genel_katsayi_farki, square_total, number_of_cards gibi.
Baka bir teknik de isimlendirmede her szcn ilk harfini Byk, dier harfleri kk
yazmaktr.
GenelKatsayiFarki, SquareTotal, NumberOfCards gibi.
C dilinde yaplan isimlendirmelerde, isimlerin maksimum uzunluu tanmlanmamtr. Bu
derleyicilere gre deiebilir. Ancak bir ok derleyicide 32 says kullanlmaktadr. Eer verilen
isim 32 karakterden daha fazla karakter ieriyorsa, derleyici bu ismi budar, yani yalnzca ilk 32
karakterini alglar.
C dili byk harf kk harf duyarl olan bir dil olduu iin (case sensitive) isimlendirmelerde
de byk harf ve kk harfler farkl karakterler olarak ele alnacaktr :

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.

Bildirimlerin Kaynak Kod inde Yapl Yerleri


C dilinde genel olarak 3 yerde bildirim yaplabilir :
1. Bloklarn iinde
2. Tm bloklarn dnda.
3. Fonksiyon parametre deikeni olarak fonksiyon parantezlerinin ierisinde
Fonksiyon parametre parantezleri ierisinde yaplan bildirimler, baka bir sentaks kuralna
uyarlar, bu bildirimler fonksiyonlar konusuna gelindiinde detayl olarak incelenecektir.
C dilinde eer bildirim bloklarn iinde yaplacaksa, bildirim ilemi bloklarn ilk ilemi olmak
zorundadr. Baka bir deyile bildirimlerden nce baka bir ifade bulunmamal ya da bildirimden
nce bir fonksiyon arlmamaldr. (Aksi halde derleme zaman srasnda hata oluur.)

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 :

Tamsay Sabitleri (integer constants)


aretli Tamsay Sabitleri (signed int) :
Bunlar tipik olarak int trden deikenlerine atanan ve tamsay biiminde olan sabitlerdir,
yazlrken herhangi bir ek almazlar. Cde int tr snrlar iinde olan her tamsay birer tamsay
sabit (ya da int trden sabit ) olarak ele alnr.
saylarnn hepsi iaretli tamsay (signed int) sabiti olarak ele alnrlar, nk int tr say
snrlar iinde bulunuyorlar ve sonlarnda herhangi bir ek bulunmuyor.
int tr sistem bamldr ve int sabitleri de sistemden sisteme deiebilir.
sistem
DOS, WINDOWS 3.1
UNIX WINDOWS 95

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)

Uzun Tamsay Sabitleri


aretli Uzun Tamsay Sabitleri (signed long)
long trden sabitler iki trl ifade edilirler :
1. long int trnn say snrlar iinde bulunan bir saynn sonuna L ya da l yazarak.
Bu durumda derleyiciler ilgili say int snrlar iinde olsa da long sabit olarak ele alr.
2234long sabittir. nk sonunda l eki var.
3
2
02
3
long
5
46 l sabitlerdir.
long sabit kullanmnda alglanmas daha kolay olduu iin L soneki tercih edilmelidir. l
soneki 1 rakamyla grnm asndan ok benzedii iin karkla neden olabilir.

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.

Karakter Sabitleri (char)


char sabitleri tipik olarak char trden nesnelere atanan sabitlerdir. (Byle bir zorunluluk yok.)
char trden sabitler C dilinde drt ayr biimde bulunabilirler.
1. stenilen bir karakter tek trnak (single quote) ierisinde kullanlrsa char trden sabit olarak
ele alnr. rnek :
Yukardaki gsterimlerin herbiri birer char trden sabitidir.
C'de tek trnak ierisinde belirtilen char sabitleri, aslnda o karakterin karakter setindeki
(rnein ASCII tablosundaki) sra numarasn gsteren bir tamsaydr.
Bu rnekte aslnda ch isimli char trden deikene a karakterinin ASCII tablosundaki sra
numaras olan 97 says aktarlmaktadr. Tek trnak iindeki karakter sabitlerini grnce
aslnda onlarn kk birer tamsay olduunu bilmeliyiz. nk bellekte karakter diye
birey yoktur herey ikilik sistemde 1 ve 0 lardan oluan saylardr. Yukardaki rnekte
istersek ch deikenine aadaki gibi bir atama yapabiliriz:
Bu durumda ch deikenine saysal olarak 100 deeri atanacaktr. Bu sayya da ASCII
tablosundaki 'd' karakteri karlk gelir.
2. nceden tanmlanm ters bl karakter sabitleri (escape sequences)
Yukarda tanmlanan yntemde ekrana baslamayan yani ekranda grnt oluturmayan
(non printable) karakterleri ifade edemeyiz. rnein an karakteri (an sesi) ya da ters
boluk (backspace) karakteri ekrana baslamaz. Tek trnak iindeki ters bl (back slash)
karakterinden sonra yer alan baz karakterler ok kullanlan ancak baslamayan baz
karakterlerin yerlerini tutarlar. Bunlarn listesi aada verilmitir:
nceceden Tanmlanm Ters Bl Karakter Sabitleri (Escape Sequences)

'\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

kullanllarna bir rnek :


3. 16'lk (hexadecimal) say sisteminde tanmlanm karakter sabitleri

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'

/* 41H numaral ASCII karakteridir.


*/
/* FFH numaral '2' karakter sabitidir.
*/
/* 1C numaral ASCII karakter sabitidir. */

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.

aretsiz trlere ilikin sabitler


aretsiz trlere ilikin sabitler onlarn iaretli biimlerinin sonuna u ya da U getirilmesiyle elde
edilirler.
-1500
1500
1200L
1200

(signed) int sabit


(unsigned) int sabit.
(signed) long sabit
(unsigned) long sabit.

Sonek olarak kullanlan l, L, u ve U harflerinin sras nemli deildir.

35

5
Yukardaki hepsi geerli birer uzun tamsay (unsigned long int) sabittir.

Tamsay sabitlerinin 16'lk ve 8'lik sistemlerde gsterilmesi


C'de tamsay sabitleri (char, int, long) 10'luk sistemin yansra 16'lk ve 8'lik sistemlerde de
yazlabilirler. Bu say sistemleriyle yazlm tamsay sabit trleri iin yukarda verilen kurallar
aynen geerlidir. nk bir sayy 16'lk ya da 8'lik sistemde yazmakla onun yalnzca
grnmn deitirmi oluruz. Sabit trleri gsterim biimiyle deil nicelikle ilikilidir. C
dilinde ikilik say sisteminde sabitlerin yazlmas sz konusu deildir.
16'lk sistemde gsterim 0Xbbb.. biimindedir. (b karakterleri basamaklar gsteriyor, 9'dan
byk basamak deerleri iin A, B, C, D, E, F karakterleri ya da a, b, c, d, e, f karakterleri
kullanlabilir.
8'lik sistemde ise 0bbb.. biimindedir. (nadir olarak kullanlr). rnekler:
0x12
0X12L
0x1C205470
0x1934ul
01234
0567L
0777U
0452Lu

says hex gsterimli bir tamsay (int) sabit.


says hex gsterimli bir uzun tamsay (long) sabit.
hex gsterimli bir uzun tamsay (long) sabit. nk (DOS'da) tamsay say
snrn amaktadr.
hex gsterimli iaretsiz uzun tamsay (unsigned long) sabittir.
oktal gsterimli tamsay (int) sabit
oktal gsterimli uzun tamsay (long) sabit
oktal gsterimli iaretsiz tamsay (unsigned int) sabit
oktal gsterimli (unsigned long) sabit.

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

Gerek Say Sabitleri (floating Constants)


1. float trden sabitler
Nokta ieren ve sonuna f ya da F getirilmi sabitler float trden sabitler olarak ele alnrlar.
rnein:
float trden sabitlerdir.
Not : Klasik C'de, yani C dilinin standartlatrlmasndan nceki dnemde float trden bir
sabit elde etmek iin, saynn sonuna f eki almas yeterliydi yani nokta iermesi
gerekmiyordu ama standartlarda yaplan deiiklikle artk float sabitlerin sonuna ek gelse
de mutlaka nokta iermeleri gerekiyor. Yani derleyiciler 3f eklinde bir yazm derleme
zamannda bir hata (error) mesajyla bildiriyorlar.
2. double trden sabitler
Sonuna f ya da F eki almam nokta ieren sabitler ile float duyarln am sabitler
double sabitler olarak deerlendirilirler. rnein :
-

double trden sabittir.

3. long double trden sabitler


long double trden sabitler noktal ya da stel biimdeki saylarn sonuna l ya da L
getirilerek elde edilirler :
long double trden sabitlerdir.

36

SABTLER

Gerek Say Sabitlerinin stel Biimde Gsterilmesi


Gerek say sabitleri stel biimde de ifade edilebilirler, bunun iin saynn sonuna e ya da E eki
getirilerek bir tamsay yazlr. Bu, saynn 10x gibi bir arpanla arpldn gsterir.
burada e 10'un kuveti anlamna gelmektedir:
ayn sabitlerdir.

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.

Fonksiyonlarn Tanmlanmas ve arlmas


Bir fonksiyonun ne i yapacann ve bu ii nasl yapacann C dilinin sentaks kurallarna uygun
olarak anlatlmasna o fonksiyonun tanmlanmas (definition) denir. Fonksiyon tanmlamalar
aada incelenecei gibi birtakm sentaks kurallarna tabidir.
Bir fonksiyonun arlmas ise o fonksiyonun yapaca ii icraya davet edilmesi anlamna gelir.
Fonksiyon arma ifadesi karlnda derleyici, programn akn ilgili fonksiyonun kodunun
bulunduu blgeye aktaracak ekilde bir kod retir. Programn ak fonksiyonun kodu iinde
akp bu kodu bitirdiinde, yani fonksiyon icra edildiinde, programn ak yine fonksiyonun
arld noktaya geri dnecektir. Fonksiyon armaya ilikin sentaks da yine aada
aklanacaktr.

Fonksiyonlarn Geri Dn Deerleri (return values)


Bir fonksiyonun yrtlmesi sonunda onu aran fonksiyona dnnde gnderdii deere,
fonksiyonun geri dn deeri (return value) denmektedir. Her fonksiyon bir geri dn deeri
retmek zorunda deildir. Fonksiyonlarn geri dn deerleri farkl amalar iin kullanlabilir;
1. Baz fonksiyonlar tek bir deer elde etmek amacyla tasarlanmlardr. Elde ettikleri deeri
de kendilerini aran fonksiyonlara geri dn deeri olarak iletirler. rnein:
pow fonksiyonu standart bir C fonksiyonudur. Birinci parametresiyle belirtilen saynn ikinci
parametresiyle belirtilen kuvvetini hesaplayarak, hesaplad sayy geri dn deeri olarak
kendisini aran fonksiyona iletir. Yukardaki rnekte 2 saysnn 3. kuvveti bu fonksiyon
yardmyla hesaplanarak bulunan deer y deikenine atanmtr.
2. Baz fonksiyonlarn geri dn deerleri fonksiyonun yrtlmesi srasnda yaplan
ilemlerin baars hakknda bilgi verir. Yani bu tr fonksiyonlarn geri dn deerleri test
amacyla kullanlmaktadr. Geri dn deerleri yaplmas istenen ilemin baarl olup
olmamas durumunu aklar. rnein :
ifadesiyle bellekte 200 byte uzunluunda bir blok tahsis etmek isteyen programc bu
ilemin baarl bir biimde yerine getirilip getirilmediini de test etmek zorundadr. Hemen
arkasndan p deikeninin ald deeri kontrol edecek ve ilemin baars hakknda bir
karara varacaktr. Dolaysyla malloc fonksiyonunun geri dn deeri, fonksiyonun
yapmas gereken iin baarl bir ekilde sonulanp sonulanmadn gstermektedir.

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

void Anahtar Szc


Bir fonksiyonun parametre deikeni ya da geri dn deeri olmak zorunda deildir. Bir
fonksiyonun parametre deikeni olmad iki ekilde belirtilebilir:

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 arlmas (function calls)


C dilinde fonksiyon arma operatr olarak () kullanlmaktadr. Bir fonksiyon arld
zaman programn ak fonksiyonu icra etmek zere bellekte fonksiyonun kodunun bulunduu
blgeye atlar, fonksiyonun icra edilme ilemi bittikten sonra da ak tekrar aran fonksiyonun
kalnan yerinden devam eder.
Bir fonksiyonun geri dn deeri varsa, fonksiyon arma ifadesi geri dn deerini retir.
Geri dn deeri bir deikene atanabilecei gibi dorudan aritmetik ilemlerde de
kullanlabilir. rnein:
Burada hesapla fonksiyonunun arlma
deikenine atanmaktadr. Bir baka deyile
ilgili fonksiyonun rettii (eer retiyorsa)
hesapla() fonksiyonu arlacak daha sonra
deeri sonuc deikenine atanacaktr.

ifadesiyle retilen geri dn deeri sonuc


bir fonksiyon arma ifadesinin rettii deer,
geri dn deeridir. Yukardaki rnekte nce
fonksiyonun icra edilmesiyle oluan geri dn

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

Fonksiyonlar ancak tanmlanm fonskiyonlarn ierisinden arlabilirler. Bloklarn dndan


fonksiyon arlamaz.
aran fonksiyon ile arlan fonksiyonun her ikisi de ayn ama kod ierisinde bulunmak
zorunda deildir. aran fonksiyon ile arlan fonksiyon farkl ama kodlar ierisinde de
bulunabilir. nk derleme ilemi srasnda bir fonksiyonun arldn gren derleyici, ama
kod ierisine (yani .obj iine) arlan fonksiyonun adn ve arl biimini yazmaktadr.
aran fonksiyon ile arlan fonksiyon arasnda balant kurma ilemi, balama aamasnda,
balayc program (linker) tarafndan yaplr.
Bu nedenle tanmlanan bir fonksiyon ierisinde, var olmayan bir fonksiyon arlsa bile
derleme aamasnda bir hata olumaz. Hata balama aamasnda oluur. nk balayc
arlan fonksiyonu bulamayacaktr.
Btn C programlar almaya main fonksiyonundan balar. Programn balad nokta olma
dnda main fonksiyonunun dier fonksiyonlardan baka hibir fark yoktur. main fonksiyonun
icras bitince program da sonlanr. Bir C programnn alabilmesi iin mutlaka bir main
fonksiyonuna sahip olmas gerekir. Eer main fonksiyonu yoksa hata balama (linking)
aamasnda balayc program tarafndan bildirilecektir.

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.

Fonksiyonlarn Geri Dn Deerlerinin Oluturulmas


C dilinde fonksiyonlarn geri dn deerleri return anahtar szc ile oluturulur. return
anahtar szcnn bir baka ilevi de iinde bulunduu fonksiyonu sonlandrmasdr.
41

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 ifadesinin deiken iermesi bir zorunluluk deildir. Bir fonksiyon


sabit bir deerle de geri dnebilir. */

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 :

szc yannda bir ifade

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.

Fonksiyon Parametre Deikenlerinin Tanmlanmas


Bir fonksiyonun parametreleri ya da parametre deikenleri fonksiyonlarn kendilerini aran
fonksiyonlardan aldklar girdileri tutan deikenleridir. Bir fonksiyonun parametre says ve bu
parametrelerin trleri gibi bilgiler, fonksiyonlarn tanmlanmas sarsnda derleyicilere
bildirilirler.
C dilinde fonksiyonlarn tanmlanmasnda kullanlan 2 temel biim vardr. Bu biimler
birbirlerinden fonksiyon parametrelerinin derleyicilere tantlma ekli ile ayrlrlar.
Bu
biimlerden birincisi eski biim (old style) ikincisi ise yeni biim (new style) olarak adlandrlr.
Artk eski biim hemen hemen hi kullanlmamaktadr, ama C standartlarna gre halen
geerliliini korumaktadr. Kullanlmas tavsiye edilen kesinlikle yeni biimdir ancak eski
kodlarn ya da eski kaynak kitaplarn incelenmesi durumunda bunlarn anlalabilmesi iin eski
biimin de renilmesi gerekmektedir.

Eski Biim (old style)


Bu biimde fonksiyonun parametre deikenlerinin yalnzca ismi fonksiyon parantezleri iinde
yazlr. (Eer parametre deikenleri birden fazla ise aralarna virgl koyulur. Daha sonra alt
satra geilerek bu deikenlerin bildirimi yaplr. Bu bildirimler daha nce rendiimiz, C
dilinin bildirim kurallarna uygun olarak yaplr. rnek :
double alan(x, y)
int x, y;
{
return x * y;
}
Yukarda tanmlanan alan fonksiyonunun iki parametre deikeni vardr ve bu parametre
deikenlerinin isimleri x ve y'dir. Her iki parametre deikeni de int trdendir.
int sample (a, b, c)
int a;
double b;
long c;
{
43

...

Bu rnekte ise sample fonksiyonu parametre almaktadr. Parametre deikenlerinin isimleri


a, b ve c'dir. smi a olan parametre deikeni int trden, b olan double trden ve ismi c olan
ise long trdendir.
Eski biimin dezavantaj gereksiz yere uzun oluudur. nk fonksiyon parantezelerinin iinde
parametre deikenlerinin isimi yer almakta sonra tekrar bu isimler alt satrlarda yeniden
kullanlarak bildirim yaplmaktadr.

Yeni Biim (new style)


Yeni biim eski biime gre hem daha ksadr hem de okunabilmesi eski biime gre ok daha
kolaydr.
Yeni biimde fonksiyon parametre deikenlerinin bildirimi fonksiyon parantezelerinin iinde
yalnzca bir kez yaplmaktadr. Bu biimde fonksiyonun parantezlerinin iine parametre
deikenin tr ve yanna da ismi yazlr. Eer birden fazla fonksiyon parametre deikeni
varsa bunlar virgllerle ayrlr ancak her defasnda tr bilgisi yeniden yazlr . rnek :
int sample (int x, int y)
{
...
}
int fonk(double x, int y)
{
...
}
Bu biimde dikkat edilmesi gereken nemli nokta, fonksiyon parametre deikenleri ayn
trden olsalar bile her defasnda tr bilgisinin tekrar yazlmas zorunluluudur. rnein :
int sample (double x, y)
{
...
}

/* error */

bildirimi hataldr. Doru tanmlamann aadaki ekilde olmas gerekir:


int sample (double x, double y)
{
...
}

Klavyeden Karakter Alan C Fonskiyonlar


Sistemlerin hemen hemen hepsinde klavyeden karakter alan 3 ayr C fonksiyonu bulunur. Bu
fonksiyonlarn biri tam olarak standarttr ama dier ikisi sistemlerin hemen hemen hepsinde
bulunmasna karn tam olarak standart deildir.

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

enter tuuna ihtiya duyar


enter tuuna ihtiya duymaz
enter tuuna ihtiya duymaz

alnan karakter ekranda grnr.


alnan karakter ekranda grnmez
alnan karakter ekranda grnr.

45

Ekrana Bir Karakterin Grntsn Yazan C Fonksiyonlar


C dilinde ekrana karakter yazamakta iki fonksiyonun kullanld grlr :

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

int trn desimal sistemde yazar.


long trn desimal sistemde yazar
unsigned int trn hexadecimal sistemde yazar.
unsigned int trn hexadecimal sistemde yazar.(semboller byk harfle)
unsigned long trn hexadecimal sistemde yazar.
unsigned int trn decimal sistemde yazar.
unsigned int trn oktal sistemde yazar.
float ve double trlerini desimal sistemde yazar.
double trn desimal sistemde yazar.
gerek saylar stel biimde yazar.
char veya int trn karakter grnts olarak yazdrr.
string olarak yazdrr.
long double trn desimal sistemde yazdrr.

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

/* u saysn 10'luk sistemde yazar */


/* u saysn 8'lik sistemde yazar */
/* u saysn 16'lk sistemde yazar */

short bir sayy yazarken d o u ya da x karakterlerinden nce h karakterini kullanyoruz :


short int sh;
printf("%hd", sh);

/* 10'luk sistemde yazar */

unsigned short int unsh;


printf("%hu", unsh);
printf("%ho", unsh);
printf("%hx", unsh);

/* 10'luk sistemde yazar */


/* 8'lik sistemde yazar */
/* 16'lk sistemde yazar */

long bir sayy yazarken d o u ya da x karakterlerinden nce l karakterini kullanyoruz :


long int lo;
printf("%ld", lo);

/* 10'luk sistemde yazar */


47

unsigned long int unlo;


printf("%lu", unlo);
printf("%lo", unlo);
printf("%lx", unlo);

/* 10'luk sistemde yazar */


/* 8'lik sistemde yazar */
/* 16'lk sistemde yazar */

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

biiminde bir giri geerli olaca gibi;


5
60
biiminde bir giri de geerlidir. scanf fonksiyonuna gnderilecek dier argumanlar & operatr
ile kullanlmaktadr. & bir gsterici operatrdr. Bu operatr gstericiler konusunda
reneceiz.

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

7 . BLM : NESNELERN FAALYET ALANLARI VE


MRLER
Daha nce C dilinde nesnelerin 3 ayr zelliini grmtk. Bunlar nesnelerin isimleri, deerleri
ve trleriydi. Nesnelerin C dili asndan ok nem tayan iki zellikleri daha sz konusudur.
Bunlar tannabilirlik alanlar (scope) ve mrleridir (storage duration). Bu dersimizde bu iki
kavram detayl olarak inceleyeceiz.

Tannabilirlik Alan (scope / visibility)


Tannabilirlik alan bir nesnenin mrn srdrd ve tannabildii program araldr. Burada
program aral demekle kaynak kodu kastediyoruz. Dolaysyla tannabilirlik alan dorudan
kaynak kod ile ilgili bir kavramdr, dolaysyla derleme zamanna ilikindir. C dilinde derleyici,
bildirimleri yaplan deikenlere kaynak kodun ancak belirli blmlerinde ulalabilir. Yani bir
deikeni tanmlyor olmamz o deikene kodun istediimiz
bir yerinde ulaabilmemizi
salamaz. Tannabilirlik alanlarn 2 ayr grupta toplayabiliriz :
Blok tannabilirlik alan. (Block scope): Bir deikenin tanmlandktan sonra, derleyici
tarafndan, yalnzca belirli bir blok iinde tannabilmesidir.
Dosya tannabilirlik alan (File scope) : Bir deikenin tanmlandktan sonra tm kaynak dosya
iinde, yani tanmlanan tm fonksiyonlarn hepsinin ierisinde tannabilmesidir.
Deikenleri de tannabilirlik alanlarna gre ikiye ayrabiliriz :
Yerel deikenler (local variables)
Global deikenler (global variables)
C dili iin ok nemli olan bu deiken tiplerini imdi detayl olarak inceleyeceiz :

Yerel Deikenler (local variables)

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

x deikeninin tannabilirlik alan


y deikeninin tannabilirlik alan
z deikeninin tannabilirlik alan

50

NESNELERN FAALYET ALANLARI VE MRLER


Yukardaki rnekte tanmlanan deikenlerden hepsi yerel deikenlerdir. nk x y z
deikenleri bloklarn ilerinde tanmlanmlardr. Bu deikenlere yalnzca tanmlanm
olduklar blok iinde ulaabiliriz. Tanmlandklar blok dnda bunlara ulamaya almak
derleme aamasnda error ile neticelenecektir.
Dikkat etmemiz gereken bir nokta da udur : Yukardaki rnekte bu deikenlerin hepsi yerel
deikenler olduklar iin blok tannabilirlik alan kuralna uyarlar, ancak bu tannabilirlik
alanlarnn tamamen ayn olmasn gerektirmez. Yukardaki ekilden de grld gibi x
deikeni en geni tannabilirlik alanna sahipken y deikeni daha kk ve z deikeni de en
kk tannabilirlik alanna sahiptir.
Yukardaki rnei geniletelim :
main ()
{
float x = 2.5;
printf(x = %f\n, x); /* LEGAL BU ALANDA xE ULAILABLR */
printf(y = %d\n, y); /* ERROR BU ALANDA yYE ULAILAMAZ. */
printf(z = %ld\n, z); /* ERROR BU ALANDA zYE ULAILAMAZ. */
{
int y = 1;
printf(x = %f\n, x);
printf(y = %d\n, y);
printf(z = %ld\n, z);
...
...

/* LEGAL BU ALANDA xE ULAILABLR */


/* LEGAL BU ALANDA yE ULAILABLR */
/* ERROR BU ALANDA zYE ULAILAMAZ. */

{
long z = 5;

}
}

printf(x = %f\n, x);


printf(y = %d\n, y);
printf(z = %ld\n, z);

/* LEGAL BU ALANDA xE ULAILABLR */


/* LEGAL BU ALANDA xE ULAILABLR */
/* LEGAL BU ALANDA xE ULAILABLR */

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

Bu durum error oluturmasayd, yukardaki rnekte derleyici hangi a deikeninin yazdrlmak


istendiini nasl anlayacakt. Zira bu durum error ile engellenmeseydi printf fonksiyonunun
arld yerde her iki a deikeni de tannabilir olacakt.
C dilinde farkl tannabilirlik alanlarna sahip birden fazla ayn isimli deiken tanmlanabilir.
nk derleyiciler iin artk bu deikenlerin ayn isimli olmas nemli deildir. Bunlar bellekte
farkl yerlerde tutulurlar.
{
int x = 100;
printf(%d\n, x);
{
int x = 200;
printf(%d\n, x);
{
int x = 300;
}
}

printf(%d\n, x);

Yukardaki program parasnda bir hata bulunmamaktadr. nk her x deikeninin de


tannabilirlik alanlar birbirlerinden farkldr. Peki yukardaki rnekte ierideki bloklarda x ismini
kullandmzda derleyici hangi x deikenini kast ettiimizi nasl anlayacak? Belirli bir kaynak
kod noktasnda, ayn isimli birden fazla deikenin faaliyet alan (scope) iindeysek, deiken
ismini kullandmzda derleyici hangi deikene ulaacaktr? Ayn isimli deikenlere ulama
konusundaki kural udur : C dilinde daha dar faaliyet alanna sahip deiken dier ayn isimli
deikenleri maskeler.
Konunun daha iyi anlalmas iin bir ka rnek daha verelim :
{

}
{

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

NESNELERN FAALYET ALANLARI VE MRLER

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.

Global Deikenler (global variables)


C dilinde tm bloklarn dnda da deikenlerin tanmlanabileceini sylemitik. te btn
bloklarn dnda tanmlanan deikenler global deikenler olarak isimlendirilirler.
Btn bloklarn d kavramn daha iyi anlamak iin bir rnek verelim :
#include <stdio.h>
/* bu blge tm bloklarn d burada global bir deiken tanmlanabilir. */
int sample1()
{
...
}
/* bu blge tm bloklarn d burada global bir deiken tanmlanabilir. */
int sample2()
{
...
}
/* bu blge tm bloklarn d burada global bir deiken tanmlanabilir. */
int sample 3()
{
...
}
/* bu blge tm bloklarn d burada global bir deiken tanmlanabilir. */
main()
{
...
}
/* bu blge tm bloklarn d burada global bir deiken tanmlanabilir. */
Yorum satrlarnn bulunduu yerler global deikenlerin tanmlanabilecei yerleri
gstermektedir. Bu blgeler hibir fonksiyon iinde deidir. Global deikenler dosya
tannabilirlik alan kuralna uyarlar. Yani global deikenler programn her yerinde ve btn
53

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

/* y bir global deiken tanmlandktan sonra her yerde tannabilir */

/*baka bir fonksiyondan da y global deikenine ulalabilir */

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;

/* g global bir deiken */

void sample(void)
{
g = 100;
printf(global g = %d\n, g);
}

/* global g deikenine atama yaplyor. */


/* global g yazdrlyor. */

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

NESNELERN FAALYET ALANLARI VE MRLER

Fonksiyonlarn kendileri de btn bloklarn balarnda tanmlandklarna gre global nesnelerdir.


Gerekten de fonksiyonlar kaynak kodun heryerinden arlabilirler. Ayn tannabilirlik alanna
ilikin ayn isimli birden fazla deiken olamayacaana gre , ayn isme sahip birden fazla
fonksiyon da olamaz. (C++ dilinde ayn isimli fakat farkl parametrik yapya sahip fonksiyonlar
tanmlamak mmkndr.)
Programclarn ou global deikenleri mmkn olduu kadar az kullanmak ister. nk
global deikenleri kullanan fonksiyonlar
baka projelerde kullanlamazlar. Kullanldklar
projelerde de ayn global deikenlerin tanmlanm olmas gerekecektir. Dolaysyla global
deikenlere dayanlarak yazlan fonksiyonlarn yeniden kullanlabilirlii azalmaktadr.

Parametre Deikenleri (formal parameters)


Parametre deikenleri, fonksiyon parametreleri olarak kullanlan deikenlerdir. Parametre
deikenleri de blok tannabilirlik alan kuralna uyarlar. Yani parametresi olduklar fonksiyonun
her yerinde tannabilirler. Fonksiyon parametre deikeninin scope'u fonksiyonun ana blounun
kapanmasyla sonlanacaktr. Yani fonksiyon parametre deikeninin tannabilirlik alan
fonksiyonun ana bloudur.
function(int a, double b)
{
/ *a ve b bu fonksiyonun heryerinde tannr. */
}
Baka bir rnek :
sample (int a, int b)
{
int a;
/* hata ayn tannrlk alan iinde ve ayn seviyede ayn isimli deiken */
...
{
int b;
/* hata deil tannabilirlik alanlar farkl */
...
}
}
Bu rnekte fonksiyonun ana blounun banda tanmlanm olan a, ayn tannabilirlik alannda
ayn blok seviyesinde ayn isimli birden fazla deiken olamaz kuralna gre geersizdir. Biri
parametre deikeni biri yerel deiken olmasna karn, her iki a deikeni ayn tannabilirlik
alanna sahiptir.

Nesnelerin mrleri (storage duration / lifespan)


mr, nesnelerin faaliyet gsterdii zaman araln anlatmak iin kullanlan bir kavramdr. Bir
kaynak kod iinde tanmlanm nesnelerin hepsi program almaya baladnda ayn zamanda
yaratlmazlar. mrleri bakmndan nesneleri iki gruba ayrabiliriz :
1. Statik mrl nesneler (static objects)
2. Dinamik mrl nesneler (dynamic / automatic objects)

Statik mrl Nesneler (static duration static storage class)


Statik mrl nesneler, programn almaya balamasyla yaratlrlar, programn almas
bitene kadar varlklarn srdrrler, yani bellekte yer kaplarlar. Statik nesneler genellikle
ama kod (.obj) ierisine yazlrlar.
C dilinde statik mrl 3 nesne grubu vardr :

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.

Dinamik mrl Nesneler


Dinamik mrl nesneler programn almasnn belli bir zamannda yaratlan ve belli sre
faaliyet gsterdikten sonra yok olan (mrlerini tamamlayan) nesnelerdir. Bu tr nesnelerin
mrleri programn toplam alma sresinden ksadr.
C dilinde dinamik mrl nense grubu vardr :
yerel deikenler
parametre deikenleri
dinamik bellek fonksiyonlar ile tahsisat yaplarak yaratlm nesneler
dinamik bellek fonskiyonlar ile yaratlm nesneleri daha sonra inceleyeceiz.
Yerel deikenler ve parametre deikenleri dinamik mrl nesnelerdir. Tanmlandklar
bloun almas baladnda yaratlrlar, bloun almas bitince yok olurlar (mrleri sona
erer.) Tannabilirlik alanlar kendi bloklarnn uzunluu kadar olan yerel deikenlerin mrleri,
program aknn bu bloa gelmesiyle balar ve bloun alma sresi bitince de sona erer .
rnek :
{

double x; /* programn ak bu noktaya geldiinde bellekte x iin bir yer


blok iinde a yaamaya devam ediyor.*/
...
/* programn ak bloun sonuna geldiinde a deikeninin de
mr sona eriyor */

ayrlyor. ve

Fonksiyonlarn parametre deikenleri de benzer biimde fonksiyon arldnda yaratlrlar,


fonksiyon icras boyunca yaarlar, fonksiyonun icras bitince yok olurlar.
Statik deikenlerle dinamik deikenler arasnda ilk deer verme(initialization) asndan da
fark bulunmaktadr. Statik olan global deikenlere de yerel deikenlerde olduu gibi ilk deer
verilebilir.
lk deer verilmemi ya da bir atama yaplmam bir yerel deikenin iinde rasgele bir deer
bulunur. Bu deer o an bellekte o deiken iin ayrlm yerde bulunan rasgele bir saydr.
(garbage value). Oysa ilk deer verilmemi, ya da bir atama yaplmam global deikenler
iinde her zaman 0 deeri vardr. Yani bu deikenler 0 deeriyle balatlrlar.
Aadaki ksa program derleyerek altrnz :
#include <stdio.h>
int globx;
int main()
{
int localy;

56

NESNELERN FAALYET ALANLARI VE MRLER


printf("globx = %d\n", globx);
printf("localy = %d\n", localy);
return 0;
}
Yerel deikenler ile global deikenler arasndaki baka bir fark da, global deikenlere ancak
sabit ifadeleriyle ilk deer verilebilmesidir. Global deikenlere ilk deer verme ileminde
kullanlan ifadede (initializer), deikenler ya da fonksiyon arma ifadeleri kullanlamazlar,
ifade yalnzca sabitlerden olumak zorundadr. (C++ dilinde byle bir zorunluluk
bulunmamaktadr.)
Ancak yerel deikenlere ilk deer verilme ileminde byle bir kstlama bulunmamaktadr.
rnek :
#include <stdio.h>
int x = 5;
int y = x + 5;
int z = funk();

/* 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()
{
...
}

Argumanlarn Parametre Deikenlerine Kopyalanmas


C dilinde bir fonksiyonun parametre deikenlerinin tanmlandklar fonksiyon iinde her yerde
tannabildiklerini sylemitik. Peki bir fonksiyonun parametre deikenleri ne ie yararlar?
Bir fonksiyonun parametre deikenleri, o fonksiyonun arlma ifadesiyle kendisine
gnderilen argumanlar tutacak olan yerel deikenlerdir. rnek :
fonk(int a)
{
.....
}
main()
{
int x;
....
fonk (x);
}
Yukardaki rnekte fonk fonksiyonu x arguman ile arldnda, programn ak fonk
fonksiyonunun kodunun bulunduu yere srar, fonk fonksiyonundaki a isimli parametre
deikeni iin bellekte bir yer ayrlr ve a parametre deikenine x deikeninin deeri atanr.
Yani
a = x;
57

ileminin otomatik olarak yapldn syleyebiliriz.


Baka bir rnek verelim :
#include <stdio.h>
main()
{
int x = 100, y = 200, z;
z = add(x, y);
printf("%d\n", z);
return 0;
}
int add(int a, int b)
{
return a + b;
}
add fonksiyonu arldnda programn ak bu fonksiyona gemeden nce, x ve y
deikenlerinin iinde bulunan deerler add fonksiyonunun parametre deikenleri olan a ve
b'ye kopyalanrlar.

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

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


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

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)

C Dilinin Operatr ncelik Tablosu


Seviye

Operatr

Tanm

()
[]
.
->
+
++
-~
!
*
&
sizeof
(tr)
*
/
%
+
<<
>>
<
>
<=
>=
==
!=
&
^
|
&&
||
?:
=
+=
-=
*=
/=
%=
<<=
>>=
&=
|=
^=
,

ncelik kazandrma ve fonksiyon arma


index operatr (subscript)
yap elemanna ulam (structure access)
yap elemanna gsterici ile ulam
iaret operatr (unary)
iaret operatr (unary)
1 artrma (increment)
1 eksiltme (decrement)
bitsel deil (bitwise not)
mantksal deil (logical not)
ierik operatr (indirection)
adres operatr (address of)
sizeof operatr
tr dntrme (type cast operator)
arpma (multiplication)
blme (division)
modulus (blmden kalan)
toplama (addition)
karma (suntraction)
bitsel sola kaydrma (bitwise shift left)
bitsel saga kaydrma (bitwise shift right)
kktr (less than)
byktr (greater than)
kk eittir (less than or equal)
byk eittir (greater than or equal)
eittir (equal)
eit deildir (not equal to)
bitsel VE (bitwise AND)
bitsel EXOR (bitwise EXOR)
bitsel VEYA (bitwise OR)
mantksal VE (logical AND)
mantksal VEYA (logical OR)
koul operatr (conditional operator)
atama (assignement)
ilemli atama (assignment addition)
ilemli atama (assignment subtraction)
ilemli atama (assignment multiplication)
ilemli atama (assignment division)
ilemli atama (assignment modulus)
ilemli atama (assignment shift left)
ilemli atama (assignment shift right)
ilemli atama (assignment bitwise AND)
ilemli atama (assignment bitwise OR)
ilemli atama (assignment bitwise EXOR)
virgl operatr (comma)

3
4
5
6

7
8
9
10
11
12
13
14

15

3. Araek Konumundaki Operatrler (infix operators)


Bu tip operatrler operandlarnn aralarna getirilirler.
rnein aritmetiksel toplama operatr (x + y)

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.

Aritmetik operatrler (arithmetic operators)


likisel operatrler (relational operators)
Mantksal operatrler (logical operators)
Gsterici operatrleri (pointer operators)
Bitsel ilem yapan operatrler (bitwise operators)
zel amal operatrler (special purpose operators)

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 Deer retmeleri

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.

Operatrlerin Yan Etkileri (side effect of operators)


C dilinde operatrlerin ana ilevleri, bir deer retmeleridir. Ancak baz operatrler operand
olan nesnelerin deerlerini deitirirler. Yani bu nesnelerin bellekteki yerlerine yeni bir deer
yazlmasna neden olurlar. Bir operatrn kendilerine operand olan nesnenin deerlerini
deitirmesine operatrn yan etkisi diyeceiz. Yan etki, bellekte yaplan eer deiiklii olarak
tanmlanmaktadr. rnein atama operatrnn, ++ ve -- operatrlerinin yan etkileri sz
konusudur.

Operatrler zerindeki Kstlamalar


Programlama dilinin tasarmnda, baz operatrlerin kullanlmalaryla ilgili birtakm kstlamalar
sz konusu olabilir. rnein ++ operatrnn kullanmnda, operandn nesne gsteren bir ifade
olmas gibi bir kstlama sz konusudur. Eer operand olan ifade bir nesne gstermiyorsa, yani
sol taraf deeri deilse, derleme zamannda hata oluacaktr.
Kstlama operatrn operand ya da operandlarnn trleriyle de ilgili olabilir. rnein %
operatrnn operandlarnn tamsay trlerinden birine ait olmas gerekmektedir. %
operatrnn operandlar gerek say trlerinden birine ait olamaz. Operandn gerek say
trlerinden birinden olmas durumunda derleme zamannda hata oluacaktr.

Operatrlerin Detayl Olarak ncelenmesi


Aritmetik Operatrler
Aritmetik operatrler drt ilemlerle ilgili ilem yapan operatrlerdir.
+ ve - Operatrleri. (toplama ve karma operatrleri)
ki operand alan araek operatrlerdir. (binary infix) Dier btn programlama dillerinde
olduklar gibi operandlarnn toplamn ve farkn almak iin kullanrlar. Yani rettikleri deer,
operandlarnn toplam ya da fark deerleridir. Operandlar zerinde herhangi bir kstlama
yoktur. ncelik tablosundan da grlecei gibi genel ncelik tablosunun 4. srasnda yer alrlar
ve ncelik ynleri soldan saadr (left associative). Yan etkileri yoktur, yani operandlarnn
bellekte sahip olduklar deerleri deitirmezler.
Toplama ve karma operatrleri olan + ve operatrlerini tek operand alan + ve
operatrleriyle kartrmamak gerekir.
aret Operatr Olan ve + Operatrleri
Bu operatrler unary prefix (tek operand alan nek konumundaki) operatrlerdir. - operatr
operand olan ifadenin deerinin ters iaretlisini retir. Unary prefix operatrnn rettii bir
nesne deil bir deerdir. Aadaki ifade matematiksel olarak doru olmasna karn C dili
asndan hataldr, derleme zamannda hata (error) oluumuna neden olur:
int x;
-x = 5;

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;

/* burada c'ye 3 deeri atanacaktr */

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

*/

Burada derleyiciler x = a++ + b;ilemlerini yapabilecei gibi x = a+ ++b; ilemlerini de


yapabilirler.
Bir ifadede bir deiken ++ ya da operatrleriyle kullanlmsa, o deiken o ifadede
bir kez daha yer almamaldr. rnein aadaki ifadelerin hepsi pheli kodlardr :
int x = 20, y;

65

y = ++x + ++x;
y = ++x + x
a = ++a;

/* pheli kod */
/* pheli kod */
/* pheli kod */

Bir fonksiyon arlrken parametrelerden birinde bir deiken ++ ya da ile kullanlmsa


budeiken dier parametrelerde gzkmemelidir.
Argumanlarm patrametre deikenlerine kopyalanma sras standart bir biimde
belirlenmemitir. Bu kopyalama ilemi baz sistemlerde soldan saa baz sistemlerde ise
sadan soladr. rnek :
int a = 10;
fonk (a, a++);

/* pheli kod fonk fonksyinuna 10, 10 deerleri mi 11, 10 deerleri mi


nderiliyor? */

void fonk(x, y)
{
...
}

Karlatrma Operatrleri (ilikisel operatrler)


C programlama dilinde toplam 6 tane karlatrma operatr vardr:
<
>
<=
>=
==
!=

kktr (less than)


byktr (greater than)
kk eit (less than or equal)
byk eit (greater than or equal)
eittir. (equal)
eit deildir. (not equal)

Bu operatrlerin hepsi iki operand alan araek operatrlerdir. (binary infix)


Operatr ncelik tablosuna bakldnda, karlatrma operatrlerinin aritmetik operatrlerden
daha sonra geldii yani daha dk ncelikli olduklar grlr. Karlatrma operatrleri kendi
aralarnda iki ncelik grubu biiminde bulunurlar.
Karlatrma operatrleri bir nerme olutururlar ve sonu ya doru ya da yanl olur.
Karlatrma operatrlerinden elde edilen deer , nerme doru ise 1 nerme yanl ise 0
deeridir ve int trdendir. Bu operatrlerin rettii deerler de tpk aritmetik operatrlerin
rettii deerler gibi kullanlabilirler. rnekler :
#include <stdio.h>
int main()
{
int x = 5;
...
y = (x > 5) + 1;
printf("%d\n", y);
funk(y >= x);
return 0;
}
Yukardaki rnekte ekrana 1 deeri yazdrlacaktr. Daha sonra da funk fonksiyonu 0 deeriyle
arlacaktr.

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.

Mantksal Operatrler (logical operators)

Bu operatrler operandlar zerinde mantksal ilem yaparlar. Operandlarn Doru (true) ya da


Yanl(false) olarak yorumladktan sonra ileme sokarlar. Cde dilinde ncelikleri farkl seviyede
olan (tabloya baknz) mantksal operatr vardr:
! deil operatr (not)
&& Ve operatr (and)
|| veya operatr (or)
Tablodan da grlecei gibi && ya da || operatrlerin ayn ifade iinde birden fazla kullanlmas
durumunda ncelik yn soldan saadr, 2. seviyede bulunan ! operatr iin ise ncelik yn
sadan soladr.
Cde mantksal veri tr yoktur. Mantksal veri tr olmad iin bunun yerine int tr
kullanlr ve mantksal doru olarak 1 mantksal yanl olarak da 0 deeri kullanlr.
C dilinde herhangi bir ifade mantksal operatrlerin operand olabilir. Bu durumda sz konusu
ifade mantksal olarak yorumlanr. Bunun iin ifadenin saysal deeri hesaplanr. Hesaplanan
saysal deer 0 d bir deer ise doru (1), 0 ise yanl (0) olarak yorumlanr. rnein:
25 Doru (nk 0 d bir deer)
-12 Doru (nk 0 d bir deer)
0 Yanl (nk 0)
int x = 5;
x * x 25
fadesi mantksal bir operatrn operand olduu zaman yanl olarak yorumlanacaktr. nk
saysal deeri 0a eittir.
! Operatr

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

/* a deikenine 0 deeri atanr */

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

zel Amal Operatrler


Bu blmde zel amal operatrlerden atama, ilemli atama, ncelik ve virgl operatrlerini
inceleyeceiz.
Atama Operatr (assignment operator)
Atama operatr C dilinde ncelik tablosunun en alttan ikinci seviyesinde bulunur ve yalnzca
virgl operatrnden daha yksek nceliklidir. Her operatr bir deer retir ve atama
operatr de yapt atama ileminin yansra bir deer retir. Atama operatrnn rettii
deer sa taraf deerinin kendisidir. rnein:
if (a = 20) {
...
}
Burada srasyla unlar olur :
1. 20 says x deikenine atanr.
2. Bu ilemden 20 says retilir.
3. 20 sfr d bir say olduu iin if deyimi doru olarak deerlendirilir.
Atama operatrnn rettii deer nesne deildir. dolaysyla;
(b = c) = a;

/* ifadesi Cde geerli bir deyim deildir. */

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;

katsayi = katsayi * (a * b + c * d) ifadesi de yine


katsayi *= a * b + c * d; eklinde yazlabilir.
var1 = 3;
var2 = 5;
var1 += var2 *= 3; ifadesinde var2 = var2 * 3 ilemiyle nce var2 deikenine 15 deeri
atanacak ve ilem sonucunda 15 deeri retilecek var1 = var1 + 15 ilemiyle var1 deikenine
18 deeri atanacaktr.

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;

if (var * 5 < 50)


deyim1;
else
deyim2;
deyim3;

1. adm : if parantezi iindeki ifadenin saysal deeri hesaplanacak :


15 < 50
sonu 1 (doru)
2. adm : deyim1 icra edilecek.
3. adm : daha sonra else ksm atlanarak deyim3 icra edilecek.
if parantezi ierisindeki ifadeler karmak yapda da olabilir :
...
char ch = Q;
if (ch >= a && ch <= z)
printf(%c\n, ch);
else
printf(kk harf deil\n);

ch = A;

Yukardaki if deyimi ile ch karakterinin kk harf olup olmad test edilmektedir. ch


karakterinin kk harf olmas durumunda bu karakter ekrana baslacak, aksi durumda ekrana
kk harf deil mesaj yazlacaktr. Her iki durumdada programn ak
ch = A;
atama deyimiyle devam edecektir.
73

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

Aadaki rnei inceleyelim :


if (!x) {
deyim1;
deyim2;
....
}

Bu if deyiminde ise ancak x deikeninin deerinin 0 olmas durumunda deyim1 ve deyim2


icra edilecektir.
Yine 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;

if Deyiminin Kullanlmasna likin Sk Yaplan Hatalar


if parantezinin sonuna yanllkla ; yerletirilmesi:
...
if (x > 5);
printf("doru!\n");
...
Yukardaki rnekte x > 5 ifadesi doru da yanl da olsa printf fonksiyonu arlacaktr. Zira
printf arm if deyiminin dndadr. if deyiminin doru ksmn bir bo deyim (Null
statement) oluturmaktadr. Ayn nedenden dolay aadaki kod derleme zamannda error
oluumuna neden olacaktr :
...
if (x > 5);
printf("doru!\n");
else
printf("yanl\n");
...
if anahtar szc olmayan bir else anahtar szc:
Tabi ki bir if deyiminin doru ya da yanl ksmn bir ; (bo deyim - null statement)
oluturabilir. Bu durumda okunabilirlik asndan bu bo deyim bir tab ieriden yazlmaldr:
...
if (funk())
;
else
x = 5;
if parantezi ierisinde karlatrma operatr (==) yerine yanllkla atama operatrnn (=)
kullanlmas
...
if (x == 5)
printf("eit\n");
...
Yukardaki if deyiminde x deikeninin deeri eer 5'e eitse printf fonksiyonu arlacaktr.
Operatrler konusunda da deindiimiz gibi karlatrma operatrnn yan etkisi yoktur, yani
yukardaki if parantezi ierisinde x deikeninin deeri yalnzca 5 sabiti ile karlatrlmakta,
deikenin deeri deitirilmemektedir. Oysa karlatrma operatrnn yerine yanllkla
atama operatr kullanlrsa:
...

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

if Deyiminin Kullanld rnek Uygulamalar


islower Fonksiyonu
islower standart bir C fonksiyonudur. Parametresi olan karakter, kk harf karakterlerinden
biri ise Doru (sfr d bir deer), deilse Yanl (sfr) deerine geri dner. Bu fonksiyonu
aadaki ekilde yazabiliriz :
#include <stdio.h>
int _islower (int ch)
{
if (ch >= a && ch <= z)
return ch:
return 0;
}
main()
{
char ch;

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.

Karakter Test Fonksiyonlar


Karakter test fonksiyonlar karakterler hakknda bilgi edinmemizi salayan fonksiyonlardr. Bu
fonksiyonlarn hepsi ctype.h balk dosyas iinde makro olarak bulunurlar. Bu nedenle karakter
test fonksiyonlar kullanlmadan nce kaynak koda mutlaka ctype.h dosyas dahil edilmelidir.
Karakter test fonksiyonlar ASCII karakter setinin ilk yars iin geerlidir, yani trke
karakterler iin kullanlmas durumunda geri dn deerleri gvenilir deildir.
C dilinindeki standart karakter test fonksiyonlar:
fonksiyon
isalpha
isupper
islower
isdigit
isxdigit
isalnum

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

Boluk karakterlerinden biriyse(space, carriage return, new line,


vertical tab, form feed) Doru deilse Yanl
Noktalama karakterlerinden biriyse (kontrol karakterleri, alfanmerik
karakterler ve boluk karakterlerinin dndaki karakterler) Doru
deilse Yanl
Ekranda grlebilen (print edilebilen) bir karakterse (space karakteri
dahil) Doru, deilse Yanl.
Ekranda grlebilen bir karakterse (space dahil deil) Doru deilse
yanl
Kontrol karakteri ya da silme karakteri ise (lk 32 karakter ya da 127
numaral karakter) Doru deilse Yanl
ASCII tablosunun standart ksm olan ilk 128 karakterden biriyse
Doru deilse Yanl

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;

printf("0 ile 15 arasnda bir say giriniz : ");


scanf("%d", &number);
printf("hexadesimal digit karl = %c\n", get_hex_char(number));
return 0;

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

if (digit >= '0' && digit <= '9')


return digit - '0';
if (digit >= 'A' && digit <= 'F')
return digit - 'A' + 10;

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;

printf("bir karakter giriniz : ");


kar = getchar();
kar = change_case(kar);
putchar(kar);
getch();
return 0;

change_case fonksiyonunu
tanmlayabilirdik :

standart

fonksiyonlarn

kullanarak

int change_case(int ch)


{
if (isupper(ch))
return tolower(ch);
return toupper(ch);
}
kinci dereceden bir denklemin zm kmesini bulan bir program :
#include <stdio.h>
#include <math.h>
main()

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

10 . BLM : FONKSYON PROTOTPLER


C programlama dilinde, bir fonksiyonun arlmas durumunda derleyiciler fonksiyonun geri
dn deerinin trn bilmek zorundadr. C derleyicileri fonksiyonlarn geri dn deerlerini
CPU yazmalarndan (registers) alrlar ve aslnda geri dn deeri tr, deerin hangi
yazmatan alnacan gsterir.
Eer arlan fonksiyonun tanmlamas, fonksiyon arma ifadesinden daha nce yer alyorsa,
derleyici derleme ilemi srasnda fonksiyon arma ifadesine gelmeden nce, arlan
fonksiyonun geri dn deeri tr hakknda zaten bilgi sahibi olacaktr. nk derleme ilemi
yukardan aa doru yaplr.
# include <stdio.h>
float calculate(float x, float y)
{
return x * y / (x + y);
}
int main()
{
float a, b, c;

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.

Fonksiyon Prototip Bildirimlerinin Genel Biimi


[geri dn deeri tr] <fonksiyon ismi> ([tr1], [tr2].....);
rnein calculate fonksiyonu iin prototip aadaki biimde yazlabilir:
float calculate(float, float);
Derleyici byle bir prototip bildiriminden calculate fonksiyonunun geri dn deerinin trnn
float olduunu anlayacaktr.
Birka rnek daha verelim:
int multiply (int, int);
double pow (double, double);
void clrscr(void);
Tpk fonksiyon tanmlamalarnda olduu gibi, fonksiyon prototip bildirimlerinde de,
fonksiyonun geri dn deeri belirtilmemise, derleyici bildirimin int trden bir geri dn
deeri iin yapldn anlayacaktr.
func(double);

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

Fonksiyon Prototiplerinin Bildirim Yerleri


Fonksiyon prototiplerinin bildirimi programn herhangi bir yerinde yaplabilir. Prototipler
bildirimleri global dzeyde yaplmsa (yani tm bloklarn dnda yaplmsa) bildirildikleri
yerden dosya sonuna kadar olan alan iinde geerliliklerini srdrrler. nemli olan nokta sz
konusu fonksiyon arlmadan bildiriminin yapm olmasdr.
Ancak uygulamalarda ok az raslanmasna karlk, fonksiyon prototipleri yerel dzeyde de
yaplabilir. Bu durumda prototip bildirimi ile , yalnzca bildirimin yaplm olduu bloa bilgi
verilmi olur. Baka bir deyile prototip bildirimi de, deiken tanmlamalar gibi faaliyet alan
kuralna uyar.

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.

Standart C Fonksiyonlarnn Prototipleri


Standart C fonksiyonlarnn prototipleri standart balk dosyalar iine yerletirilmitir.
Programc, uygulamalarda standart bir C fonksiyonunun prototipini kendi yazmaz, bu prototip
bildiriminin
bulunduu balk dosyasn #include nilemci komutuyla (ileride detayl
greceiz) koda dahil eder.
Standart C fonksiyonlarnn prototip bildirimlerinin yaplmamas durumda hata ortaya kmaz.
Eer geri dn deeri tr int deilse ve geri dn deeri kullanlrsa, programda yanllk
sz konusu olacaktr.
Derleme zamannda hata oluumu sz konusu deildir, nk derleyici fonksiyonun geri dn
deerinin trn int trden kabul edecek fakat daha sonra kaynak kod iinde fonksiyonun
tanmlamasn gremediinden hata olumayacaktr. Ancak programn alma zaman srasnda
fonksiyonun geri dn deeri int trden bir deer olarak alnacandan yanllk sz konusu
olacak ve program doru almayacaktr.
Standart C fonksiyonlarnn prototipleri sonu .h uzantl olan (header) balk dosyalar iindedir.
nilemci komutuyla ilgili balk dosyasnn kaynak koda ilave edilmesiyle, aslnda standart C
fonksiyonunun da prototip bildirimi yaplm olmaktadr. Zira nilemci modlnn kts olan
kaynak program artk derleyiciye verildiinde, ekleme yaplm bu dosyada fonksiyonun
prototip bildirimi de bulunmaktadr. phesiz, balk dosyay kaynak koda ilave etmek yerine
standart C fonksiyonunun prototipini kendimiz de kaynak koda yazabiliriz, bu durumda da bir
yanllk sz konusu olmayacaktr. rnek :
Standart bir C fonksiyonu olan pow fonksiyonunun
ekleyebiliriz:

prototipini iki ekilde kaynak koda

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

Fonksiyon Prototip Bildirimi le Arguman-Parametre Uyumu Kontrol


Fonksiyon prototiplerinin ana amac yukarda da belirtildii gibi, derleyiciye fonksiyonun geri
dn deeri tr hakknda bilgi vermektir. Ancak fonksiyon prototip bildirimlerinde fonksiyon
parametrelerinin trleri belirtilmise, derleyici prototip bildirimindeki parametre deikeni
saysn fonksiyon arma ifadesindeki fonksiyona gnderilen arguman says ile karlatrr.
rnein:
float calculate(float, float);
biiminde bir prototip yazldnda eer calculate fonskiyonu eksik ya da fazla parametre ile
arlrsa derleme hatas oluacaktr.
89

10
x = calculate(5.8);
y = calculate(4.6, 7.9, 8.0)

/* hata eksik parametre ile arlm */


/* hata fazla parametre ile arlm */

Fonksiyon prototip bildiriminde parantezin ii bo braklrsa (buraya hibir parametre tr bilgisi


yazlmazsa) bu durumun zel bir anlam vardr. Bu durumda derleyiciden parametre kontrolu
yapmas istenmemi olur. (Derleyici artk fonksiyon arma ifadesindeki arguman saysyla
fonksiyonun formal parametrelerinin saysnn eitliini kontrol etmez.) Parametre kontrolu
yaplmasnn istenmemesi uygulamalarda sk grlen bir durum deildir. Parametre
deikenlerinin says ile fonksiyona gnderilen arguman saysnn uyumu kontrol, C diline
standartlarma almalar srasnda eklenmitir. Klasik C diye adlandrdmz, C dilinin
standartlatrlmasndan nceki dnemde byle bir kontrol sz konusu deildi ve prototip
bildirimlerinde fonksiyon parantezlerinin ii bo braklrd. Geriye doru uyumun korunmas ve
eskiden yazlm kaynak kodlarn da desteklenmesi amacyla, fonksiyon prototip bildirimlerinde
fonksiyon parantezlerinin iinin bo braklmas durumu halen geerli bir ilem olarak
braklmtr.
float calculate(); /* derleyiciden parametre kontrol yapmamas isteniyor */
Yukardaki bildirimden calculate fonksiyonunun parametre almad anlam kmaz. Yukardaki
bildirimden sonra eer calculate fonksiyonu aadaki ifadelerle arlrsa derleme zaman
hatas olumayacaktr:
x = calculate (5.8);
y = calculate (4.6, 7.9, 8.0)

/* derleme zamannda hata olumaz */


/* derleme zamannda hata olumaz */

Eer fonksiyonun gerekten parametre deikeni yoksa, ve derleyicinin fonksiyonun arlmas


durumunda arguman parametre deikeni kontrolu yapmas isteniyorsa, prototip bildiriminde
fonksiyon parantezi ierisine void anahtar szc yazlmaldr.
float sample(void);
Burada sample fonksiyonunun parametre almad bildirilmitir. Eer fonksiyon
x = sample(20);

/* derleme hatas */

fadesiyle arlrsa derleme hatas oluur.


(C++ dilinde fonksiyon prototip bildiriminde, fonksiyon parametre parantezinin iinin bo
braklmas, fonksiyonun parametre deikeni olmadn gstermektedir. Baka bir deyile,
prototip bildirimi srasnda parantezlerin iini bo brakmak, derleyiciden arguman says
kontrolu yapmasn istememek anlamna gelmez. C++'da arguman says ile parametre
deilenlerinin saysnn uyumu daima derleyici tarafndan kontrol edilir. Dolaysyla derleyici,
prototip bildiriminde, parametre parantezi iine bir ey yazlmadn grdkten sonra,
fonksiyonun tanmlanma ifadesinde parametre deiken(ler)inin varln grrse, bu durumu
bir error mesaj ile bildirir.)
Fonksiyon prototip bildiriminin yaplm olmas o fonksiyonun tanmlamasn ya da arlmasn
zorunlu klmaz.
Prototip bildirimi yaplan bir fonksiyonu tanmlamamak hata oluturmaz.
Bir fonksiyonun prototip bildirimi birden fazla yaplabilir.. Bu durumda hata oluturmaz. Ama
yaplan bildirimler birbirleriyle elimemelidir.
Kaynak dosya iinde ayn fonksiyona ilikin prototip bildirimlerinin farkl yerlerde ve aadaki
biimlerde yapldn dnelim :
int sample (int, int);
sample (int, int);
int sample(int x, int y);

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

long sample(double x);


sample (double x);

/*

error!

bildirimler

arasnda

eliki

var.

*/

Fonksiyon prototiplerinde parametre deikenlerinin trlerinin de belirtilmesi, argumanlarn


parametre deikenlerime aktarlmasnda tr dnmne olanak salamaktadr. Bu durum tr
dnmleri konusunda ele alnacaktr.

91

11

11 . BLM : KOUL OPERATR


Koul operatr (conditional operator) C dilinin 3 operand alan tek operatrdr. (ternary
operator) Koul operatrnn 3 operand, ifade tanmna uygun herhangi bir ifade olabilir.
Koul operatrnn genel sentaks aadaki gibidir:
ifade1 ? ifade2 : ifade3
Koul operatr yukardaki biimden de grld gibi birbirinden ayrlm iki atomdan
olumaktadr. ? ve : atomlar operatrn 3 operandn birbirinden ayrr.
Derleyici bir koul operatr ile karlatn ? atomundan anlar ve ? atomunun solundaki
ifadenin (ifade1) saysal deerini hesaplar. Eer ifade1in deeri 0 d bir saysal deerse, bu
durum koul operatr tarafndan doru olarak deerlendirilir, ve bu durumda yalnzca
ifade2nin saysal deeri hesaplanr.
Eer ifade1in deeri 0 ise bu durum koul operatr tarafndan yanl olarak deerlendirilir ve
bu durumda yalnzca ifade3n saysal deeri hesaplanr.
Dier operatrlerde olduu gibi koul operatr de bir deer retir. Koul operatrnn rettii
deer ifade1 doru ise (0 d bir deer ise) ifade2nin deeri, ifade1 yanl ise ifade3n
deeridir. rnek:
m = x > 3 ? y + 5 : y 5;
Burada nce x > 3 ifadesinin saysal deeri hesaplanacaktr. Bu ifade 0 d bir deerse (yani
doru ise) koul operatr y + 5 deerini retecektir. x > 3 ifadesinin deeri 0 ise (yani yanl
ise) koul operatr y 5 deerini retecektir. Bu durumda m deikenine x > 3 ifadesinin
doru ya da yanl olmasna gre y + 5 ya da y 5 deeri atanacaktr.
Ayn ilem if deyimi ile de yaplabilir :
if (x > 3)
m = y + 5;
else
m = y 5;
Koul operatr Operatr ncelik Tablosunun 13. ncelik seviyesindedir. Bu seviye atama
operatrnn hemen stdr. Aadaki ifadeyi ele alalm:
x>3?y+5:y5=m
Koul operatrnn ncelii atama operatrnden daha yksek olduu iin, nce koul
operatr ele alnr. x > 3 ifadesinin DORU olduunu ve operatrn y + 5 deerini rettiini
dnelim. Toplam ifadenin deerlendirilmesinde kalan ifade
y+5=m
olacak ve bu da derleme zaman hatasna yol aacaktr. nk y + 5 ifadesi sol taraf deeri
deildir, nesne gstermez. (Lvalue required).
Koul operatrnn birinci ksmn (ifade1) parantez iine almak gerekmez. Ancak, okunabilirlik
asndan genellikle parantez iine alnmas tercih edilir.
(x >= y + 3) ? a * a : b
Koul operatrnn nc operand (ifade3) konusunda dikkatli olmak gerekir. rnein :
m = a > b ? 20 : 50 + 5
92

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

Koul Operatrnn Kullanld Durumlar


Koul operatr her zaman if deyimine bir alternatif olarak kullanlmamaldr. Koul
operatrnn kullanlmasnn tavsiye edildii tipik durumlar vardr ve bu durumlarda genel fikir,
koul operatrnn rettii deerden ayn ifade iinde faydalanmak, bu deeri bir yere
aktarmaktr.
1. Bir nermenin doru ya da aynl olmasna gre farkl iki deerden birinin ayn deikene
aktarlmas durumunda:
p = (x == 5) ? 10 : 20;
m = (a >= b + 5) ? a + b : a b;
Yukardaki deyimleri if else yapsyla da kurabilirdik:
if (x == 5)
p = 10;
else
p = 20;
if (a >= b + 5)
m = a + b;
else
m = a b;
2. Fonksiyonlarda return ifadesini olutururken:
return (x > y ? 10 : 20);
Bu rnekte x > y ifadesinin doru olup olmamasna gre fonksiyonun geri dn deeri 10
ya da 20 olacaktr. Yukaridaki ifade yerine aadaki if yaps da kullanlabilirdi :
if (x > y)
return 10;
else
return 20;
3. Fonksiyon arma ifadelerinde arguman olarak:
func(a == b ? x : y);
Bu ifadede func fonksiyonu a deikeninin b degikenine eit olup olmamas durumuna
gre x ya da y argumanlaryla arlacaktr. if deyimiyle aadaki ekilde karlanabilir:
if (a == b)
func(x);
else
func(y);
4. if deyiminde koul ifadesi olarak da koul operatrnn kullanld grlr:
if ( y == (x > 5 ? 10 : 20))
Yukaridaki ifadede x > 5 ifadesinin doru olup olmamasna gre if parantezi iinde y
deikeninin 10 ya da 20ye eitlii test edilecektir.

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

BOOL is_leap(int year)


{
return !(year % 4) && year % 100 || !(year % 400);
}
Koul operatrnn ncelik yn sadan soladr. (right associative). Bir ifade iinde birden
fazla koul operatr varsa nce en sadaki deerlendirilecektir.
Aadaki kod parasn inceleyelim :
int x = 1;
int y = 1;
m = x < 5 ? y == 0 ? 4 : 6 : 8;
printf("m = %d\n", m);
Yukardaki kod parasnda printf fonksiyonu armnda m deikeninin deeri 6 olarak
yazdrlacaktr. fade aadaki gibi ele alnacaktr :
m = x < 5 ? (y == 0 ? 4 : 6) : 8;

96

DNG DEYMLER

12 . BLM : DNG DEYMLER


Bir program parasnn yinelemeli olarak altrlmasn salayan kontrol deyimlerine dng
denir. C dilinde 3 ayr dng deyimi vardr:
Kontroln bata yapld while dngleri
Kontroln sonda yapld while dngleri (do while dngleri)
for dngleri
Bu dng deyimlerinden en fazla kullanlan for deyimidir. for deyimi yalnzca C dilini deil,
tm programlama dillerinin en gl dng yapsdr. Aslnda while ya da do while dngleri
olmasa da bu dngler kullanlarak yazlan kodlar, for dngsyle yazlabilir. Ancak
okunabilirlik asndan while ve do while dnglerinin tercih edildii durumlar vardr.

Kontrolun Basta Yapld while Dngleri


Genel biimi:
while (ifade)
deyim;
while anahtar szcn izleyen parantez ierisindeki ifadeye kontrol ifadesi (control
statement) denir. while parantezini izleyen ilk deyime dng gvdesi denir. Dng gvdesi
basit bir deyim olabilecei gibi, bloklanm birden fazla deyimden de (bileik deyim) oluabilir.
while deyiminin icras u ekilde olur: Kontrol ifadesinin saysal deeri hesaplanr. Kontrol
ifadesinin saysal deeri 0 d bir deerse, mantksal olarak doru kabul edilir ve dng
gvdesindeki deyim ya da deyimler altrlr. Kontrol ifadesinin saysal deeri 0 ise mantksal
olarak yanl kabul edilir programn ak dngnn dndaki ilk deyimle devam eder. Yani
while dngs, kontrol ifadesinin saysal deeri 0 d bir deer olduu srece, dng
gvdesini oluturan deyim(ler)in icras ile devam eder.
Daha nce belirttiimiz gibi C dilinde yaln bir deyimin olduu yere bileik bir deyim de
yerletirilebilir. Bu durumda while dngs aadaki gibi de oluturulabilir :
while (ifade) {
ifade1;
ifade2;
ifade3;
......
}
Bu durumda kontrol ifadesinin saysal deeri 0 d bir deer olduu (doru)
parantezleri arasnda kalan tm deyimler icra edilecektir. rnek:
#include <stdio.h>
int main()
{
int i = 0;
while (i < 10) {
printf ("%d\n", i)
++i;
}
return 0;
}
Baka bir rnek:

97

srece blok

12

#include <stdio.h>
#include <ctype.h>
int main()
{
char ch;

while (ch = getch(), toupper(ch) != 'Q')


putchar(ch);
return 0;

Baka bir rnek daha:


int main()
{
char ch;
while (ch = getch(), isupper (ch))
putchar(ch);
return 0;
}
while parantezinin iindeki ifade yani koul ifadesi, ifade tanmna uygun herhangi bir ifade
olabilir.
while (1) {
....
}
Yukardaki while deyiminde kontrol ifadesi olarak bir sabit olan 1 says kullanlmtr. 1 deeri
0 d bir deer olduundan ve kontrol ifadesi bir deikene bal olarak deiemeyeceinden,
byle bir dngden kmak mmkn olmayacaktr. Bu tr dnglere sonsuz dngler (infinite
loops) denir. Sonsuz dngler bir yanllk sonucu oluturulabildii gibi, bilinli olarak da
oluturulabilir. Sonsuz dnglerden baz yntemlerle klabilir.

break Anahtar Szc


break anahtar szc ile bir dng sonlandrlabilir. Kullanm
break;
eklindedir. Programn ak break anahtar szcn grdnde, dng krlarak dngnn
ak dng gvdesi dndaki ilk deyim ile devam eder. Yani koulsuz olarak dngden klr.
int main (void)
{
char ch;
while (1) {
ch = getch();
if (ch == 'q')
break;
putchar(ch);
}
printf("dngden kld!..\n");
return 0;
}

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

while Dngs erisinde Postfix ++ ya da -- Operatrnn Kullanlmas


Bir postfix artrm ya da eksiltme ilemi yapldnda nce dngye devam edilip edilmeyecei
karar verilir, sonra artrm ya da eksiltim uygulanr. rnek :
int main()
{
int i = 0;
while (i++ < 100)
printf("%d\n", i);
printf("%d\n", i);
return 0;

/* ekrana 101 deerini basar. */

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

while (i++ < 10) {


printf("%d\n", i);
j = 1000000L;
while (j--> 0 )
;
return 0;

Bazen dngler bilinli bir ekilde bo deyimle kapatlmak istenebilir. Bu durumda bo deyim
normal bir deyim gibi tablama kuralna uygun olarak yerletirilmelidir.

Kontroln Sonda Yapld while Dngleri


Genel biim;
1. do
ifade 1;
while (ifade 2);
2. do {
ifade 1;
100

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;

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


printf(%d\n, i);
printf(son deer = %d\n, i);
return 0;

Yukardaki program inceleyelim:


Programn ak for deyimine gelince, nce for parantezi iindeki 1. ifade icra ediliyor. Yani i
deikenine 0 deeri atanyor.
imdi programn ak for parantezinin 2. ksmna yani kontrol ifadesine geliyor ve i < 2 koulu
sorgulanyor. Kontrol ifadesinin deeri 0 d bir deer olduu iin, ifade mantksal olarak doru
kabul ediliyor ve programn ak dng gvdesine geiyor. Dng gvdesi bloklanmad iin,
dng gvdesinde tek bir deyim var. (basit deyim). Bu deyim icra ediliyor. Yani ekrana i
deikeninin deeri yazlarak imle alt satra geiriliyor.
Programn ak bu kez for parantezinin 3. ksmna geliyor ve buradaki ifade bir deyimmi gibi
icra edeiliyor, yani i deikeninin deeri 1 artrlyor. i deikeninin deeri 1 oluyor.
2. ifade yeniden deerlendiriliyor ve i < 2 ifadesi doro olduu iin bir kez daha dng gvdesi
ira ediliyor.

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;

for (ch = getch(); ch != p ; ch = getch())


putchar(ch);
return 0;

Baka bir rnek:


int main()
{
for (printf(1. ifade\n"); printf(2. ifade\n), getch() != q; printf(3. ifade\n));
}

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

2. return anahtar szc ile


bu durumda fonksiyonun (main de olabilir) icras sona erecektir.
3. goto anahtar szcyle.
ie birden fazla dng varsa en iteki dng iinden en dtaki dngnn dna kadar
kabiliriz. (goto anahtar szcnn ok az saydaki faydal kullanmndan biri budur.)
4. exit fonksiyonu ile. (ileride greceiz)

continue Anahtar Szc


continue anahtar szc de tpk break anahtar szc gibi bir dng ierisinde
kullanlabilir. Programn ak continue anahtar szcne geldiinde sanki dng yinelemesi
bitmi gibi yeni bir yinelemeye geilir. Eer for dngs ierisinde kullanlyorsa yeni bir
yinelemeye gemeden nce dngnn 3. ksm yaplr. rnek :
#include <stdio.h>
int main()
{
int i, k;
char ch;

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


if (i % 3 == 0)
continue;
printf("%d\n", i);
}
return 0;

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

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


for (i = 1; i <= n; ++i)
for (i = n - 1; i >= 0; --i)
for (i = n; i > 0; --i)
Bir dngden kmak iin dng deikeni ile oynamak kt bir tekniktir. Bu programlar
okunabilirlikten uzaklatrr. Bunun yerine break anahtar szc ile dnglerden klmaldr.

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;

Baka bir zm:


#include <stdio.h>
#include <conio.h>
int main()
{
int i, b1, b2, b3;

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

int obeb(int number1, int number2);


int okek(int number1, int number2);
int main()
{
int x, y;
int n = 20;
clrscr();
while (n-- > 0) {
printf("iki tamsay giriniz : ");
scanf("%d%d", &x, &y);
printf("obeb = %d\n", obeb(x, y));
printf("okek = %d\n", okek(x, y));
}
getch();
return 0;
}
int obeb(int number1, int number2)
{
int i;
int min = (number1 < number2) ? number1 : number2;
for (i = min; i >= 1; --i)
if (number1 % i == 0 && number2 % i == 0)
return i;
}
int okek(int number1, int number2)
{
int i;
int max = (number1 > number2) ? number1 : number2;
for (i = max; i <= number1 * number2; i += max)
if (i % number1 == 0 && i % number2 == 0)
return i;
}

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;

for (k = 7; k * k <= number; k += 2)


if (number % k == 0)
return 0;
return 1;

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;

for (i = 2; i < = number / 2; ++i)


if (number % i == 0)
total += i;
return number == total;

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;

for (k = 1111; k < 1200; ++k) {


printf("%d saysnn arpanlar = ", k);
factors(k);
putchar('\n');
getch();
}
return 0;

void factors(int number)


{
int temp = number;
int k;

for (k = 2; k <= number / 2; ++k)


while (temp % k == 0) {
printf("%d ", k);
temp /= 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;

while (total < 3) {


ch = getch();
putchar(ch);
if (ch == '' && total == 0)
total++;
else if (ch == '' && total == 1)
total++;
else if (ch == 'k' && total == 2)
total++;
else total = 0;
}
return 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 );

/* x deikenine 234 deeri atanacaktr */

y = 32768.1;
x = y;
printf(x = %d\n, x );

/* x deikenine -32768 deeri atanacaktr */

Tam Sayya Terfi (integral promotion)


Daha nce de akland gibi integral promotion bir ifade iinde bulunan char, unsigned
char, short, unsigned short trlerinin, ifadenin derleyici tarafndan deerlendirilmesinden
nce, otomatik olarak int tre dntrlmeleri anlamna gelir.
Peki dnm signed int trne mi unsigned int trne mi yaplacak, bunu nasl bileceiz?
Genel kural udur: Tr dnmne urayacak trn btn deerleri int tr ile ifade
edilebiliyorsa int, edilemiyorsa unsigned int trne dnm yaplr.
rnein unsigned short ve int trlerinin ayn uzunlukta olduu DOS iletim sisteminde
unsigned short tr, tamsayya terfi ettirilirken unsigned int trne dntrlr.
Eer tam sayya terfi ettirilecek deer, signed char, unsigned char ya da short (signed
short) trlerinden ise dnm signed int trne yaplacaktr.
Bilgi kayb ile ile ilgili u hususu da gz ard etmemeliyiz. Baz durumlarda bilgi kayb tr
dnm yapld iin deil yaplmad iin oluur. Snr deer tamalar buna iyi bir rnek
olabilir.
rnek: (DOS altnda altmz dnelim)
long x = 1000 * 2000;
Yukardaki kod ilk bakta normal gibi grnyor. Zira arpma ileminin sonucu olan 2000000
deeri DOS altnda long tr say snrlar iinde kalmaktadr. Oysa bilgi kayb atama
ileminden nce gerekleir. 1000 ve 2000 int trden sabitlerdir, ileme sokulduklarnda
arpma operatrnn de rettii deer int trden olacaktr. Bu durumda 2 byte uzunlukta olan
int tr 2000000 saysn tutamayaca iin yksek anlaml byte kaybedilecektir. 2000000 hex
sistemde 0x1E8480 olarak gsterilebilir. Yksek anlaml byte kaybedilince ilem sonucu
0x8480 olarak bulunur. 0x8480 negatif bir saydr. kiye tmleyenini alrsak
0x8480
1000 0100 1000 0000
ikiye tmleyeni 0111 1011 1000 0000 (0x7B80 = 31616)
Grld gibi ilem sonucu retilecek deer 31616 dir. Bu durumda x deikeninin tr
long da olsa, atanacak deer 31616 olacaktr.

117

13

Fonksiyon armalarnda Tr Dnm


Daha nce sylendii gibi bir fonksiyona gnderilecek argumanlarla, bu argumanlar tutacak
fonksiyonun parametre deikenleri arasnda tr fark varsa otomatik tr dnm
gerekleecek ve argumanlarn tr, parametre deikenlerinin trlerine dntrlecektir.
Ancak bu tr dnmnn gereklemesi iin, derleyicinin fonksiyon arma ifadesine
gelmeden nce fonksiyonun parametre deikenlerinin trleri hakknda bilgi sahibi olmas
gerekecektir. Derleyici bu bilgiyi iki ayr ekilde elde edebilir:
1. arlan fonksiyon aran fonksiyondan daha nce tanmlanmsa, derleyici fonksiyonun
tanmlamasndan parametre deikenlerinin trn belirler.
2. Fonksiyonun prototip bildirimi yaplmsa derleyici parametre deikenlerinin tr hakknda
nceden bilgi sahibi olur.
rnek:
#include <stdio.h>
double func(double x, double y)
{
...
}
int main()
{
int a, b;
...
funk(a, b);
return 0;
}
Yukardaki rnekte main fonksiyonu iinde arlan func fonksiyonuna arguman olarak int
trden olan a ve b deikenlerinin deerleri gnderilmitir. Fonksiyon tanmlamas arma
ifadesinden nce yer ald iin int trden olan a ve b deikenlerinin deerleri, double tre
dntrlerek func fonksiyonunun parametre deikenleri olan x ve y deikenlerine
aktarlrlar. func fonksiyonunun main fonksiyonundan daha sonra tanmlanmas durumunda
otomatik tr dnmnn yaplabilmesi iin prototip bildirimi ile derleyiciye parametre
deikenlerinin trleri hakknda bilgi verilmesi gerekir.
#include <stdio.h>
double funk(double x, double y);
int main()
{
int a, b;
...
funk(a, b);
return 0;
}
double funk(double x, double y)
{
...
}
Peki arlan fonksiyon aran fonksiyondan daha sonra tanmlanmsa, ve fonksiyon prototipi
bildirimi yaplmamsa (tabi bu durumda derleme zamannda error olumamas iin

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

14 . BLM : switch DEYM


switch deyimi ile bir ifadenin farkl deerleri iin farkl iler yapmak mmkn hale gelir.
zellikle else if yaplarna bir alternatif olarak kullanlr.
Genel biimi:
switch (ifade) {
case ifade_1:
case ifade_2:
case ifade_3:
.......
case ifade_n:
default:
}
switch, case ve default anahtar szcklerdir.

switch Deyiminin almas


Derleyici switch parantezi ierisindeki ifadenin saysal deerini hesaplar. Bu saysal deere eit
bir case ifadesi olup olmadn aratrr. Bulursa programn ak o case ifadesine geirilir.
Artk program buradan akarak ilerler. Eer switch parantezi iindeki ifadenin saysal deeri
hibir case ifadesine eit deilse ak default anahtar szcnn bulunduu ksma geirilir.
default anahtar szcnn bulunmas zorunlu deildir. Uygun bir case ifadesi yoksa ve
default anahtar szc de yoksa programn ak switch deyiminin iine girmez ve switch
deyimi dndaki ilk deyim ile devam eder.
rnek:
#include <stdio.h>
int main()
{
int a;
scanf(%d, &a);

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

mmkn nk 1 + 3 sabit ifadesi ama ,


case x + 5:

/* error */

nk sabit ifadesi deil. Derleyici derleme aamasnda saysal bir deer hesaplayamaz.
case a :

/* geerli, bir sabit ifadesidir. */

case 3.5 :

/* gerek say (double) trnden olduu iin geerli deildir. */

case ifadelerini izleyen deyimlerin 15 - 20 satrdan uzun olmas okunabilirlii zayflatr. Bu


durumda yaplacak ilemlerin fonksiyon arma biimine dntrlmesi doru bir tekniktir.
switch (x) {
case ADDREC:
addrec();
break;
case DELREC:
delrec();
break;

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;

void dispdate(int day, int month, int year)


{
printf("%2d", day);
switch (day) {
case 1 :
case 21:
case 31: printf("st "); break;
case 2 :
case 22: printf("nd "); break;
case 3 :
case 23: printf("rd "); break;
default : printf("th ");
}

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;

int isleap(int year)


{
return (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)
}
int dayofyear(int day, int month, int year)
{
int yearday = day;
switch (month - 1) {
case 11: yearday += 30;
case 10: yearday += 31;
case 9 : yearday += 30;
case 8 : yearday += 31;
case 7 : yearday += 31;
case 6 : yearday += 30;
case 5 : yearday += 31;
case 4 : yearday += 30;
case 3 : yearday += 31;
case 2 : yearday += isleap(year) ? 29 : 28;
case 1 : yearday += 31;
}
return yearday;
}

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>

int isleap(int year);


void randomdate(void);
126

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

15 . BLM : NLEMC KAVRAMI


imdiye kadar tek bir yap halinde ele aldmz C derleyicileri aslnda, iki ayr modlden
olumaktadr:
1. nilemci Modl
2. Derleme Modl
sim benzerlii olsa da nilemcinin bilgisayarn ilemcisi ya da baka bir donanmsal
elemanyla hibir ilgisi yoktur, nilemci tamamen C derleyicisine ilikin yazlmsal bir
kavramdr.
nilemci, kaynak program zerinde birtakm dzenlemeler ve deiiklikler yapan bir n
programdr. nilemci programnn bir girdisi bir de kts vardr. nilemcinin girdisi kaynak
programn kendisidir. nilemcinin kts ise derleme modlnn girdisini oluturur. Yani
kaynak program ilk aamada nilemci tarafndan ele alnr. nilemci modl kaynak
programda eitli dzenlemeler ve deiiklikler yapar, daha sonra deitirilmi ve dzenlenmi
olan bu kaynak program derleme modl tarafndan ama koda dntrlir.
kaynak kod

nilemci

derleyici

ama program

C programlama dilinde # ile balayan btn satrlar nilemciye verilen komutlardr.


# karakterinin sanda bulunan szckler ki bunlara nilemci komutlar denir (preprocessor
directives), nilemciye ne yapmas gerektiini anlatr. rnein:
#include
#define
#if
#ifdef
#ifndef
hepsi birer nilemci komutudur.
nilemci komutlar derleyici asndan anahtar szck deildir # karakteriyle birlikte anlam
kazanrlar, yani istersek include isimli bir deiken tanmlayabiliriz ama bunun okunabilirlik
asndan iyi bir fikir olmadn syleyebiliriz. nilemci komutlarn belirten szckler ancak
sol taraflarndaki # karakteriyle kullanldklar zaman zel anlam kazanrlar ki bunlara nilemci
anahtar szckleri de diyebiliriz.
nilemci ama kod oluturmaya ynelik hibir i yapmaz. nilemci kaynak program # ieren
satrlardan arndrr. Derleme modlne girecek programda artk # ieren satrlar yer
almayacaktr.
Bir ok nilemci komutu olmakla birlikte imdilik yalnzca #include komutu ve #define
nilemci komutlarn inceleyeceiz. Geriye kalan nilemci komutlarn da ileride detayl olarak
inceleyeceiz.

#include nilemci komutu


genel kullanm biimi:
#include <dosya ismi>
ya da
#include "dosya ismi"

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.

#define nilemci Komutu


#define nilemci komutu text editrlerindeki bul ve deitir zellii (find & replace) gibi
alr. Kaynak kod ierisindeki bir yazy baka bir yaz ile deitirmek iin kullanlr.

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)

eklinde yazsaydk, result deikenine 60 deeri atanm olurdu.


Bir sembolik sabit baka bir sembolik sabit tanmlamasnda kullanlabilir. rnein:
#define
#define

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

Sembolik sabitler C dilinin deiken isimlendirme kurallarna uygun olarak isimlendirilir:


#define BYK

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

"DOSYA AILAMIYOR \n"

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

#define nilemci Komutu Neden Kullanlr


1. Okunabilirlii ve algnalabilirlii artrr. Bir takm sabitlere onlarn ne amala kullanldn
anlatan yazlar karlk getirilirse programa bakan kiiler daha iyi anlamlandrr.
#define PERSONEL_SAYISI 750
int main()
{
if (x == PERSONEL_SAYISI)
...
return 0;
}
2. Bir sabitin program ierisinde pekok yerde kullanld durumlarda deitirme ilemi tek
yerden yaplabilir. Bylece sz konusu program sembolik sabite bagl olarak yazlp, daha
sonra sembolik sabitin deitirilmesiyle farkl parametrik deerler iin altrlabilir.

133

15

3. Saysal sabitlerin kullanlmasnda tutarszlklar ve yazm yanllarn engeller.


rnein matematiksel hesaplamalar yapan bir kodda sksk pi saysn kullandmz
dnelim. pi says yerine
#define

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.

Sembolik Sabitlerin Kullanlmasnda ok Yaplan Hatalar


1. Sembolik sabit tanmlamasnda gereksiz yere = karakterini kullanmak.
#define

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 . BLM : goto DEYM


Dier programlama dillerinde olduu gibi C dilinde de programn ak, bir koula bal
olmakszn kaynak kod iinde baka bir noktaya ynlendirilebilir. Bu C dilinde goto deyimi ile
yaplmaktadr.
goto deyiminin genel sentaks aadaki ekildedir.
<goto label;>
....
<label:>
<statement;>
goto C dilinin 32 anahtar szcnden biridir. (anahtar szcklerin kk harfle yazldklarn
tekrar hatrlatalm.) Label (etiket) programcnn verdii bir isimdir. phesiz C dilinin
isimlendirme kurallarna uygun olarak seilmelidir. Programn ak bu etiketin yerletirilmi
olduu yere ynlendirilecektir. Etiket, goto anahtar szcnn kullanld fonksiyon iinde,
en az bir deimden nce olaak ekilde, herhangi bir yere yerletirilebilir. Etiket isminden sonra
gelen : atomu sentaks tamamlar. Etiketin goto anahtar szcnden daha sonraki bir kaynak
kod noktasna yerletirilmesi zorunluluu yoktur, goto anahtar szcnden nce de
tanmlanm olabilir. rneklerle aklayalm:
int main()
{
...
goto GIT;
...
...
GIT:
printf("goto deyimi ile buraya gelindi);
return 0;
}
int main()
{
GIT:
printf("goto deyimi ile gelinecek nokta);
...
goto GIT;
...
return 0;
}
goto etiketleri bir fonksiyon ierisinde, bir deyimden nce herhangi bir yere yerletirilebilir.
Yani ayn fonksiyon iinde bulunmak kaydyla goto anahtar szcnn yukarsna ya da
aasna etiketi yerletirebiliriz. Bu da aslnda deiik bir faaliyet alan tipidir. C dili
standartlarnda bu faaliyet alan trne "fonksiyon faaliyet alan" denmitir.
Yapsal programlama tekniinde goto deyiminin kullanlmas tavsiye edilmez. nk goto
deyiminin kullanlmas birtakm dezavantajlar dourur:
1. goto deyimi programlarn okunabilirliini bozar. Kodu takip eden kii goto deyimiyle
karlatnda fonksiyonun iinde etiketi arayacak, ve program bu noktadan takip etmeye
koyulacaktr.
2. goto deyimlerinin kullanld bir programda bir deiiklik yaplmas ya da programn,
yaplacak eklemelerle, gelitirilmeye allmas daha zor olacaktr. Programn herhangi bir
yerinde bir deiiklik yaplmas durumunda, eer program ierisinde baka yerlerden kodun
135

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

17 . BLM : RASTGELE SAYI RETM


Rasgele say retimi matematiin nemli konularndan biridir. Rasgele saylar ya da daha doru
ifadeyle, rasgele izlenimi veren saylar (szde rasgele saylar - pseudo random numbers)
istatistik, ekonomi, matematik gibi pekok alanda olduu gibi programclkta da
kullanlmaktadr.
Rasgele saylar bir rasgele say reticisi (random number generator) tarafndan retilirler.
Rasgele say reticisi aslnda matematiksel bir fonksiyondur. Sz konusu fonksiyon bir
balang deeri alarak bir deer retir. Daha sonra rettii her deeri girdi olarak alr ve
tekrar baka bir say retir . reticinin rettii saylar rasgele izlenimi vermektedir.
C standartlar rasgele tamsay reten bir fonskiyonun standart bir C fonksiyonu olarak
tanmlanmasn zorunlu klmtr. Bu fonksiyonun prototip bildirimi aadaki gibidir:
int rand(void);
C standartlar rand fonksiyonunun rasgele say retimi konusunda kullanaca algoritma ya da
teknik zerinde bir koul koymamtr. Bu konu derleyiciyi yazanlarn seimine bal
(implementation dependent) braklmtr. rand fonksiyonunun prototipi standart bir balk
dosyas olan stdlib.h iinde bildirilmitir.
Bu yzden rand fonksiyonunun arlmas durumunda bu balk dosyas "include" nilemci
komuduyla kaynak koda dahil edilmelidir.
#include <stdlib.h>
rand fonksiyonu her arldnda [0, RAND_MAX] aralnda rasgele bir tamsay deerini geri
dndrr. RAND_MAX stdlib.h balk dosyas iinde tanmlanan bir sembolik sabittir,
derleyicilerin ounda RAND_MAX sembolik sabiti 32767 olarak, yani 2 byte'lk signed int
trnn maximum deeri olarak tenmlanmtr.
Aadaki program parasnda 0 ile 32767 arasnda 10 adet rasgele say retilerek ekrana
yazdrlmaktadr :
#include <stdio.h>
#include <stdlib.h>
int main()
{
int k;

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


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

Yukardaki kaynak kodla oluturulan programn her altrlmasnda ekrana ayn saylar
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

RASTGELE SAYI RETM


bir say elde edilir. Tohum deer zerinde yaplan ilem bu kez elde edilen rasgele say
zerinde tekrarlanr...
rand fonksiyonu rasgele say retmek iin bir balang deeri kullanyor. Rasgele say
reticilerinin (random number generator) kullandklar balang deerine tohum deeri (seed)
denir. rand fonksiyonunu ieren program her altrdmzda ayn tohum deerinden
balayaca iin ayn say zinciri elde edilecektir. te ikinci fonksiyon olan srand fonksiyonu,
rasgele say reticisinin tohum deerini deitirmeye yarar:
void srand (unsigned seed);
srand fonksiyonuna gnderilen arguman rasgele say reticisinin tohum deerini deitir.
srand() fonksiyonuna baka bir tohum deeri gnderdiimizde fonksiyonun rettii rasgele say
zinciri deiecektir. Yukardaki programa bir ilave yaparak yeniden altrn.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int k;
srand(100);
for (k = 0; k < 10; ++k)
printf("%d ", rand());
return 0;
}
1862 11548 3973 4846 9095 16503 6335 13684 21357 21505
Ancak bu kez oluturduumuz program her eltrdmzda yine yukardaki say zinciri elde
edilecek. Zira rand fonksiyonunun kullanmakta olduu nceden seilmi (default) tohum
deerini kullanmasak da, rasgele say retme mekanizmas bu kez her defasnda bizim srand
fonksiyonuyla gndermi olduumuz tohum deerini kullanacak. Program birka kere altrp
ayn say zincirini rettiini test edin.
Bir ok durumda programn her altrlmasnda ayn rasgele say zincirinin retilmesi
istenmez. Programn her almasnda farkl bir say zincirinin elde edilmesi iin programn her
almasnda srand fonksiyonu baka bir deerle, rasgele say reticisinin tohum deerini set
etmelidir. Bu amala ou zaman time fonksiyonundan faydalanlr:
time fonksiyonu standart bir C fonksiyonudur, prototip bildirimi standart bir balk dosyas olan
time.h iindedir. time fonksiyonu, parametre deikeni gsterici olan bir fonksiyon olduundan
ileride detayl olarak ele alnacaktr. imdilik time fonksiyonunu iimizi grecek kadar
inceleyeceiz. time fonksiyonu 0 argumanyla arldnda 01.01.1970 tarihinden fonksiyonun
arld ana kadar geen saniye saysn geri dndrr. Fonksiyonun geri dn deeri
derleyicilerin ounda long trden bir deerdir. inde rasgele say retilecek programda,
srand fonksiyonuna arguman olarak time fonksiyonunun geri dn deeri arguman olarak
gnderilirse, program her altnda rasgele say reticisi baka bir tohum deeriyle ilk
deerini alacaktr, byle progarmn her altrlmasnda farkl say zinciri retilecektir.
srand(time(0));
srand fonksiyonunun bu ekilde arm derleyicilerin ounda randomize isimli bir makro
olarak tanmlanmtr. Yukardaki fonksiyon arm yerinde bu makro da arlabilir. Makrolar
konusunu ileride detayl olarak inceeyeceiz :
randomize();

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

Yalnzca 0 ya da 1 deerini retir.


0 - 5 aralnda rasgele bir deer retir
1 - 6 aralnda rasgele bir deer retir.
5 - 8 aralnda rasgele bir deer retir.

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

RASTGELE SAYI RETM


#define TIMES 2500
tura gelme olasl = 0.506800
#define TIMES 10000
tura gelme olasl = 0.503500
#define TIMES 30000
tura gelme olasl = 0.502933
#define TIMES 100000
tura gelme olasl = 0.501450
#define TIMES 1000000
tura gelme olasl = 0.500198
#define TIMES 10000000
tura gelme olasl = 0.500015
#define TIMES 2000000
tura gelme olasl = 0.500198
Aadaki main fonksiyonunda uzunluklar 3 - 8 harf arasnda deien ingiliz alfabesindeki
harfler ile oluturulmu rasgele 10 kelime ekrana yazdrlmaktadr:
#include
#include
#include
#include

<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

: Dizi elemanlarnn trn gsteren anahtar szcktr.


: simlendirme kurallarna uygun olarak verilecek herhangi bir isimdir.
: Dizinin ka elemana sahip olduunu gsterir.

rnek Dizi Bildirimleri:


double a[20];
/* a, 20 elemanl ve elemanlar double trden olan bir dizidir*/
float ave[10];
/* ave 10 elemanl ve her eleman float trden olan bir dizidir. */
unsigned long total[100]; /* total 100 elemanl ve her eleman unsigned long trden olan
bir dizidir */
char path[80];
/* path 80 elemanl ve her eleman char trden olan bir dizidir. */
Tanmlamada yer alan eleman saysnn mutlaka tamsay trlerinden birinden sabit ifadesi
olmas zorunludur. (Sabit ifadesi [constant expression] tanmn hatrlayalm; deiken ve
fonksiyon arm iermeyen, yani yalnzca sabitlerden oluan ifadelere, sabit ifadesi denir.)
int dizi[x]; /* x dizisinin bildirimi derleme zamannda hata olusturur .*/
int dizi[5.]; /* gerek say trnden sabit ifadesi olduu iin derleme zamannda hata
olusturur . */
int sample[10 * 20]

/* sample dizisinin bildirimi geerlidir. Eleman saysn gsteren


ifade sabit ifadesidir. */

Dizi bildirimlerinde eleman says yerine sklkla sembolik sabitler kullanlr:


#define
MAXSIZE
...
int dizi[MAXSIZE];
...

100
/* geerli bir bildirimdir */

Dier deiken bildirimlerinde olduu gibi, virgl ayracyla ayrlarak, birden fazla dizi tek bir
tr belirten anahtar szckle tanmlanabilir.
143

18

int x[100], y[50], z[10];


x, y ve z elemanlar int trden olan dizilerdir.
Dizi tanmlamalar dier deiken tanmlamalar ile kombine edilebilir.
int a[10], b, c;
a int trden 10 elemanl bir dizi, b ve c int trden nesnelerdir.
Dizi elemanlarnn her biri ayr birer nesnedir. Dizi elemanlarna index operatryle []
ulalabilir. Index operatr bir gsterici operatrdr. Gstericiler konusunda ayrntl bir
ekilde ele alnacaktr.
ndex operatrnn operand dizi ismidir. (Aslnda bu bir adres bilgisidir, nk dizi isimleri
adres bilgisi belirtirler.) Keli parantez iinde dizinin kanc indisli elemanna ulaacamz
gsteren bir tamsay ifadesi olmaldr.
C dilinde dizilerin ilk eleman sfrnc indisli elemandr.
a[n] gibi bir dizinin ilk eleman a[0] son eleman ise a[n - 1] dur.
rnekler:
dizi[20] /* a dizisinin 20. indisli yani 21. sradaki eleman. */
ave[0]
/* ave dizisinin 0. indisli yani birinci sradaki eleman */
total[j]
/* total dizisinin j indisli eleman */
Grld gibi bir dizinin n. eleman ve bir dizinin n indisli eleman terimleri dizinin farkl
elemanlarna iaret eder. Bir dizinin n indisli eleman o dizinin n + 1 . elemandr.
Bir dizi tanmlamas ile karlaan derleyici, tanmlanan dizi iin bellekte yer tahsis
edecektir..Ayrlacak yer phesiz dizinin eleman says * bir elemann bellekte kaplad yer
kadar byte olacaktr. rnein:
int a[5];
gibi bir dizi tanmlamas yapldn dnelim. DOS iletim sisteminde alyorsak, derleyici a
dizisi iin bellekte 2 * 5 = 10 byte yer ayracaktr. Bellekte bu dizinin yerleimi aadaki gibi
olacaktr :
...
-------------------------------------------------------------

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

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


printf(yerel[%d] = %d\n, i, yerel[i]);

dizilerin birbirine atanmas


int a[SIZE], b[SIZE];
tanmlamasndan sonra, a dizisi elemanlarna b dizisinin elemanlar kopyalanmak istenirse
a = b;

/*

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

char name[ ] = {A, l, i};


yukardaki tanmlama
varsayacaktr.

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

/* C'de hata deil, C++'da hata */

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

puts fonksiyonu ve %s format karakteriyle kullanldnda printf fonksiyonu, sonlandrc


karakter grene kadar btn karakterleri ekrana yazar. Bu durumda, herhangi bir ekilde NULL
karakter ezilirse her iki fonksiyon da ilk sonlandrc karakteri grene kadar yazma ilemine
devam edecektir.
rnein :
char city[ ] = Ankara;
city[6] = !;
deyimi ile sonlandrc karakter ortadan kaldrlrsa (ezilirse) :
puts(name);
eklinde puts fonksiyonu arldnda ekrana Ankara!yazldktan sonra tesadfen ilk NULL
karakter grlene kadar ekrana yazmaya devam edilir. puts ve printf fonksiyonlar karakter
dizilerini yazarken yalnzca NULL karakteri dikkate alrlar. karakter dizilerinin uzunluklaryla
ilgilenmezler.
sizeof operatrnn dizilerle kullanlmas
sizeof operatr operand olarak bir dizi ismi aldnda byte olarak o dizinin toplam uzunluunu
deer olarak retir.
double sample[10];
sizeof(sample)
ifadesi 80 deerini retecektir.
sizeof operatr operand olarak dizinin bir elemann aldnda rettii deer, dizi hangi trden
ise o trn kullanlan sistemdeki byte olarak uzunluu olacaktr. yani yukardaki rnekte
sizeof(sample[0])

ifadesi, 8 deerini retecektir.

sizeof operatrn bir dizinin uzunluk bilgisi gerektii yerde de kullanabiliriz :


sizeof(sample) / sizeof(sample[0])
ifadesi dizi uzunluunu verecektir. rnek :
for (i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
a[i] = 0;
karakter dizileriyle ilgili baz kk uygulama rnekleri
Uygulama 7: Karakter dizisi ierisindeki yaznn uzunluunu bulan program:
#include <stdio.h>
main()
{
int k = 0,
char s[50];
gets(s);

157

18

while (s[k] != \0)


++k;
printf(uzunluk = %d\n, k);

yukarda while dngs yerine for dngs kullanlabilirdi :


for (k = 0; s[k] != \0; ++k)
;
Uygulama 8: karakter dizisini tersten yazdran program :
#include <stdio.h>
#define

SIZE

100

main()
{
char s[SIZE];
int k;

printf("bir yaz giriniz :");


gets(s);
for (k = 0; s[k + 1] != '\0'; ++k)
++k;
for (; k >= 0; --k)
putchar(s[k]);
return 0;

Uygulama 9: Karakter dizisindeki, byk harfleri kk harfe kk harfleri byk harfe


eviren bir program :
#include <stdio.h>
#include <ctype.h>
#define SIZE

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.

Ayr Bir Tr Olarak Adres


Yazlmsal adan RAM'de belirli bir byte'dan ne amala bahsetmek isteyebiliriz? O byte iinde
yer alan nesnenin deerini tespit etmek iin! Eer tm nesnelerimiz 1 byte uzunluunda
olsalard, o zaman yazlmsal olarak adres ile fiziksel adres arasnda herhangi bir fark
bulunmayacakt. Oysa RAM'deki belirli bir byte'dan sz ettiimizde, o byte' (belki onu izleyen
baz byte'larla birlikte) herhangi trden bir nesne kaplyor olabilir. Yazlmsal olarak adres bilgisi
yalnzca bellekte yer gsteren bir saydan ibaret deildir; ayn zamanda o adresin gsterdii
yerdeki bilginin ne biimde yorumlanacan belirten bir tr bilgisini de iermektedir.
rnein yazlmsal olarak 1250 adresindeki deerden sz etmek isteseydik aadaki sorularn
cevab akta kalacakt.
Sz konusu deer yalnzca 1250 adresindeki byte da m saklanm yoksa bunu izleyen (1251,
1252 vs.) bytelar da nesnenin deerinin tespit edilmesinde kullanlacak m? Sz konusu deer
hangi formatta yorumlanacak? (Yani iaretli tamsay aritmetiine gre mi, iaretsiz tam say
aritmetiine gre mi, gerek say formatna gre mi, vs.)
yazlmsal olarak bir adres bilgisinin iki bileeni vardr:
1. Bellekte yer gsteren saysal bir deer
2. Adresin tr

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

rnek gsterici bildirimleri:


float *f;
char *s;
int *dizi;
unsigned long *PDWORD;
Gsterici bildirimlerinin dier trlere ilikin bildirimlerden * atomu ile ayrlmaktadr.
char s;
bildiriminde s char trden bir deiken iken
char *s;
bildiriminde s char trden bir gstericidir. erisine char trden bir adres konulmaldr. Bu
bildirimden derleyici u bilgileri karacaktr:
s bir nesnedir, yani bellekte bir yer kaplar. s nesnesi iin bellekte ayrlan yerdeki 1 ler ve 0 lar
char trden bir adresin saysal bileeni olarak yorumlanrlar. Bu adresin tr bileeni ise char
trdr.
Burada * bir operatr deildir. Sentaks olarak nesnenin bir gsterici olduunu anlatmaktadr.
Ritchie stilinde, okunabilirlik asndan * ile gsterici ismi bitiik yazlmaldr. Gsterici
bildirimleri ile normal bildirimler bir arada yaplabilir. rnein :
int *p, a;
Burada p int trden bir gstericidir ama a int trden bir normal bir deikendir.
Ayn trden birden fazla gstericinin bildirimi yaplacaksa araya virgl konularak, her gsterici
deikenin bildirimi * atomu ile yaplmaldr.
char *str, *ptr;
Yukardaki bildirimde str ve ptr char trden gstericilerdir.
long *p1, *p2, l, k[20];
Yukardaki bildirimde p1 ve p2 long trden gstericiler, l long trden bir deiken ve k ise
long trden 20 elemanl bir dizidir.

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;

/* geerli ve uygun bir atamadr */

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

p gstericisinin bellekte bulundugu yere 1FC3 deeri


yazlyor.

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

Bu durumda dizi ismi olan s, char trden 1C00 adresine edeerdir.


Gstericilere kendi trlerinden bir adres bilgisi atamak gerektiine gre aadaki atamalarn
hepsi legal ve dorudur:
int a[100];
long l[20];
char s[100];
double d[10];
int *p;
long *lp;
char *cp;
double *dp;
p = a;
lp = l;
cp = s;
dp = d;
Bir gstericinin iine ayn trden bir dizinin ismi atanmaldr. rnein:
int *p;
char s[] = Necati;
p = s;
Yukardaki rnekte int trden bir gstericiye char trden bir adres bilgisi atanmtr. Derleme
zamannda error oluumuna neden olmaz ama yanltr, ileride detayl olarak incelenecektir.
C dilinde hibir deikenin ya da dizinin tahsisat yeri programc tarafndan belirlenemez.
Programc deikeni tanmlar, derleyici onu herhangi bir yere yerletirebilir.
Dizi isimleri gstericiler gibi sol taraf deeri olarak kullanlamaz. rnein, s bir dizi ismi olmak
zere
++s;
deyimi error oluturur. nk dizi isimleri nesne gstermezler.
zetle, adres belirten 3 tr ifade ele alnd.
1. Adres sabitleri.
2. Gstericiler.
3. Dizi isimleri.
Gstericiler ilerinde adres bilgileri tadklarna gre bir gstericiye ayn trden baka bir
gstericinin deerinin atanmas da tamamen uygundur.
int *p, *q;

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

p gstericisine (int *) 1AA0 adresi atanyor.

q gstericisine de p gstericisinin iindeki deer


atanyor

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

indirection operator (dereferencing operator)


address of operator
index operator (subscript operator)
arrow operator

Bu operatrlerden ok operatr yap trnden adreslerle kullanld iin yaplar konusunda


detayl olarak incelenecektir.

Gsterici Operatrlerinin Ayrntl ncelenmesi


& Adres Operatr (adress of operator)
Adres operatr tek operand alan nek konumunda bir operatrdr. (unary prefix). Operatr
ncelik tablosunun ikinci seviyesinde yer alr. Bu operatrn rettii deer operand olan
nesnenin adresidir. Yani operatrn rettii adres bilgisinin saysal bileeni nesnenin bellekteki
fiziksel adres numaras, tr bileeni ise nesnenin tr ile ayn trdr. & operatrnn operand
mutlaka bir nesne olmaldr. nk yalnzca nesnelerin (sol taraf deerlerinin) adres bilgilerine
ulalabilir. & operatrne operand olarak nesne olmayan bir ifade gnderilirse bu durum
derleme zamannda hata oluumuna neden olacaktr. (Borland derleyicileri bu durumda yle
bir error mesaj verirler : must take address of memory location)
int k;
&k
ifadesini ele alalm. Bu ifadenin rettii deer int trden bir adres bilgisidir. Adres bilgilerinin
iki bileeni olduunu sylemitik. Yukardaki ifadenin rettii bilginin saysal bileeni k
nesnesinin bellekte yerletirildii yerin balang adresi, tr bileeni ise int trdr. Zira k
deikeni int trden bir deikendir.
& operatr dier tek operand alan (unary) operatrler gibi, operatr ncelik tablosunun 2.
seviyesinde bulunur. Bilindii gibi bu ncelik seviyesinin ncelik yn sadan soladr.
Adres operatr ile elde ettiimiz adres ayn trden bir gstericiye atanmaldr. rnein
aadaki programda bir gstericiye farkl trden bir adres atanmtr:
char ch = 'x';
int *p;
p = &ch;

/* error deil ama yanl */

Bu durumda C'de adres belirten 4 tr ifade grm olduk:


1.
2.
3.
4.

Adres sabitleri.
Gstericiler.
Dizi isimleri.
& operatr ile oluturulmu ifadeler.

Tabi bu operatrn rettii adres bilgisi nesne deildir. rnein:

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.

* erik Operatr (indirection operator)


erik operatr de nek konumunda bulunan ve tek operand alan bir operatrdr (unary
prefix). Bir gsterici, * operatrnn operand olursa, elde edilen ifade p gstericisinin
ierisindeki RAM adresinde bulunan, nesneyi temsil eder. Dolaysyla, * operatr ile
oluturulan bir ifade bir nesneyi temsil etmektedir, ve sol taraf deeri olarak kullanlabilir.
int a;
gibi bir bildirimde a nesnesinin tr intdir. nk a nesnesi ierisinde int trden bir bilgi
tutulmaktadr.
int *p;
bildiriminde p nin tr int trden bir adrestir.
char *ptr;
gibi bir bildirimden iki ey anlalr:
ptr char trden bir gstericidir. erisine char trden bir adres bilgisi yerletirilir. ptr gstericisi
* operatr ile birlikte kullanldnda elde edilen nesne char trdendir. Yani *ptr char trden
bir nesnedir.
rnein:
int *p;
p = (int *) 0x1FC3;
*p = 100;
Burada *pnin tr intdir. Dolaysyla *p = 100 gibi bir ilemden yalnzca 0x1FC3 byte deil,
0x1FC3 ve 0x1FC4 bytelarndan her ikisi birden etkilenir.
Gstericinin ierisindeki adresin saysal bileeni nesnenin dk anlaml bytenn adresini ierir.
Bu durumda bir gstericinin ierisine RAMdeki herhangi bir blgenin adresi atanabilir. Daha
sonra * operatr ile o RAM blgesine eriilebilir.
* operatrnn operand bir adres bilgisi olmak zorundadr. Yani operand adres sabiti olabilir.
Dizi ismi olabilir. Bir gsterici olabilir. Adres operatr ile elde edilmi bir adres ifadesi olabilir.
* operatr yalnz gstericilerle deil, her tr adres bilgisi ile (adres sabitleri ve dizi isimleri
vs.) de kullanlabilir. Bu operatr operand ile belirtilen adresteki nesneye erimekte kullanlr.
Bu operatr ile elde edilen deer, operand olan adreste bulunan deerdir.
* operatr bir adrese uygulandnda ifade bir nesne belirtir. Nesnenin tr operand olarak
kullanlan adresin tr ile ayn trdendir. rnein :
int main()
{
char s[] = Balkesir;

169

19
putchar(*s);
}

return 0;

* operatr operatr ncelik tablosunun 2. dzeyinde sadan sola ncelikli bulunmaktadr.


rnein :
*s + 1;
ifadesinde nce *s yaplr. Sonra + operatr yaplr. Oysa ifade *(s + 1) biiminde olsayd
nce + operatr yaplrd.
Derleyiciler * operatrnn arpma operatr m yoksa adres operatr m olduunu ifade
ierisindeki kullanmna bakarak anlar. arpma operatr iki operand alrken adres operatr
nek konumundadr ve tek operand alr. rnek :
*s * 2
ifadesinde 1. * adres operatr iken 2. * aritmetik arpma operatrdr.

[] Kseli Parantez (index) Operatr :


Dizi elemanlarna erimekte kullandmz keli parantez aslnda unary prefix bir gsterici
operatrdr.
[] ierisine tamsay trnden bir ifade yazlr. (fadenin deeri pozitif olmak zorunda deildir.)
[] operatrnn operand dizi ismi olmak zorunda deildir. Bir adres bilgisi olmak zorundadr.
[] operatrnn operand bir dizi ismi olabilir. Gsterici olabilir. Dier adres belirten ifadeler
olabilir.
p[n] ile *(p + n) tamamen edeerdir.
Yani keli parantez operatr bir adresten n ilerisinin ieriini almak iin kullanlr. [] operat
ile elde edilen nesnenin tr operand olan adresin tr ile ayn trdendir. rnein:
#include <stdio.h>
int main()
{
char s[] = "stanbul";
char *p;
p = s + 1;
putchar(p[2]);
return 0;
}
[] operatr ncelik tablosunun en yksek dzeyinde bulunur. rnein:
&p[n]
ifadesinde nce [] yaplr, nesne elde edilir daha sonra nesnenin adresi alnr.
[] ierisindeki ifadenin saysal deeri negatif olabilir. rnein p[-2] geerli bir ifadedir.
#include <stdio.h>
int main()
170

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.

Adreslerle lemler / Adreslerin Artrlmas ve Eksiltilmesi (gsterici


aritmetii)
C dilinde adreslerle tamsay trnden saylar toplama ve karma ilemlerine sokulabilir. ki
adres ayn trden ise karlatrma operatrleri ile ileme sokulabilir. Burada adreslerin saysal
bileenleri ileme sokulmaktadr.
C dilinde bir adres bilgisi tamsay trleri ile artrlabilir veya eksiltilebilir. Sonu ayn trden bir
adres bilgisi olur. Bir adres bilgisi 1 artrldnda adresin saysal bileeni adresin trnn
uzunluu kadar artmaktadr. Bu durumda rnein DOS'da char trden bir gstericiyi, 1
artrdmzda adresin saysal bileeni 1 int trden bir gstericiyi 1 artrdmzda ise adresin
saysal bileeni 2 artar. Bu durumda p[n] ifadesi p adresinden n byte ilerisinin ierii deil, p
adresinden n * p gstericisinin trnn uzunluu kadar byte ilerinin ierii anlamna gelir.
ki adres bilgisinin toplanmas faydal bir ilem olmad gerekesiyle yasaklanmtr. Ancak iki
adres bilgisi birbirinden kartlabilir. ki adres birbirinden kartlrsa sonu int trden olur. ki
adres birbirinden kartldnda nce adreslerin saysal bileenleri kartlr, sonra elde edilen
deer adresin trnn uzunluuna blnr. rnein a int trden bir adres olmak zere:
&a[2] - &a[0] ifadesinden elde edilen deer 2'dir.
#include <stdio.h>
int main()
{
int a[5] = {1, 2, 3, 4, 5};
int *p;
p = a;
printf("%p adresindeki deer = %d\n", p, *p);
++p;
printf("%p adresindeki deer = %d\n", p, *p);
return 0;
}

++ ve -- operatrlerinin gsterici operatrleriyle birlikte kullanlmas


++*p durumu
x = ++*p;
*p = *p + 1; anlamna gelir. *p bir nesne gsterdii iin nesnenin deeri 1 artrlacaktr.
Yukardaki deyimle x deikenine *p nesnesinin artrlm deeri atanacaktr.

*++p durumu
p gstericisinin deeri 1 artrlr. Artrlm adresteki nesneye ulalm olur.
x = *++p;

171

19

deyimi ile x deikenine artrlm adresteki bilgi atanr.

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

Gstericilere lk Deer Verilmesi


Dier trden deikenlerde olduu gibi gstericilere de tanmlanmalar srasnda ilk deer
verilebilir. Gstericilere ilk deer verme ilemi gstericinin trnden bir adres bilgisi ile
yaplmaldr. rnekler:
char s[100];
double x;
int *ptr = (int *) 0x1A00;
char * str = (char *) 0x1FC0;
chat *p = s;
double *dbptr = &x;

Fonksiyon Parametre Deikeni Olarak Gstericilerin Kullanlmas


Bir fonksiyonun parametre deikeni herhangi bir trden gsterici olabilir.
void func(int *p)
{
...
}
Bir fonksiyonun parametre deikeni bir gsterici ise fonksiyon da ayn trden bir adres bilgisi
ile arlmaldr.
Bir fonksiyonun baka bir fonksiyonun yerel deikenini deitirebilmesi iin o fonksiyonun
yerel deikeninin adresini parametre olarak almas gerekir.
#include <stdio.h>
void func(int *p)
{
*p = 20;
}
int main()
{
int a = 10;
func(&a);
printf("%d\n", a);
return 0;
}
Bir fonksiyon bir deer elde edip, aran fonksiyona bu deeri iletmek isterse 2 yntem
kullanlabilir:
1. Elde edilen deer arlan fonksiyon tarafndan geri dn deeri olarak retilir.

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;

void factorial(int n, long *p);


{
if (n == 0 || n == 1)
*p = 1;
for (*p = 1; n > 0; n--)
*p *= n;
}
a bir yerel deiken olsun. C dilinde bir fonksiyon
func(a);
biiminde arlmsa, arlan bu fonksiyonun, a deikenini deitirme ans yoktur. (Bu tr
fonksiyon armna "deer ile arma" (call by value) denmektedir. Fonksiyonun a
deikenini deitirebilmesi iin
func(&a);
biiminde arlmas gerekir. rnein scanf fonksiyonuna & operatr ile bir nesnenin
adresinin arguman olarak yollanmasnn nedeni budur. Bu ekilde fonksiyon armaya C'de
"adres ile arma" (call by reference) denmektedir.
int trden iki yerel nesnenin deerlerini deitirmek (swap etmek) istediimizi dnelim. Bunu
bulunduumuz fonksiyon ierisinde aadaki gibi yapabiliriz:
swap ileminin bir fonksiyon tarafndan yaplmasn istersek, aadaki gibi bir fonksiyon iimizi
grr myd?
Yukardaki program altldnda ekrana
a = 10
b = 20
yazacaktr. Zira swap fonksiyonu a ve b deikenlerinin deerlerini deitirmemitir. Zaten
yerel nesneler olan a ve b deikenlerinin deerleri ancak adresleri bir fonksiyona gnderilerek
deitirilebilirdi. Oysa bizim yukardaki swap fonksiyonumuz a ve b deikenlerinin deerlerini
parametre deikenleri olan x ve y deikenlerine kopyalyor. Yani deerleri deitirilen

174

GSTERCLER
parametre deikenleri x ve y'nin deerleri. stediimiz amac gerekletirecek fonksiyon
dardan adres alaca iin gsterici parametre deikenlerine sahip olmal:

Dizilerin Fonksiyonlara Gstericiler Yoluyla Geirilmesi


Bir diziyi fonksiyona geirebilmek iin dizinin balang adresinin ve uzunluunun geirilmesi
yeterlidir. Dizinin balang adresini alacak parametre deikeninin ayn trden bir gsterici
olmas gerekir. Fonksiyonun 2. parametresi dizinin uzunluunu tutacak int trden bir deiken
olabilir. Bir dizinin balang adresini parametre olarak alan fonksiyon dizi elemanlarna keli
parantez operatr ya da ierik operatr ile eriebilir. Ancak dizi elemanlarnn ka tane
olduu bilgisi fonksiyon tarafndan bilinemez. Bu nedenle dizi uzunluunu ikinci bir parametre
olarak fonksiyona yolluyoruz. rnek:
Dizi uzunluu hakknda fonksiyona bilgi vermek amac ile baka teknikler de kullanlr. Dizi
uzunluunu dizinin birinci parametresinde saklayabiliriz. Yukardaki fonksiyonu, dizi uzunluunu
birinci dizi elemannda saklayarak yeniden yazalm:
Bir dizi ierisinde, zlen problemin koullarna bal olarak, belirli bir deerin bulunmas
olanakszsa, bu deer dizi sonunu belirten bir iaret olarak kullanlabilir. Bir dizi iinde
rencilerin aldklar notlar sakladmz varsayalm. rencilerin negatif bir not almalar
mmkn olmadna gre dizi ierisinde negatif bir say bulunamaz. Bu durumda biz -1 gibi bir
deeri dizi sonunu belirtmek amacyla kullanabiliriz. Yukardaki rnei yeniden yazalm:
n elemanl int trden bir dizinin aritmetik ortalamasn bulan getavg fonksiyonunu tasarlanmas:

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

average = getavg(s, 10);


printf("dizinin aritmetik ortalamas = %lf\n", average);
return 0;

double getavg(int *p, int size)


{
int i;
double total = 0;

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


total += p[i];
return total / size;

size elemanl int trden bir


yazlmas:

dizi ierisindeki en byk sayya geri dnen getmax isimli fonksiyonun

#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

printf("%d\n", getmax(s, 10));


return 0;

int getmax(int *p, int size)


{
int i, max;
max = p[0];
for (i = 1; i < size; ++i)
if (max > p[i])
max = p[i];
}

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

Geri Dn Deeri Adres Trnden Olan Fonksiyonlar


Bir fonksiyon parametre deikeni olarak bir gsterici alabildii gibi, adres trlerinden bir geri
dn deerine de sahip olabilir. Geri dn deerinin adres olduu, fonksiyon tanmlanrken *
operatr ile aadaki biimde belirtilmektedir.
<adresin tr> *<fonksiyon ismi> ([parametreler])
{
...
}
rnein int trden bir adrese geri dnen ve parametre deikeni almayan sample isimli
fonksiyon aadaki gibi tanmlanabilir:

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

Gstericilere likin Uyarlar ve Olas Gsterici Hatalar


Bir Gstericiye Farkl Trden Bir Adres Atanmas:
Bir gstericiye farkl trden bir adres atandnda, C derleyicileri durumu pheyle karlayarak
bir uyar mesaj verirler. Yani bu ilem hata (error) deil uyar gerektirmektedir. Ancak
derleyici yine de farkl trden adresin saysal bileenini hedef gstericiye atar. Borland
derleyicileri bu durumda aadaki uyar mesajn verirler:
warning : suspicious pointer coversion in function ......
Bu ilemin faydal bir gereke ile yaplma ihtimali zayftr. Ancak bazan bilinli olarak da
yaplabilir. O zaman bilinli olarak yapld konusunda derleyiciyi ikna etmek gerekmektedir.
int *p;
char s[ ] = "Ankara";
p = s;

/* uyar */

Uyar bilinli tr dntrmesiyle kesilebilir.


p = (int *) s;
Tr dntrme operatr kullanlarak char trden bir adres int trden bir adrese
dntrlmtr.
Bir gstericiye farkl trden bir adres atanmas durumunda, otomatik tr dnm
sonucunda, atama operatrnn sa tarafndaki ifadenin tr, atama operatrnn sol
tarafndaki nesnenin trne dntrlecek, ve dntrlm olan adres bilgisi nesneye
atanacaktr.
rnein int trden bir gstericiye char trden bir adres atadmz dnelim:
int main()
{
char s[20] = "Necati Ergin";
int *p;
p = s;
...
return 0;
}
Bu durumda int trden p gstericisini ierik operatr ya da indeks operatryle
kullandmzda elde ettiimiz nesne char trden deil int trden olacaktr. Byle bir durumun
bilinli olarak yaplm olma ihtimali azdr, ve bilinli olarak yaplmas durumunda tr
dntrme operatr kullanlarak, derleyicinin verecei uyar mesaj kesilmelidir. (derleyici
ikna edilmelidir)
C++ dilinde bir gstericiye farkl trden bir adres atanmas durumunda, derleme zamannda
hata oluacaktr. Yani bu durum uyar seviyesinden error seviyesine ykseltilmitir.

Bir Gstericiye Adres Olmayan Bir Deerin Atanmas


Bu da bilinli olarak yaplma ihtimali ok az olan bir ilemdir. C derleyicileri pheli olan bu
durumu bir uyar mesaj ile programcya bildirirler. rnein bu uyar mesaj Borland
derleyicilerinde:
"nonportable pointer conversion"

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

Yazlarn Fonksiyonlara Parametre Olarak Geirilmesi


Yazlar karakter dizilerinin ierisinde bulunurlar. Bir yazy fonksiyona parametre olarak
geirebilmek iin yaznn yalnzca balang adresini fonksiyona geirmek yeterlidir. Yani
fonksiyon yaznn (karakter dizisinin) balang adresi ile arlr. Yazy iinde tutan char
trden dizinin uzunluk bilgisini fonksiyona geirmeye gerek yoktur. nk yazlar saklamak
amacyla kullanlan karakter dizilerinin sonu null (ASCII karakter tablosnda 0 sra numaral
karakter.) karakterle iaretlenmitir. Karakter dizileri zerinde ilem yapan algoritmalar dizinin
sonunu null karakter yardmyla belirlerler.
Yazlarla ilem yapan fonksiyon char trden bir gsterici ile zerinde ilem yapaca karakter
dizisinin balang adresini alr. Fonksiyon, null karakter grene kadar bir dng ile yaznn
btn karakterlerine eriir.
str char trnden bir gsterici olmak zere yaz zerinde null karakter grene kadar ilem
yapabilecek dngler yle oluturulabilir:
while (*str != '\0') {
...
++str;
}
for (i = 0; str[i] != '\0'; ++i) {
...
}
rnein puts fonksiyonunun parametre deikeni char trnden bir gstericidir. puts fonksiyonunu
myputs ismi ile yeniden yazalm:

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;

Yazlarla lgili lem Yapan Fonksiyonlar


Bir grup standart C fonksiyonu vardr ki, bu fonksiyonlar bir yaznn balang adresini
parametre olarak alarak yaz ile ilgili birtakm faydal ilemler yaparlar. Bu fonksiyonlara string
fonksiyonlar denir. String fonksiyonlarnn prototipleri string.h dosyas iindedir. Bu
fonksiyonlardan bazlarn inceleyelim :

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

printf("bir yaz giriniz : ");


gets(s);
printf("%d\n", strlen(s));
return 0;

standart C fonksiyonu olan strlen fonksiyonunu kendimiz yazsaydk aadaki biimlerde


yazabilirdik:
#include <stdio.h>
unsigned
unsigned
unsigned

strlen1 (char *str);


strlen2(char *str);
strlen3(char *str);

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;

while (*str != '\0) {


++length;
++str;
}
return length;

unsigned int strlen2(char *str)


{
unsigned int len;
for (len = 0; str[len] != '\0'; ++len)
;
return len;
}
unsigned int strlen3(char *str)
{
char *ptr = str;

while (*str != '\0')


str++;
return str - ptr;

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

Bu fonksiyon, 2. parametresi olan ch karakterini, 1. parametresi olan str adresinden


balayarak null karakter grene kadar arar. (Aranan karakter null karakterin kendisi de
olabilir.) Fonksiyonun geri dn deeri, ch karakterinin yaz iinde bulunabilmesi durumunda
ilk bulunduu yerin adresidir. Eer ch karakteri yaz iinde bulunamazsa, fonksiyon NULL
adresine geri dnecektir.
strchr fonksiyonunu kendimiz yazsaydk aadaki ekilde yazabilirdik:
#include <stdio.h>
#include <string.h>
int main()
{
char s[100];
char *p, ch;

printf("bir yaz giriniz : ");


gets(s);
printf("yaz iinde arayacanz karakteri giriniz : ")
scanf("%c", &ch);
p = strchr(s, ch);
if (p == NULL) {
printf("aranan karakter bulunamad\n");
else
puts(p);
return 0;

char *my_strchr(char *str, int ch)


{
while (*str != '\0) {
if (ch == *str)
return str;
++str;
}
if (ch == '\0')
return str;
return NULL;
}
Yukarda verilen main fonksiyonununda strchr fonksiyonunu ardmz yerde kendi
yazdmz my_strchr fonksiyonunu ararak fonksiyonun doru alp almadn test
edebiliriz.
if (ch == '\0')
return str;
deyimleri aranan karakterin null karakter olup olmadn test etmek iin eklenmitir. while
dngs yerine for dngs de kullanabilirdik;
...
int i;
for (i = 0; str[i] != '\0'; ++i)
if (ch == str[i])
return (str + i);
...

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;

for (i = 0; (dest[i] = source[i]) != '\0'; ++i)


;
return dest;

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
{

char *temp = dest;


while ((*source++ = *dest++) != '\0')
;
return temp;

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

strcat fonksiyonunu kendimiz yazsaydk aadaki ekilde yazabilirdik :


char *_strcat(char *s1, char *s2)
{
char *temp = s1;
while (*s1 != '\0')
++s1;
while ((*s1++ == *s2++) != '\0')
;
return temp;

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

strset fonksiyonunu kendimiz yazsaydk aadaki ekillerde yazabilirdik :


#include <stdio.h>
char *_strset(char *str, int ch)
{
int i;
for (i = 0; str[i] != '\0'; ++i)
str[i] = ch;
return str;
}
char *_strset2(char *str, int ch)
{
char *temp = str;

while (*str != '\0') {


*str = ch;
++str;
}
return temp;

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

printf("parolay giriniz : ");


gets(s);
if (!strcmp(s, password))
printf("Parola doru!..\n");
else
printf("Parola yanl!..\n");
return 0;

strcmp fonksiyonunu kendimiz yazsaydk aadaki ekillerde yazabilirdik :


int _strcmp(char *s1, char *s2)
{
while (*s1 == *s2) {
if (*s1 == '\0')
return 0;
++s1;
++s2;
}
return *s1 - *s2;
}
strrev fonksiyonu

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

printf("ters evirilecek yazy giriniz : ");


gets(s);
printf("yaznzn ters evrilmi hali : \n");
puts(setrev(s));
return 0;

strrev fonksiyonunu kendimiz yazsaydk aadaki ekilde yazabilirdik :


#include <string.h>
#include <stdio.h>
char *strrev(char *str)
{
int i, temp;
int length = strlen(str);

for (i = 0; i < length / 2, ++i) {


temp = str[i];
str[i] = str[length - i - 1];
str[length - i - 1] = temp;
}
return str;

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

n > strlen(source) ise NULL karakter ekleniyor.


#include <stdio.h>
#include <string.h>
int main()
{
char dest[100], source[100];
int n;
printf("birinci yazy giriniz : ");
fflush(stdin);
gets(dest);
printf("ikinci yazy giriniz : ");
gets(source);
printf("ikinci yazdan 1. yazya ka karakter kopyalamak istiyorsunuz : ");
scanf("%d", &n);
strncpy(dest, source, n);
printf("kopyalamadan sonra 1. yaznn yeni ekli : ");
puts(dest);
return 0;
}
strncpy fonksiyonunu kendimiz yazsaydk aadaki ekilde yazabilirdik :
#include <stdio.h>
char *_strncpy(char *dest, char *source, int n)
{
int i;

for (i = 0; i < n && source[i] != '\0'; ++i)


dest[i] = source[i];
if (n > i)
dest[i] = '\0';
return dest;

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
{

char dest[100], source[100];


int n;

printf("birinci yazy giriniz : ");


fflush(stdin);
gets(dest);
printf("ikinci yazy giriniz : ");
gets(source);
printf("ikinci
yazdan
1.
yaznn
sonuna
ka
istiyorsunuz : ");
scanf("%d", &n);
strncat(dest, source, n);
printf("eklemeden sonra 1. yaznn yeni ekli : ");
puts(dest);
return 0;
}

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

strupr ve strlwr fonksiyonlar


Standart C fonksiyonlar olmamalarna karn hemen hemen her derleyicide bulunurlar.
simleri string upper ve string lower kelimelerinin ksaltlarak birletirilmesinden elde edilmitir.
Bu fonksiyonlarn bir yaznn tm karakterleri iin byk harf kk harf dntrmesi
yaparlar. Fonksiyonlarn geri dn deerleri parametresi ile verilen adresin aynsdr. Geri
dn deerlerine genellikle ihtiya duyulmaz. Her iki fonksiyon da ingiliz alfabesinde olan
harfler iin dnm yaparlar. Trke karakterler iin de dnm yapacak bir fonksiyon
kullanmak istiyorsak kendimiz yazmalyz.
#include <stdio.h>
#include <string.h>
int main()
{
char s[ ] = "C programcs olmak iin ok almak gerekir!";
strupr(s);
puts(s);
return

0;

}
strupr ve strlwr fonksiyonlarn kendimiz de aadaki ekilde
#include <stdio.h>,
#include <ctype.h>
char *_strupr(char *str)
{
char *temp = str;

while (*str != '\0') {


if (islower(*str))
/* if (*str >= 'a' && *str <= 'z')
* str = toupper(*str);
/* *str = *str - 'a' + 'A'; */
++str;
}
return temp;

char *_strlwr(char *str)


{
char *temp = str;

190

*/

GSTERCLER

while (*str != '\0') {


if (isupper(*str))
/* if (*str >= 'A' && *str <= 'Z')
* str = tolower(*str);
/* *str = *str - 'A' + 'a'; */
++str;
}
return temp;

strlwr ve strupr fonksiyonlarnn trke versiyonlarn aadaki ekilde yazabiliriz :


#include <stdio.h>
#include <string.h>
#include <ctype.h>
char *struprtrk(char *str)
{
char trklower[ ] = "";
char trkupper[ ] = "I";
int index;
char *p, *temp;
temp = str;
while (*str != '\0') {
p = strchr(trklower, *str);
if (p) {
index = p - trklower;
*str = trkupper[index];
}
else
*str = toupper(*str);
++str;
}
return temp;
}
char *strlwrtrk(char *str)
{
char trklower[ ] = "";
char trkupper[ ] = "I"
int index;
char *p, *temp;

temp = str;
while (*str != '\0') {
p = strchr(trkupper, *str);
if (p) {
index = p - trkupper;
*str = trklower[index];
}
else
*str = tolower(*str);
++str;
}
return temp;

char trden bir gstericiyi NULL karaktere teleme


Bir gstericiyi NULL karakteri gsterir hale getirmek iin 3 yntem kullanlabilir :
char *p;

191

*/

19
i.

p += strlen(p);

ii.

p = strchr(p, '\0');

iii.

while (*p != '\0')


++ptr;

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;

/* p gstericisinin iinde rasgele bir adres var */


/* p gstericisinin iindeki adreste buluna nesneye 25 deeri atanyor */

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

/* NULL pointer assignment */

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

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


a[k] = 0;
...

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;

/* herhangi bir uyar mesaj alnmaz */

p = str;

/* herhangi bir uyar mesaj alnmaz */

Benzer biimde fonksiyon arma ifadelerinden argumanlarn fonksiyon parametre


deikenlerine kopyalanmasnda da, void gstericiler sz konusu olduunda, adres trlerinin
farkllndan dolay uyar mesaj alnmaz.
funk1(void *p)
{
...
}
main()
{
int *ptr;
...
funk1(ptr);
}

/* p = ptr gibi bir atama ilemi yaplmaktadr. Uyar mesaj alnmaz. */

funk2(int * p)
{
...
}
195

19

int main()
{
void *ptr;
...
funk2(ptr);
}

/* p = ptr gibi bir atama ilemi yaplmaktadr. Uyar mesaj alnmaz. */

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;

/* error! void trden adresler birbirinden karlamaz! */

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

/* hata olumaz ve uyar mesaj alnmaz. */


/* hata olumaz ve uyar mesaj alnmaz. */

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

aadaki fonksiyon ar da edeerdir.


char s[50] = Ali;
char d[50];
strcpy(d, s);
memcpy(d, s, strlen(s) + 1);
memcpy fonksiyonunun gsterici olan parametreleri void trdendir. nk hangi trden adres
geirilirse geirilsin, derleyicilerden herhangi bir uyar mesaj alnmaz.
void memcpy(void *dest, void *source, int n);
ancak memcpy fonksiyonunun akk bloklarn kopyalanmasnda davran standart deildir.
akk bloklarn kopyalanmasnda ayr prototipe sahip olan memmove fonksiyonu tercih
edilmelidir. zellikle dizi elemanlarnn kaydrlmas gibi uygulamalarda akk bloklarn
kopyalanmas sz konusu olabilir. Bu durumda memmove fonksiyonu tercih edilmelidir.
Standart Cde ba mem ile balayan mem.... biiminde bir grup fonksiyon vardr. Bu
fonksiyonlar trden bamsz olarak byte says ile ilem yaparlar.
memset fonksiyonu
prototipi :
memset(void *p, char ch, int n);
Bu fonksiyon 1. parametresiyle belirtilen adresten balayarak n tane byte' , 2. parametresiyle
belirtilen bilgiyle doldurulur. Bu fonksiyon herhangi trden bir diziyi sfrlamak amacyla
kullanlabilir. rnein :
double d[100];
memset(d, 0, sizeof(d));
void gsterici parametresine sahip olan fonksiyonlarn yazlmas :
Byle bir fonksiyon yazlrken parametre deikeni olan void gsterici nce tr belirli bir
gstericiye atanr, daha sonra ilemler bu gstericiyle gerekletirilir.
rnek 1 :
void *mymemcpy (void *dest, void *source, int n)
{
char *-dest = (char *) dest;
char *_source = (char *) source;
int i;

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


_dest[i] = _source[i];
return dest;

ayn fonksiyonu u ekilde de yazabilirdik :


void *mymemcpy (void *dest, void *source, int n)
{
char *-dest = (char *) dest;
char *_source = (char *) source;
198

GSTERCLER

while (n-- > 0)


*_dest++ = *_source++;
return dest;
}
int main()
{
int a[5] = {1, 2, 3, 4, 5};
int b[5], i;
mymemcpy(b, a, 10);
for (i = 0; i < 5; ++i)
printf(%d\n, b[i]);
}
memset fonksiyonunun yazlmas
#include <stdio.h>
void *mymemset(void *p, int x, int n);
int main()
{
int a[10];
int i;
mymemset(a, 0, 20);
for (i = 0; i < 10; ++i)
printf(%d\n, a[i]);
return
}

0;

void *mymemset(void *p, int x; int n);


{
char *_p = (char *)p;
while (n-- > 0)
* _p++ = x;
return p;
}

Gstericilerle lgili rnek Uygulamalar


Uygulama 1 : long trden bir sayy verilen bir adrese virgllerle ayrarak string olarak yazan longtoa
fonksiyonunun yazlmas. Fonksiyon gnderilen adrese geri dnecektir.

#include <stdio.h>
#include <string.h>
#define NEGATIVE
#define POSITIVE

(-1)
1

char *longtoa(long val, char *str)


{
int i, sign;
char digit;
if (val < 0) {
sign = NEGATIVE;
val = -val;
199

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

char *mystrstr(char *s1, char *s2)


{
200

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>

int gettrknum(char *str);


void main()
{
char s[100];
printf("YAZIYI GRNZ : ");

gets(s);
printf("\ntrke karakter says = %d", gettrknum(s));

int gettrknum(char *str)


{
int counter = 0;
int i;

char trk[ ] = "";


for (i = 0; str[i] != '\0'; ++i)
if (strchr(trk, str[i]))
++counter;
return counter;

Uygulama 4: Byk harf kk harf duyarl olmadan iki stringi karlatran fonksiyon.

#include
#include
#include
#include

<stdio.h>
<conio.h>
<string.h>
<ctype.h>

int mystricmp(char *s1, char *s2);


void main()
{
char s1[100];
char s2[100];
int result;
int n = 10;
while (n-- > 0) {

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

gstericilerle ilgili rnek uygulamalar


/*
mystrstr.c
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.
*/

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

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

/*
trknum.c
klavyeden girilen bir yaz ierisindeki trke karakterlerin
saysn bulan fonksiyon
*/
#include
#include
#include
#include

<stdio.h>
<conio.h>
<string.h>
<ctype.h>

int gettrknum(char *str);


int main()
{
char s[100];
printf("YAZIYI GRNZ : ");
gets(s);
printf("ntrke karakter says = %d", gettrknum(s));
return 0;
}
int gettrknum(const char *str)
{

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>

int mystricmp(char *s1, char *s2);


int main()
{
char s1[100];
char s2[100];
int result;
int n = 10;
while (n-- > 0) {
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();
}
return 0;
}
int mystricmp(char *s1, char *s2)
{
while (toupper(*s1) == toupper(*s2)) {
if (*s1 == '_)
return 0;
++s1;
++s2;
}
return toupper(*s1) - toupper(*s2);
}

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

int wcount(const char *str)


{
int w_count = 0;
int state_flag = OUT;
while (*str != ' ') {
if (isspace(*str) || ispunct(*str))
state_flag = OUT;
else if (state_flag == OUT) {
state_flag = IN;
++w_count;
}
++str;
}
return w_count;
}
int main()
{
char s[MAX_LEN];
printf("bir yaz giriniz : ");
gets(s);
printf("yaznzda %d szck var!.\n", wcount(s));
return 0;
}

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.

Stringlerin Fonksiyonlara Arguman Olarak Gnderilmesi


Parametre deikeni char trden bir gsterici olan fonksiyonu char trden bir adres ile
armak gerektiini biliyoruz. nk doal olarak char trden bir gstericiye char trden bir
adres atanmaldr.
Derleyiciler asndan stringler de char trden bir adres belirttiklerine gre, parametre
deikeni char trden gsterici olan bir fonksiyonu bir string ile armak son derece doal bir
durumdur, ve C dilinde bu yap ok kullanlr:
puts("Necati Ergin");
Burada derleyici "Necati Ergin" stringini bellee yerletirip sonuna NULL karakteri koyduktan
sonra artk bu stringi, karakterlerini yerletirdii bellek blounun balang adresi olarak
grecektir. puts fonksiyonunun parametre deikenine
de artk char trden bir adres
kopyalanacaktr. puts fonksiyonu parametre deikeninde tutulan adresten balayarak NULL
karakteri grene kadar tm karakterleri ekrana yazmaktadr. Bu durumda ekranda
Merhaba
yazs kacaktr. Baka bir rnek:
char str[20];
...
strcpy(str, "Kaan Aslan");
Bu rnekte de "Kaan Aslan" stringi str adresinden balayarak kopyalanmaktadr. String
ifadelerinin bulunduu yerde char trden bir adresin bulunduu dnlmelidir. imdi
aadaki ifadeyi yorumlayalm:
strcpy("Ali", "Kaan");

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;

printf("fark1 = %d\n", p - q);


printf("fark2 = %d\n", lp - lq);
return 0;

Yukardaki programn altrlmasyla ekrana:


fark1 = 8
fark2 = 2
yazlacaktr.
C derleyicileri kaynak kodun eitli yerlerinde tamamen zde stringlere rastlasa bile bunlar
iin farkl yerler ayrabilirler. Derleyici zde stringlerin sadece bir kopyasn da bellekte
saklayabilir. zde stringlerin nasl saklanaca baz derleyicilerde programcnn seimine
braklmtr. Derleyicinin ayarlar arasnda bu konuyla ilgili bir seenek bulunur.
rnein bir programn ierisinde:
printf("Dosya alamyor!..\n");
...
printf("Dosya alamyor!..\n");
...
printf("Dosya alamyor!..\n");
ifadelerinin bulunduunu varsayalm. Farkl yerlerde "Dosya alamyor!..\n" gibi zde stringler
bulunsa bile derleyici bunlar iin tekrar ve farkl yerler ayrabilir. Bu da byk uygulamalar iin
bellein verimsiz kullanlmasna yol aabilir.
Bellekte yer ayrma ilemi derleme aamasnda yaplmaktadr. Aadaki kod parasnn
altrlmasyla ekrana hep ayn adres baslacaktr :
char *p;

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

printf(ad ve soyad giriniz : );


gets(s);
return s;

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

Stringlerde Ters Bl Karakter Sabitlerinin Kullanlmas


Stringler ierisinde ters bl karakter sabitleri de (escape sequence) kullanlabilir. Derleyiciler
stringler ierisinde bir ters bl karakteri grdklerinde, onu yanndaki karakter ile birlikte tek
bir karakter olarak ele alrlar. rnein:
char *p;
p = "Necati\tErgin";
ifadesinde \t bir karakterdir. (9 numaral ASCII carakteri olan tab karakteri)
yani
printf("stringdeki karakter says = %d\n", strlen(p));
ifadesi ile ekrana
stringdeki karakter says = 12
yazdrlacaktr.
String ifadelerinde dorudan ift trnak ya da ters bl karakterleri kullanlamaz, nk bu
karakterlerin zek ilevi var. ift trnak karakter sabitinin kendisini ifade etmek iin ift tirnak
karakterinden nce bir ters bl karakteri kullanlr. rnein:
p = "\"Necati Ergin\"";
gibi bir string ifadesi geerlidir. Bu durumda
puts(p);
ile ekrana
"Necati Ergin"
yazs baslacaktr.

Stringlerle Gstericilere lkdeer Verilmesi


Stringler kullanlarak char trden gstericilere ilkdeer verilebilir. rnein:
char *p = "stanbul";
char *err = "Bellek yetersiz";
char *s = "Devam etmek iin bir tua basnz";
...
String ifadeleri aslnda char trden bir adres olduuna gre ilk deer verilen gstericilerin de
char trden gstericiler olmas gerekir. Dizilere iki trnak ierisinde ilk deer vermeyle
gstericilere stringlerle ilk deer verme arasndaki ayrma dikkat etmek gerekir.
char *p = "Deneme";
char s[10] = "Deneme";
ifadeleri tamamen farkldr.
Gstericilere ilkdeer verildiinde derleyici bunu bir string ifadesi olarak ele almaktadr. Yani
string bellee yerletirildikten sonra balang adresi gstericiye atanr. Oysa dizilerde nce dizi
iin yer ayrlr, daha sonra karakterler tek tek dizi elemanlarna yerletirilir. Dizilere ilkdeer
verirken kullandmz iki trnak ifadeleri adres belirtmezler (string deildireler). Dizi
211

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

/ * Diziye yaznn karakterleri klavyeden alnyor */


/* s3 dizisinin elemanlar s2 dizisi iine kopyalanyor */

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

21 . BLM : GSTERC DZLER


Gstericiler de birer nesne olduguna gre gsterici dizileri de tanmlanabilmelidir.
Elemanlar gstericilerden oluan dizilere gsterici dizileri (pointer arrays) denir. Bildirimleri aadaki
ekilde yaplr :
<tr> *<dizi ismi [dizi_uzunluu];>
rnein :
char *s[10];
int *sample[50];
float *kilo[10];
Gsterici dizilerinin bildirimleri normal dizi bildirimlerinden farkl olarak * operatr ile yaplmaktadr. rnein:
char str[100];
bildiriminde, str 100 elemanl char trden bir diziyken
char *str[100];
bildiriminde ise, str 100 elemanl char trden bir gsterici dizisidir.
Derleyici bir gsterici dizisi tanmlamas ile karlanca dier dizilerde yapt gibi, bellekte belirtilen sayda
gsteriyi tutabilecek kadar ardl yer tahsis eder. rnein:
char *p[10];
bildirimi ile derleyici, s dizisinin 10 elemanl ve her elemann char trden bir gsterici olduunu anlar.
Kullanlan sistemde gstericilerin uzunluunun 2 byte olduunu kabul edersek, 20 byte srekli bir blge
tahsis edecektir. Bu durumda;
p[0], p[1], p[2], ...p[9]
dizi elemanlarnn her biri char trden bir gstericidir. Elemanlarndan her biri dierinden bamsz olarak
kullanlabilir ve her bir eleman bir nesnedir. Aadaki rnei inceleyiniz :
main()
{
char *s[10];
int k;
for (k = 0; k < 10; ++k)
s[k] = (char *) malloc(30);
if (s[k] == NULL) {
printf("cannot allocate memory!..\n");
exit(EXIT_FAILURE);
}
printf("ismi giriniz : ");
gets(s[k]);
}
Bu rnekte her eleman char trden bir gsterici olan, 10 elemanl bir gsterici dizisi alm ve dizinin her
eleman iin, dng ierisinde malloc fonksiyonu ile 30 byte byklnde bir bellek blou tahsis
edilmitir.Tahsis edilen bloklarn balang adresleri gsterici dizisinin elemanlarna yerletirildikten sonra,
gets fonksiyonu ile klavyeden girilen karakterlerin tahsis edilen bloklara aktarlmtr. s isimli dizi yerel bir dizi
olduuna gre, dizi elemanlar ierisinde rasgele (garbage values) deerler olduunu belirtelim. Dolaysyla
malloc fonksiyonu ile yer ayrmadan yaplan veri aktarmlar gsterici hatalarna yol aacaktr.
Dinamik olarak tahsis edilen alanlar, gerektii zaman yine bir dng yardmyla serbest braklabilir :

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

22 . BLM : GSTERCY GSTEREN


GSTERCLER
konu eklenecek.

218

DNAMK BELLEK YNETM

23 . BLM : DNAMK BELLEK YNETM


C dilinde bir dizi tanmland zaman, bu dizi iin derleyici tarafndan bellekte yer ayrlr.
rnein:
int a[100];
Derleme srasnda yukardaki gibi bir dizi tanmlamas ile karlaan derleyici bellekte (eer
kullanlan sistemde int tr uzunluunun 2 byte olduu varsaylrsa) toplam 200 byte yer
ayracaktr. Programn almas srasnda bir dizinin uzunluunu deitirmek mmkn deildir.
Diziler konusunda akland gibi, dizi tanmlama ifadelerinde dizi boyutunu gsteren ifade
(keli parantezin ierisindeki ifade) sabit ifadesi olmaldr, deiken ieremez. nk
derleyicinin bellekte yer ayrmas iin, dizi boyutunu bilmesi gerekir. Oysa pratikte birok
uygulamada almas gereken dizinin boyutu programn almas srasnda (runtime)
belirlenmektedir.
Birtakm saylarn kullanlmak zere klavyeden girildiini dnelim. Kullancnn ka tane say
gireceinin belli olmadn dnelim. Kullancnn girdii saylar tutmak iin alan bir dizinin
boyutu ne olmaldr? Ya da bir dizindeki dosyalar sraya gre dizmek iin dosya bilgilerini geici
olarak bir dizide saklayacamz dnelim. Dizinin uzunluu ne olmaldr? Bu balangta belli
deildir. nk dizin iinde ka dosya olduu belli deildir. Bu tr rnekleri oaltabiliriz. Bu
tip durumlara zellikle veri taban uygulamalarnda sklkla raslarz. Baz uygulamalarda dizilerin
gerek uzunluu programn almas srasnda, ancak birtakm olaylar sonucunda kesin olarak
belirlenebilir. Bu durumda dizilerle alan programc herhangi bir gsterici hatasyla
karlamamak iin dizileri en kt olasl gznnde bulundurarak amak zorundadr. Bu da
bellein verimsiz bir ekilde kullanlmas anlamna gelir. stelik alan diziler yerel ise ilgili blok
sonlanana kadar, global ise programn almasnn sonuna kadar bellekte tutulacaktr. Oysa,
dizi ile ilgili ilem biter bitmez, dizi iin ayrlan bellek blgesinin boaltlmas verimli bellek
kullanm iin gereklidir.
Programn alma zaman srasnda belli byklkte ardl (contigious) bir bellek blgesinin
programc tarafndan tahsis edilemesine ve istenildii zaman serbest braklmasna olanak
salayan yntemlere dinamik bellek ynetimi denir. C dilinde dinamik bellek ynetimi dinamik
bellek fonksiyonlaryla yaplmaktadr. Dinamik bellek ynetiminde kullanlan standart C
fonksiyonlar hakknda aada detayl bilgi verilmektedir. phesiz bu fonksiyonlarn dnda,
ticari derleyici paketlerinin ktphanesinde, standart olmayan dinamik bellek fonksiyonlar da
bulunabilir. Ancak yazlan kaynak kodun tanabilirlii asndan standart C fonksiyonlar tercih
edilmelidir.
imdi dinamik bellek ynetiminde kullanlan standart C fonksiyonlarn tek tek detayl olarak
inceleyelim:

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

/* bellekte 30 byte'lk bir yer tahsis edilmek isteniyor */

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

if (!(p1 && p2 && p3 && p4 && p5)) {


printf("cannot allocate memory!..\n");
exit(EXIT_FAILURE);
}
malloc fonksiyonu bloklarn herhangi birinde baarsz olursa bu durum if deyimi iinde tespit
edilmektedir.
malloc fonksiyonunun geri dn deeri void trden bir adres olduu iin, bu adres
sorunsuzca her trden gstericiye atanabilir. Ancak okunabilirlik asndan malloc
fonksiyonunun geri dn deeri olan adresin, tr dntrme operatr yardmyla,
kullanlacak gstericinin trne dntrlmesi tavsiye edilir. Bylece malloc fonksiyonu ile

220

DNAMK BELLEK YNETM


tahsis edilen bloun ne trden bir diziymi gibi kullanlaca bilgisi de aka okuyucuya
verilmi olabilir.
C dilinin standartlatrlmasndan nceki dnemde void trden gstericiler olmad iin, malloc
fonksiyonunun geri dn deeri char trden bir adresti ve bu durumda, geri dn deeri
olan adresin, char tr dnda bir gstericiye atanmas durumunda tr dnm bir
zorunluluktu.
int trden bir dizi iin dinamik olarak tahsisat yaptmz dnelim. rnein bir kullancnn
klavyeden int trden saylar gireceini dnelim. Kullancdan, ka tane say girecei bilgisi
alnsn ve istenilen miktardaki sayy saklayabilecek bir alan dinamik olarak tahsis edilsin.
int main()
{
int number;
int i;
int *ptr;

printf("ka tane say girmek istiyorsunuz? ");


scanf("%d", &number);
ptr = (int *) malloc(number * 2);
...
return 0;

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

DNAMK BELLEK YNETM


rnein 50 elemanl int trden bir dizi iin bellekten bir blou dinamik olarak tahsis ettikten
sonra sfrlamak istediimizi dnelim. Bu ilemi malloc fonksiyonu ile yaparsak, diziyi ayrca
dng ierisinde sfrlamamz gerekecektir :
int *ptr;
int i;
...
ptr = (int *) malloc(sizeof(int) * 100);
if (ptr == NULL) {
printf("cannot allocate memory!..\n");
exit(EXIT_FAILURE);
}
for (i = 0; i < 100; ++i)
ptr[i] = 0;
...
Oysa calloc fonksiyonu zaten sfrlama ilemini kendi ierisinde yapmaktadr.
calloc fonksiyonu, bellek tahsisatn yapabilmek iin, kendi iinde malloc fonksiyonunu arr.

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

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


/* 2 */
ptr[i] = i;
ptr = realloc(ptr, sizeof(int) * 10); /* 3 */
if (ptr == NULL) {
printf("bellek yetersiz!..\n");
exit(EXIT_FAILURE);

}
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

2. Bir dng yardmyla tahsis edilen alana atamalar yaplyor.


1A00
1A01

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

DNAMK BELLEK YNETM


ptr------>

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

realloc fonksiyonunun bu davranndan dolay mutlaka geri dn deeri bir gstericiye


atanmaldr. Aada sk yaplan ok tipik bir hata grlmektedir:
int main()
{
char *p;
p = malloc(10);
if (p == NULL) {
printf(can not allocate memory!..\n");
exit(EXIT_FAILURE);
}
...
if (realloc (p, 20) == NULL) {
printf(can not allocate memory!..\n");
exit(EXIT_FAILURE);
}
gets(p);
return 0;
}
realloc fonksiyonunun baarl olmas tahsis edilen bloun altnda ilave tahsisat yapld
anlamna gelmez. (realloc fonksiyonu daha nce tahsis edilmi alan baka bir yere tayarak
yeni bloun balang adresiyle geri dnm olabilir. Bu durumda eski blok serbest braklr ve
artk bu adresin bir gvenilirlii yoktur.
Yukardaki rnekte realloc fonksiyonunun tahsisat daha nce tahsis edilen blou byterek
yapt varsaylmtr. Eer realloc fonksiyonu bir tama yapmsa, yukardaki kodda bir
gsterici hatas yaplm olacaktr, nk artk p gstericisinin gsterdii adres gvenilir bir
adres deildir.
Bu yzden uygulamalarda genellikle realloc fonksiyonunun geri dn deeri, realloc
fonksiyonuna gnderilen 1. adresi iinde tutan gstericiye atanr.
ptr = realloc(ptr, 100);
gibi. Ancak bu bir zorunluluk deildir. Eer realloc fonksiyonu ile yaplan tahsisatn baarl
olmamas durumunda program sonlandrlmayacaksa (rnein artk daha fazla tahsisat
yaplamamas durumunda) daha nce dinamik olarak tahsis edilen blgedeki deerler bir
dosyaya yazlacak ise, artk realloc fonksiyonunun baarsz olmas durumunda, ptr
gstericisine NULL adresi atanaca iin ptr gstericisinin daha nce tahsis edilen blok ile ilikisi
kesilmi olacaktr.
225

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>

void display_array(int *ptr, int size);


int find_max(int *ptr, int size);
int find_min(int *ptr, int size);
double find_ave(int *ptr, int size);
double find_stddev(int *ptr, int size);
int main()
{
int *ptr = NULL;
int ch, grade;
int counter = 0;
clrscr();
for (;;) {
printf("not girmek istiyor msunuz? [e] [h]\n");
while ((ch = toupper(getch())) != 'E' && ch != 'H')
;
if (ch == 'H')
break;

226

DNAMK BELLEK YNETM


printf("notu giriniz : ");
scanf("%d", &grade);
counter++;
ptr = (int *) realloc(ptr, sizeof(int) * counter);
if (ptr == NULL) {
printf("cannot allocate memory!..\n");
exit(EXIT_FAILURE);
}
ptr[counter - 1] = grade;

}
if (counter == 0) {
printf("hibir not girii yapmadnz!..\n");
return 0;
}
printf("toplam %d tane not girdiniz\n", counter);
printf("girdiiniz notlar aada 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");

/* yanl, bir gsterici hatas!! */

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

DNAMK BELLEK YNETM


#include <stdlib.h>
char *getname(void)
{
char s[30];
char *ptr;
printf("ismi giriniz : ");
gets(s);
ptr = (char *) malloc(strlen(s) + 1);
if (ptr == NULL) {
printf("cannot allocate memory!..\n");
exit(EXIT_FAILURE);
}
strcpy(ptr, s);
return ptr;
}
Yukardaki fonksiyonda kullancdan isim nce kullancdan, yerel bir diziye alnyor. Daha sonra
strlen fonksiyonu kullanlarak ismin uzunluu tespit ediliyor ve malloc fonksiyonu ile bu ismi ve
sonuna gelecek NULL karakteri iine alacak byklkte bir alan dinamik olarak tahsis ediliyor.
Daha sonra da strcpy fonksiyonu kullanlarak, isim dinamik olarak tahsis edilen alana
kopyalanayor ve bu bloun balang adresine geri dnlyor.
Dinamik tahsisat fonksiyonun arlmas neticesinde yaplacak ve tahsis edilen bloun serbest
braklmas fonksiyonu arann sorumluluunda olacaktr :
int main()
{
char *p;
...
p = getname();
...
free(p)
...
return 0;
}
Bir fonksiyon iinde dinamik olarak bir bellek blou tahsis etmek ve daha sonra bu bloun
balang adresine geri dnmek C dilinde ok kullanlan bir tekniktir:
Aada tasarm verilen strcon fonksiyonu birinci parametresinde balang adresi tutulan
yaznn sonuna ikinci parametresinde balang adresi tutulan yazy kopyalayacak fakat her iki
adresteki yazlar da bozmadan, birletirilmi yaznn balang adresi olan bir adrese geri
dnecektir. Bu dinamik bellek fonksiyonlarnn kullanlmasyla mmkndr :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *strcon(const char *s1, const char*s2)
{
char *ptr;
ptr = malloc (strlen(s1) + strlen(s2) + 1);
if (ptr == NULL) {
printf(cannot allocate memory..\n");
exit(EXIT_FAILURE);
}

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.

Yer ve Tr Belirleyicileriyle Bildirim lemi


Bildirimin genel biimi:
[yer belirleyici] [tr belirleyici] <tr> nesne1, [nesne2], [nesne3], ...
auto
const
register
volatile
static
extern
Yer belirleyici, tr belirleyici ya da tr ifade eden anahtar szcklerin dizilimi herhangi bir
biimde olabilir.
auto const unsigned long int
const auto unsigned long int
unsigned long int auto const
int const long auto unsigned

a;
a;
a;
a;

Yukardaki bildirimlerin hepsi geerli bildirimlerdir. Ancak okunabilirlik asndan bildirimlerin


yukardaki genel biime uygun olarak yaplmas tavsiye edilir.
Eer bir bildirimde yer ya da tr belirleyicileri bir tr bilgisi olmadan kullanlrsa, nceden
seilmi (default) olarak int tr bildirimin yapld kabul edilir.
const a;/* const int a; bildirimi ile edeerdir. */
imdi yer ve tr belirleyicilerini tek tek detayl olarak inceleyelim :

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;

/* hata x deikeni global register belirleyicisi ile kullanlamaz */

int sample (register int y)


/* hata deil */
{
register float x;
/* hata deil */
...
}
Ne kadar deikenin yazmalarda saklanabilecei bilgisayar donanmlarna ve derleyicilere
baldr. Ayrca, uzunluu tamsay (int) trnden byk olan trler genellikle yazmalarda
saklanamazlar bu durumlarda da derleyicilerden hata veya uyar mesaj beklenmemelidir.
232

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:

static Anahtar Szcnn Yerel Deikenlerle Kullanlmas


static yer belirleyicisine sahip olan yerel deikenler programn icras boyunca bellekte kalrlar.
Baka bir deyile, static anahtar szc yerel deikenlerin mrn uzatmaktadr. Statik
yerel deikenler tpk global deikenler gibi programn almaya balamasyla yaratlrlar ve
programn icras bitene kadar da bellekte tutulurlar.
Statik yerel deikenler programc tarafndan ilk deer verildikten sonra kullanlrlar. lk deer
verme ilemi programn almas srasnda deil, derleme zamannda derleyici tarafndan
yaplr. (Derleyici bellekten yer ayrlmasna yol aacak makine kodunu oluturur ve statik
deiken iin bellekte yer programn yklenmesi srasnda ayrlr. "Derleyici tarafndan bellekte
yer ayrlr." derken bunu kastediyoruz. Derleme zamannda gerekten bellekte yer ayrlmyor,
bellekte yer ayrma iini yapacak makine kodu yaratlyor.) Statik yerel deikenler ilk
deerleriyle birlikte bellee yklenirler. rnek :
int statfunc(void)
{
static int x = 12;
/* bu ksm yalnzca derleme srasnda ve bir kez ilem grr */
++x;
/* fonksiyonun her arlnda yeniden yaratlmaz ve deerini korur */
return x;
}
void main()
{
printf(a = %d\n, statfunc()); /* a = 13 */
printf(a = %d\n, statfunc()); /* a = 14 */
}
Yukarda verilen rnekte statfunc() fonksiyonunun ierisindeki yerel x deikeninin deeri
fonksiyonun her arlnda bir artrlr. nk x statik yerel deiken olduu iin, fonksiyonun
her arlnda yeniden yaratlmayacak, en son ald deeri koruyacaktr.
Daha nce sylendii gibi, bir adres deerine geri dnen fonksiyonlar yerel deikenlerin
adreslerine geri dnmemelidir. Ancak yerel deikenin statik olarak tanmlanmas durumunda,
statik bir yerel deiken programn sonlanmasna kadar bellekteki yerini koruyacandan,
fonksiyonun statik bir yerel deikenin adresine geri dnmesinde bir saknca yoktur:
char * funk(void)
{
static char ch;
...
return &ch;
}
Diziler bir ya da daha fazla nesnenin bir arada tanmland veri yaplar olduguna gre, yerel
diziler de static anahtar szcyle tanmlanabilirler.
233

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.

Statik Yerel Deikenler le Global Deikenlerin Karlatrlmas


Statik yerel deikenler mr asndan global yerel deikenler ile ayn zellikleri gsterirler.
Yani programn almaya balamas ile yaratlrlar ve programn almas bitince mrleri
sona erer. Ama faaliyet alan (scope) asndan farkllk gsterirler. Global deikenler dosya
faaliyet alanna uyarken statik yerel deikenler blok faaliyet alanna uyarlar. Statik yerel
deikenlerin faaliyet alanlarnn dar olmas (blok faaliyet alanna sahip olmas) soyutlamay
(abstraction) ve yeniden kullanlabilirlii (reusability) kuvvetlendirmektedir. nk global
deikenlere bal olan fonksiyonlar projeden projeye tanamazlar ve kendi ilerinde bir
btnlk oluturmazlar.

static Anahtar Szcnn Global Deikenler le Kullanlmas


static belirleyicisi global bir deiken ile birlikte kullanlrsa, global deikenin faaliyet alann,
yalnzca tanmland modl kapsayacak biimde daraltr. Yani global deikenleri kendi
modlleri iine hapseder. Statik global deikenler yalnzca tanmlandklar modl ierisinde
faaliyet gsterebilirler. Statik global deikenleri daha iyi anlayabilmek iin modl kavramnn
ne olduunu bilmek zorundayz:
Bir proje birbirinden bamsz olarak derlenebilen birden fazla kaynak dosyadan oluabilir.
Projelerin bamsz olarak derlenebilen herbir kaynak dosyasna modl denir.
Bir projeyi oluturan farkl kaynak dosyalar birbirinden bamsz olarak derlendikten sonra,
hepsi birlikte balayc (linker) ile birletirilerek tek bir .exe dosyas oluturulur.

Byk Projelerin Modllere Ayrlmasnn Ne Gibi Faydalar Vardr


Eer btn modller tek bir kaynak kod ierisinde birletirilirse en ufak bir deiiklikte tm
proje tekrar derlenmek zorundadr. Oysa modllere ayrlm projelerde, yalnz deiikliin
yapld modln derlenmesi yeterlidir. nk dier modller zaten derlenmitir ve onlar
yalnzca balama aamasnda ilem grrler. Programlar modller halinde yazmann bir dier
avantaj da grup almas yaparken ortaya kar. Bu durumda projelerin bamsz paralar
(modlleri) ayr kiiler tarafndan hazrlanabilir.
Global bir deiken normal olarak tm modller ierisinde faaliyet gsterebilirken (Bu
durumda, bir sonraki konuda aklayacamz gibi dier, modllerde extern bildiriminin
yaplm olmas gerekmektedir.) statik global deikenler yalnzca tanmlandklar modl
ierisinde faaliyet gsterirler.
Global deikenler iin statik tanmlamasnn yalnzca faaliyet alan zerinde etkili olduuna,
mr zerinde etkili olmadna dikkat ediniz.
Farkl modllerde ayn isimli iki statik global deiken tanmlanabilir. Cde ayn faaliyet alanna
sahip ayn isimli birden fazla deiken tanmlanamaz kuraln anmsayalm. ki farkl modlde
tanmlanan ayn isimli iki statik global deikenin faaliyet alan farkldr.

234

BELRLEYCLER

extern Belirleyicisi ve Balant Kavram (Linkage)


extern belirleyicisini aklamadan nce linkage (balant) kavram zerinde durmak istiyoruz.
lk derslerimizde nesnelerin zelliklerinden birinin de balant (linkage) zellii olduunu
sylemitik. C standartlar ayr balant snf tanmlamtr :
1. D Balant (external linkage)
Bir modlde tanmlanan bir nesneye program oluturan baka modllerde de ulalabilmesi
zelliidir. Eer bir deikene baka bir modlde de tannabiliyorsa o deikenin d balants
var denir.
2. i balant (internal linkage)
Bir modlde tanmlanan bir nesneye yalnzca kendi modl ierisinde ulalabilmesi zelliidir.
Eer bir deiken ancak kendi modl ierisinde
tannabiliyorsa, dier modllerde
tannamyorsa, o deikenin i balants var denir.
3. balantsz (no linkage)
Bir modlde tanmlanan bir nesneye, o modl iinde yalnzca belirli bir blok iinde ulalabilmesi
zelliidir. Eer bir deiken ancak kendi modl ierisinde belirli bir blok dahilinde
tannabiliyor, bu blok dnda kendi modl iinde tannmyorsa, o deikenin balants yoktur
denir.
Global deikenlerin d balants varken, statik global deikenlerin i balants vardr. Yerel
deikenlerin balants yoktur.
Btn belirleyiciler iinde belki de anlalmas en g olan extern belirleyicisidir. extern
belirleyicisi genel olarak, derleyiciye nesnenin baka bir modlde tanmlandn bildirmek iin
kullanlr
Bir proje MOD1.C ve MOD2.C biiminde iki modlden olumu olsun :
MOD1.C
int a;
float fonk1()
{
...
a = 100;
...
}

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

MOD2.c modlnde x1 fonksiyonu iin yazlm olan prototip ifadesini inceleyiniz:


extern float x1(void);
Bu rnekte x1 fonksiyonu baka bir modlde tanml olduu iin prototip ifadesine extern
belirleyicisi konmutur. Ancak konulmasayd derleyici zaten extern varsayacakt. (Tpk yerel
deikenler iin auto belirleyicisini varsayd gibi.)

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;

/* x global bir deiken ama tanmlanmasndan nce yukarda kullanlm */

int fonk()
{
....
x
...
}

200;

yukardaki kod derlendiinde , main fonksiyonunun ierisindeki x deikeninin bildiriminin


bulunamadn ifade eden bir hata mesajyla karlalr. Bu durumda, eer bir global deiken
tanmlamadan nce kullanlyorsa, hata olumamas iin daha nce extern bildiriminde
bulunulmaldr.
extern int x;
void main()
{
...
x = 100;
}
int x;
int fonk()
{
....
x
...
}

200;

extern bildirimini bu ekilde kullanmak yerine, global deikeni programn en banda


tanmlamak daha iyi bir tekniktir.

extern bildirimlerinin yapl yerleri


extern bildirimleri kaynak kodun herhangi bir yerinde yaplabilir. Global ya da yerel olmas
szkonusu deilldir. Bildirimin yapld yerden dosya sonuna kadarcolan blge iin geerlidir.
Ancak extern bildirimlerinin programn tepesinde ya da programcya ait bir balk dosyasnn
iinde yaplmas daha uygun olur.

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

const anahtar szcnn gstericilerle birlikte kullanlmasnda en sk grlen biim budur ve


zellikle fonksiyonlarn parametre deikenleri olan gstericilerle bu biim kullanlr:
void func(const char *s)
{
...
}
Yukarda func fonksiyonunun parametre deikeni olan s gstericisi deerini fonksiyonun
armasyla alacaktr. Fonksiyon arma ifadesindeki arguman fonksiyonun arlmasyla s
gstericisine kopyalanacaktr. Ancak fonksiyon iinde *s nesnesine ya da s[x] nesnesine bir
atama yaplamaz. Yani s gstericisinin gsterdii yerdeki nesne (fonksiyona adresi gnderilen
nesne) deitirilemez. Yukardaki rnekte const anahtar szcnn kullanlmas hereyden
nce okunabilirlik ile ilgilidir. Yukardaki kodu okuyan bir C programcs func fonksiyonunun
dardan adresi alnan nesnenin yalnzca deerinden istifade edeceini, yani bu nesnenin
deerini deitirmeyeceini anlar. Geleneksel olarak, const anahtar szcnn, parametre
deikeni olan gstericilerin tanmlanmasnda kuallanlmamas okunabilirlik asndan bir mesaj
olarak kabul edilir:
void func(char *s)
{
...
}
Yukardaki kodu okuyan bir C programcs func fonksiyonunun (aslnda sentaks asndan bir
zorunluluk bulunmasa da) kendisine adresi gnderilen nesneyi deitireceini anlar. Kodu
okuyan kii yle dnecektir : Eer func fonksiyonu adresi gnderilen nesneyi
deitirmeyecek olsayd, s gstericisi const anahtar szc ile tanmlanrd.
2. const anahtar szcnn gsterici isminden hemen nce kullanlmas . rnekler :
...
char ch;
int m;
float f;
float fdizi[20];
char *const str = &ch ;
int *const ptr = (int *) 0x 1AC3;
float *const fptr = &f;
Bu durumda gstericinin gsterdii yerdeki nesne deitirilebilir ama gstericinin ierii
deitirilemez:
str = (char *) 0x1FC0;
/* error */
ptr = &m;
/* error */
fptr = fdizi;
/* error */
*str = 'A';
*ptr = 15;
fptr[2] = 12.3f;

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

*/
*/
*/
*/

const szcnn bu biimde kullanlmas yine daha ok parametre


tanmlanmasnda grlr ise de bu uygulamalarda seyrek olan bir durumdur.

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

otomatik (automatic) blok (block)

yok (none)

* b ve j deikenleri kendi modlleri iinde tanmlanan global deikenler de olabilir. Bu


durumda bu deikenle
static anahtar szcyle tanmlanm olmalar durumunda
i
balantya sahip olacak, static anahtar szc olmadan tanmlanmlar ise d balantya
sahip olacaklardr.

belirleyicilerin hangi tr deikenlerle kullanlabileceklerini gsteren tablo :


belirleyici
auto
static
register
extern
volatile
const

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.

Yap Bildiriminin Genel ekli


<struct > [yap ismi] {
<tr> <m1>;
<tr> <m2>;
<tr> <m3>;
...
};
Yukardaki gsterimde struct bir anahtar szcktr. Bildirimde mutlaka yer almas
gerekmektedir. Yap ismi (structure tag) C dilinin isimlendirme kurallarna uygun olarak
seilmi bir isimdir.
rnek bildirimler:
struct SAMPLE {
int a;
long b;
char ch;
};
struct DATE {
int day, month, year;
};
struct POINT {
int x, y;
};
Yap isimleri (structure tags) geleneksel olarak byk harfle yazlr. Bu bir zorunluluk deildir.
Yap bildiriminin yaplmas bellekte derleyici tarafndan bir yer ayrlmasna neden olmaz. Yani
bir tanmlama (definition) sz konusu deildir. Bu bildirimle (declaration) programcnn
yaratt yeni bir veri tr hakknda derleyiciye bilgi verilmektedir.
Yap bildiriminin yaplmasndan sonra artk bildirimi yaplm yap trnden nesneler
tanmlanabilir. Yap bilidiriminin yaplmas ile yeni bir veri tr yaratlmtr. Derleyici artk bu
tr hakknda bilgi sahibi oldugundan, bu yeni veri trnden, nesneler tanmlanabilir. Yeni veri
trnden nesnelerin tanmlanmas durumunda artk derleyici bu nesneler iin bellekte ne kadar
bir alan ayrmas gerektii bilgisine sahip olacaktr.

Yap Trnden Nesne Tanmlamas


<struct> <yap isimi> <nesne ismi>;
rnekler :
struct DATE x;

/* x DATE yaps trnden bir nesnedir. */


243

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

Yukardaki program parasnda ekrana (DOS altnda) 7 says yazdrlacaktr. nk yap


nesnesi olan x nesnesinin bellekte kaplad yer parasnn kaplad uzunluun toplamdr.
Bunu aadaki ekilde de ifade edebiliriz:
sizeof(x) == sizeof(int) + sizeof(long) + sizeof(char)
(Hizalama [alignment] konusuna geldiimizde bu durumu daha detayl olarak inceleyeceiz.)

Yap Elemanlarna Eriim


Yaplarn dizilerden nemli bir fark da elemanlara eriim konusundadr. Dizi elemanlarna
eriim, dizi ismi (aslnda bir adres bilgisidir) ve indis operatr [ ] (index operator - subscript
operator) yoluyla yaplrken, yap elemanlarna eriim dorudan yap nesnesinin ve elemann
isimleriyle olur. Yap elemanlarna eriimde nokta operatr kullanlr.
Nokta operatr (.) iki operand alan araek konumunda (binary infix) bir operatrdr. Bu
operatrn sol tarafndaki operand bir yap trnden deiken olmaldr. Sa tarafndaki
operand ise ilgili yap trnnn (yani yap bildiriminde nceden belirlenmi) bir yesi olmak
zorundadr. Nokta operatr, operatr ncelik tablosunun en yksek dzeyinde bulunur.
Yap nesneleri de yerel ya da global olabilir. Dier nesnelerde olduu gibi yap nesneleri iinde
faaliyet alan (scope) kavram sz konusudur. Tm bloklarn dnda tanmlanan yap nesneleri
global iken bloklarn ilerinde tanmlanan yap deikenleri yereldir. Global yap nesneleri dier
trden global nesneler gibi statik mr karakterine sahiptir ve dosya faaliyet alan kuralna
uyarlar. Yerel yap nesneleri ise dinamik mrldr ve blok faaliyet alan kuralna uyarlar.
Yap deikenlerine programc tarafndan deer verilmemise, yap deikeni yerel (local) ise
tm elemanlarnda rasgele deerler (garbage value) bulunur. Yap nesnesi global ise tm
elemanlarnda 0 deeri bulunur.
Bir yap nesnesi tanmlanarak, bu yap nesnesinin elemanlarna nokta operatr ile
ulaldnda artk bu elemanlarn her biri ayr bir nesne olarak ele alnr. Bu nesnelerin yap
dnda tanmlanan nesnelerden herhangi bir fark yoktur, nesnelerin tm zelliklerine
sahiptirler.

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.

Yap Bildirimlerinin Yapl Yerleri


Yap bildirimi global ya da yerel olarak yaplabilir. Eer yerel olarak yaplrsa yalnzca bildirimin
yapld blokta o yap trnden nesne tanmlanabilir. Bildirim global olarak yaplrsa her yerde
o yap trnden deiken tanmlanabilir.
Uygulamalarda hemen hemen her zaman yap bildirimleri programn tepesinde global olarak
yaplr. (Yap bildirimi balk dosyalarnn iinde de yaplabilir. Bu durumu ileride detayl olarak
inceleyeceiz.)
Yap bildiriminde yer alan yap elemanlarnn faaliyet alan yap bildirim blouyla snrldr. Yani
yap bildirimi blou dnda, yap eleman ile ayn isimli bir deiken tanmlanabilir. Yap ismi
(structure tag) ile ayn isimli deikenler de tanmlanabilir.
Aadaki program parasnda isimlendirme asndan bir hata yok. Okunabilirlik asndan iyi
bir uygulama deil.
struct SAMPLE {
int sample;
long x;
};
int main()
{
int sample, SAMPLE;
...
return 0;
}

Yap Elemanlarnn Bellekteki Yerleimi


Yap elemanlar bellee, bildirimde ilk yazlan eleman kk adreste olacak biimde, ardl
olarak yerletirilir.
rnek:
struct SAMPLE {
int a;
245

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

Yap Deikenlerine lk Deer Verilmesi (initialization)


Yap deikenlerine kme parantezleri ierisinde ilk deer verilebilir. Bu durumda verilen ilk
deerler sras ile yap elemanlarna yerletirilir. Daha az sayda yap elemanna ilk deer
verilebilir, bu durumda ilk deer verilmemi yap elemanlar 0 deeri alrlar.
struct DATE {
int day, month, year;
};
int main()
{
struct DATE x = {10, 12, 1999};
struct DATE y = {10, 12};

printf("%d %d %d\n", x.day, x.month, x.year};


printf("%d %d %d\n", y.day, y.month, y.year};

Dizilerde olduu gibi, yaplarda da yap elemanlarndan daha fazla sayda elemana ilk deer
vermek derleme zamannda hata oluumuna neden olacaktr.

Yap Eleman Olarak Gstericilerin Kullanlmas


Yapnn bir eleman herhangi trden bir gsterici olabilir. Bu durumda bu yap elemanna
ulalddnda, bu gsterici de yap eleman olmayan gstericiler gibi deerlendirilir
rnek:
struct PERSON {
char *name;
int no;
};
int main()
{
struct PERSON x;

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

Yap Eleman Olarak Dizilerin Kullanlmas


Yapnn bir eleman herhangi trden bir dizi olabilir. Dizilerde olduu gibi, bu durumda da
yapnn dizi elemannn ismi nesne belirtmez. (adres bilgisi belirtir).
rnek:
struct PERSON {
char name[30];
int no;
};
int main()
{
struct PERSON x;
gets(x.name);
puts(x.name);
putchar(x.name.[3]);
x.name++
/* error. dizi ismi nesne deildir. */
return 0;
}

Yap Nesneleri zerinde Yaplabilecek lemler


Yap deikenleri bir btn olarak aritmetik operatrlerle ve karlatrma operatrleri ile ileme
sokulamaz. Yap nesneleri zerinde u ilemler yaplabilir:
1. Bir yap deikeninin adresi alnabilir.
2. Ayn trden iki yap deikeni birbirine atanabilir.
3. sizeof operatr ile bir yap nesnesinin bellekte kaplad alan bulunabilir.
Ayn trden iki yap deikeninin birbirine atanmasnda yap elemanlar karlkl olarak
birbirlerine atanr. Yani bir blok kopyalanmas sz konusudur. Atama ilemi iin kesinlikle iki
yap deikeninin de ayn trden olmas gerekmektedir. ki yap deikeni de ayn trden
deilse bu durum derleme aamasnda hata oluturur. ki yapnn ayn trden olmalar iin ayn
yap ismi ile tanmlanm olmalar gerekir. Aadaki iki yap, elemanlarnn trleri ve dizilileri
ayn olduu halde birbirleri ile ayn deildir ve birbirlerine atanamazlar.
struct POINT_1 {
int x, y;
};
struct POINT_2{
int x, y;
};
...
struct POINT_1 a;
struct POINT_2 b;
b.x = 10;
b.y = 20;
a=b

/* derleme zamannda hata. a ve b yaplar ayn trden deil. */

Yap Trnden Adresler ve Gstericiler


Bir yap deikeninin adresi alnabilir. Bu durumda elde edilen adresin saysal bileeni yapnn
bellekteki balang adresi, tr bileeni ise yap ile ayn trden adrestir. Bir yap trnden
gstericiler de tanmlanabilir. Yap trnden gstericilere ayn yap trnden bir adres
atanmaldr.

247

25
rnek:
struct POINT_1 *p = &a;

Gstericiler Yap Elemanlarna Eriim


p yap trnden bir gsterici ve elm de o yapnn bir eleman olmak zere eriim u biimde
yaplr:
(*p).elm
Burada ncelik operatrnn kullanlmas zorunludur. Kullanlmazsa nce p.elm ele alnr daha
sonra * operatr ileme sokulurdu. Bu durum da derleme zamannda hata oluumuna neden
olurdu.

Yaplarn Fonksiyonlara Parametre Olarak Geirilmesi


Yaplar fonksiyonlara geirebilmek iin iki yntem kullanlabilir:
1. Yapnn kendisinin fonksiyona parametre olarak geirilmesi.
Ayn trden yap nesnelerinin birbirlerine atanabilmesi zelliinden faydalanlr. Bu
yntemde fonksiyonun parametre deikeni bir yap deikeni olur. Fonksiyon da ayn yap
trnden bir yap deikeni ile arlr. Ayn trden iki yap deikeninin birbirine atanmas
geerli olduuna gre bu ilem de geerlidir. Bu ilem bir blok kopyalamas gerektirdii iin
hem bellek hem de zaman asndan greli bir kayba neden olur. stelik bu yntemle,
fonksiyon kendisine gnderilen argumanlar deitiremez. Yani fonksiyon deerle
arlmtr. (call by value)
rnek :
struct PERSON {
char name[30];
int no;
};
void disp(struct PERSON y)
{
printf("%s %d\n", y.name, y.no);
}
int main()
{
struct PERSON x = {"Necati ERGIN", 125};
disp(x);
}
2. Yap deikenlerinin adreslerinin geirilmesi.
Bu yntemde fonksiyonun parametre deikeni yap trnden bir gsterici olur. Fonksiyon
da bu trden bir yap deikeninin adresi ile arlr. Bu yntem iyi bir tekniktir. Hemen her
zaman bu yntem kullanlmaldr. Bu yntemde yap ne kadar byk olursa olsun aktarlan
yalnzca bir adres bilgisidir. stelik bu yntemde fonksiyon kendisine adresi gnderilen yap
deikenini deitirebilir. phesiz byle bir aktarm ileminin mmkn olabilmesi yap
elemanlarnn bellekteki ardllk zelliinden faydalanlmaktadr. rnek :
struct PERSON {
char name[30];
int no;
};
void disp(struct PERSON *p)
{
248

YAPILAR
printf("%s %d\n", (*p).name, (*p).no);
}
int main()
{
struct PERSON x = {"Necati Ergin", 156};
disp(&x);
}

Yaplarn Kullanm Yerleri


Yaplar temel olarak 3 nedenden dolay kullanlrlar.
1. Birbirleri ile ilikili olan deikenler yap elemanlar olarak bir yap ierisinde toplanrsa
algsal kolaylk salanr. rnein dzlemde bir nokta, bir tarih bilgisi, bir depoda bulunan
mamllere ilikin zellikler bir yap ile temsil edilebilir.
2. C dilinde bir fonksiyon en fazla 8 - 10 parametre almaldr. Daha fazla parametreye sahip
olmas kt bir tekniktir. Bir fonksiyon ok fazla parametrik bilgiye gereksinim duyuyorsa,
bu parametrik bilgiler bir yap biiminde ifade edilmelidir. O yap trnden bir deiken
tanmlanmal, bu deikenin adresi fonksiyona parametre olarak gnderilmelidir. rnein
bir kiinin nfus czdan bilgilerini parametre olarak alp bunlar ekrana yazdracak bir
fonksiyon tasarlayacak olalm. Nfus czdan bilgilerinin hepsi bir yap biiminde ifade
edilebilir ve yalnzca bu yapnn adresi fonksiyona gnderilebilir.
3. C dilinde fonksiyonlarn tek bir geri dn deeri vardr. Oysa fonksiyonlarn ok deiik
bilgileri aran fonksiyona iletmesi istenebilir. Bu ilem yle yaplr: letilecek bilgiler bir
yap biiminde ifade edilir. Sonra bu trden bir yap deikeni tanmlanarak adresi
fonksiyona gnderilir. Fonksiyon da bu yap deikeninin iini doldurur. Yani fonksiyon
knda bilgiler yap deikeninin iinde olur.
4. C dilinin tasarmnda belirlenmi veri trleri yalnzca temel trleri kapsayacak ekildedir.
rnein tarihler ya da karmak saylar iin C dilinde belirlenmi temel bir tr yoktur
(default veri tipi yoktur.) Yaplar bu gibi veri trlerini oluturmak iin kullanyoruz.

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

Bir Yap Trne Geri Dnen Fonksiyonlar


Bir fonksiyonun geri dn deeri bir yap trnden olabilir.

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;

struct POINT make_point(int x, int y)


{
struct POINT temp;
temp.x = x;
temp.y = y;
return temp;
}
Bu durumda geri dn deerinin aktarld geici blge de struct POINT trnden olur. Byle
bir fonksiyonun geri dn deeri ayn trden bir yap deikenine atanabilir.
Ancak byle fonksiyonlar kk yaplar iin kullanlmaldr. nk return ifadesiyle geici
blgeye geici blgeden de geri dn deerinin saklanaca deikene atamalar yaplacaktr.
Bu da kt bir teknik olmaya adaydr. Kk yaplar iin tercih edilebilir. nk algsal
karmakl daha azdr.
make_point fonksiyonunun parametre deikenleri ile POINT yapsnn yeleri ayn isimde
olduklar halde faaliyet alanlar farkldr.

Yap Trnden Bir Alann Dinamik Olarak Tahsis Edilmesi


Nasl bir dizi iin bellek alan dinamik olarak tahsis edilebiliyorsa bir yap iin de byle bir
tahsisat yaplabilir. Aadaki rnekte DATE trnden bir yap iin dinamik tahsisat yaplmtr:
struct DATE {
int day, month, year;
};
int main()
{
struct DATE *p;
p = (struct DATE *) malloc (sizeof(struct DATE));
p->day = 10;
p->month = 12;
p->year = 2000;
printf("%d %d %d\n", p->day, p->month, p->year);
free(p);
return 0;
}

250

YAPILAR

Bir Yap Adresine Geri Dnen Fonksiyonlar


Bir fonksiyonun geri dn deeri bir yap trnden adres de olabilir.
rnein:
struct POINT {
int x, y;
};
struct POINT *dump_point(struct POINT *p);
int main()
{
struct POINT *p;
struct POINT a;

a.x = 10;
b.x = 20;
p = dump_point(&a);
return 0;

struct POINT dump_point(struct POINT *p)


{
struct POINT *retval;
if ((retval = (struct POINT *) malloc(sizeof(struct POINT))) == NULL) {
printf("not enough memory");
exit(EXIT_FAILURE);
}
*retval = *p;
return retval;
}
Tabi byle bir fonksiyon yerel bir yap deikeninin adresine geri dnemez. Global bir yap
deikeninin adresine de geri dnmesinin bir anlam yoktur. (Statik bir yerel yap nesnesinin
adresiyle geri dnlmesinde hibir saknca yok. Statik yerel deikenler konusundaki
bilgilerinizi hatrlaynz.) En iyi tasarm, ieride dinamik olarak tahsis edilmi bir yapnn
adresine geri dnmektir.
Tahsis edilen alann
sorumluluundadr.

"heap"

bellek

alanna

iade

edilmesi,

fonksiyonu

arann

Yap Bildirimi le Deiken Tanmlamasnn Birlikte Yaplmas


Bir yap bildirimi noktal virgl ile kapatlmayp, yap bildiriminin kapanan blok parantezinden
hemen sonra bir deiken listesi yazlrsa yap bildirimi ile deiken tanmlamas bir arada
yaplm olur.
struct DATE {
int day, month, year;
} bdate, edate;
Bu tanmlamada struct DATE trnden bir yapnn bildirimi ile birlikte bu yap trnden bdate
ve edate deikenleri de tanmlanmtr. Bu durumda yap deikenlerinin faaliyet alanlar yap
bildiriminin yerletirildii yere bal olarak belirlenir. Yani sz konusu yap deikenleri yerel ya
da global olabilir.

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.

ie Yaplar (nested structures)


Bir yapnn eleman baka bir yap trnden yap deikeni ise bu duruma iie yaplar denir.
ie yap bildirimi iki biimde yaplabilir :
1. nce eleman olarak kullanlan yap bildirilir. Onun aasnda dier yap bildirimi yaplr.
rnek:
struct DATE {
int day, month, year;
};
struct PERSON {
char name[30];
struct DATE birthdate;
int no;
};
Bu durumda iteki yapya ulamak iin 2 tane nokta operatr kullanmak gerekir.
int main()
{
struct PERSON employee;

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;

ie Yaplara lk Deer Verilmesi


Normal olarak ilk deer vermede elemanlar srasyla, iteki yap da dikkate alnacak biimde,
yap yelerine atanr. Ancak iteki yapnn ayrca kme parantezleri ierisine alnmas
okunabilirlii artrd iin tavsiye edilir. rnek:
struct PERSON per = {"Necati Ergin", {10, 10, 1967}, 123};
Eer iteki yap ayrca kme parantezi iine alnmsa iteki yapnn daha az sayda elemanna
ilk deer vermek mmkn olabilir. rnek :
struct PERSON per = {"Necati Ergin", {10, 10}, 123};
Burada doum tarihinin year elemanna ilk deer verilmemitir. Derleyici bu elemana otomatik
olarak 0 deeri yerletirecektir. Ancak burada iteki kme parantezleri kullanlmasayd 123 ilk
deeri year elemanna verilmi olacak, no elemanna otomatik olarak 0 deeri verilmi olacakt.
Ayn durum yap iinde dizi bildirimlerinde de sz konusudur. rnek :
struct SAMPLE {
int a[3];
long b;
char c;
};
struct SAMPLE x = {{1, 2, 3}, 50000L, 'x'};
Aadaki gibi bir bildirim de geerlidir :
struct SAMPLE {
int a[3];
long b;
char c;
} x = {{1, 2, 3}, 50000L, 'A}, *p;

253

25

ie Yap Kullanmnn Avantajlar


Aadaki gibi bir yap bildiriminin yapldn dnelim :
struct ISIM {
char ad[ADUZUNLUK + 1];
char soyad[SADUZUNLUK + 1];
};
sim yapsn daha byk bir yapnn paras olarak kullanabiliriz.
struct OGRENCI {
struct ISIM isim;
int no, yas;
char cinsiyet;
} ogrenci1, ogrenci2;
Bu durumda ogrenci1 degiskeninin ad ve soyad'na ulamak icin iki kez nokta operatr
kullanlacaktr:
strcpy(ogrenci1.isim.ad, Hakan);
Yukardaki rnekte OGRENCI yapsnn eleman olarak ISIM yapsn kullanmak yerine,
dogrudan ad[ADUZUNLUK + 1] ve char soyad[SADUZUNLUK + 1] dizilerini OGRENCI yapsnn
elemanlar yapabilirdik. Ama isim yapsn dorudan bir eleman olarak kullanrsak baz ilemleri
daha kolay yapabiliriz. rnein rencilerin ad ve soyadn yazan bir fonksiyon yazacamz
dnelim. Bu durumda yazlacak fonksiyona 2 arguman gndermek yerine yalnzca 1
arguman gnderilecektir.
isim_yaz(ogrenci1.isim);
Benzer ekilde isim trnden bir yap elemanndan grencinin ad ve soyad bilgilerini OGRENCI
yaps trnden bir deikenin alt elemanlarna kopyalama daha kolay yaplacaktr :
struct isim yeni_isim;
...
ogrenci1.isim = yeni_isim;

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;

Program parasn u ekilde de yazabilirdik:


int main()
{
...
for (i = 0; i < 5; ++i)
disp(&birthdate[i]);
return 0;
}
void Disp(struct DATE *p)
{
printf("%02d / %02d / %04d\n", pdate->day, pdate->month, pdate->year);
}

Yaplara likin Karmak Durumlar


Bir yapnn eleman baka bir yap trnden yap gstericisi olabilir. rnein:
struct DATE {
int day, month, year;
};
struct PERSON {
char name[30];
struct DATE *bdate;
int no;
};
struct PERSON x; eklinde bir tanmlamann yapldn dnelim.
1. x.bdate ifadesinin tr struct DATE trnden bir adrestir ve nesne belirtir. (Nesne belirtir
nk bdate bir gsterici deikendir.)
2. x.bdate->day ifadesinin tr int dir ve nesne belirtir.
3. &x.bdate->day ifadesinin tr int trden bir adrestir.
Tabi bu rnekte, bir deer atamas yaplmamsa, x.bdate ile belirtilen gsterici ierisinde
rasgele bir adres vardr. (garbage value) Bu gstericinin kullanlabilmesi iin tahsis edilmi bir
alan gstermesi gerekir. rnein bu alan dinamik olarak tahsis edilebilir.
x.bdate = (struct DATE *) malloc (sizeof(struct DATE));
Yukardaki rnekte elimizde yalnzca struct PERSON trnden bir gsterici olduunu
dnelim.
struct PERSON *person;
1. person->bdate ifadesinin tr struct DATE trnden bir adrestir.
2. person->bdate->day ifadesinin tr int dir.
Bu rneklerde henz hibir yer iin bilinli bir tahsisat yaplmamtr. Hem person gstericisi
iin hem de person->date gstericisi iin, dinamik bellek fonksiyonlaryla bellekte yer
tahsisatlarnn yaplmas gerekir:
person = (struct PERSON *) malloc(sizeof(struct PERSON));
person->bdate = (struct DATE *) malloc(sizeof(struct DATE));
Burada dinamik olarak tahsis edilen alanlar ters srada iade (free) edilmelidir.

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.

Bal Liste Nedir


Bellekte elemanlar ardl olarak bulunmayan listelere bal liste denir. Bal listelerde her
eleman kendinden sonraki elemann nerede olduu bilgisini de tutar. lk elemann yeri ise yap
trnden bir gstericide tutulur. Bylece bal listenin tm elemanlarna ulalabilir. Bal liste
dizisinin her eleman bir yap nesnesidir. Bu yap nesnesinin baz yeleri bal liste
elemanlarnn deerlerini veya tayacaklar dier bilgileri tutarken, bir yesi ise kendinden
sonraki bal liste eleman olan yap nesnesinin adres bilgisini tutar. rnek:
struct LLIST {
int val;
struct LLIST *next;
};
Bal listenin ilk elemannn adresi global bir gstericide tutulabilir. Son elemanna ilikin
gsterici ise NULL adresi olarak brakllr. Bal liste elemanlar malloc gibi dinamik bellek
fonksiyonlar ile oluturulur.

Bal Listelerle Dizilerin Karlatrlmas


Dizilerde herhangi bir elemana ok hzl eriilebilir. Oysa bal listelerde bir elemana
eriebilmek iin, bal listede ondan nce yer alan btn elemanlar dolamak gerekir.
Dizilerde araya eleman ekleme ya da eleman silme ilemleri iin blok kaydrmas yapmak
gerekir. Oysa bal listelerde bu ilemler ok kolay yaplabilir.
Diziler bellekte ardl bulunmak zorundadr. Bu durum bellein blnm olduu durumlarda
belirli uzunlukta dizilerin almasn engeller. Yani aslnda istenilen toplam byklk kadar bo
bellek vardr ama ardl deildir. te bu durumda bal liste tercih edilir.
Bal liste kullanm srasnda eleman ekleme, eleman silme, bal listeyi gezme (traverse), vb.
ilemler yaplr.

256

C DLNN TARH VE ZAMAN LE LGL LEM YAPAN STANDART FONKSYONLARI

26 . BLM : C DLNN TARH VE ZAMAN LE


LGL LEM YAPAN STANDART FONKSYONLARI
time_t time (time_t *timer);
01.01.1970 tarihinden itibaren geen saniye saysn
bulur. Bu deer baz tarih ve zaman fonksiyonlarnda
girdi olarak kullanlmaktadr.

geri dn deeri 01.01.1970 den


arld zamana kadar geen saniye
saysdr. Bu deeri ayn zamanda
kendisine
gnderilen
argumandaki
adrese de yazar. Arguman olarak NULL
adresi gnderilirse saniye deerini
yalnzca geri dn deeri olarak
retir.
struct tm localtime(const time_t *timer);
Geri dn deeri struct tm trnden
localtime fonksiyonu arld andaki sistem bir yap adresidir. Bu yap iinde
tarihinin ve zamannn elde edilmesi amacyla ayrtrlm tarih ve zaman bilgileri
kullanlr. 01.01.1970 tarihinden geen saniye bulunmaktadr.
saysn
(yani
time
fonksiyonunun
ktsn)
parametre olarak alr, bunu o andaki tarih ve zaman
deerine dntrerek statik olarak tahsis edilmi bir
yap ierisinde saklar.
char *ctime(const time_t *time);
fonksiyon kendi ierisnde statik olarak
Bu fonksiyon time fonksiyonunun ktsn parametre tahsis ettii dizinin adresine geri
olarak alr, 26 karakterlik NULL ile biten bir diziye dner. (Dolaysyla hep ayn adrese
yerletirerek dizinin balang adresiyle geri dner. geri dnmektedir.)
Tarih ve zaman bilgisinin dizi ierisindeki durumu
yledir:
DDD MMM dd hh:mm:ss YYYY
Mon Oct 20 11:31:54 1975\n\0
DDD : ngilizce gnlerin ilk harfinden elde edilen
ksaltma
MMM : ngilizce aylarn ilk harfinden elde edilen
ksaltma
dd
: Saysal olarak ayn hangi gn olduu
hh
: Saat
mm
: Dakika
ss
: Saniye
YYYY : Yl
char *asctime (const struct tm *tblock);
fonksiyon kendi ierisnde statik olarak
ctime fonksiyonuna benzer bir ilevi yerine tahsis ettii dizinin adresine geri
getirir.Parametre olarak ctime fonksiyonundan farkl dner. (Dolaysyla hep ayn adrese
olarak struct tm trnden bir gsterici alr. Tpk geri dnmektedir.)
ctime fonksiyonunda olduu gibi tarihi ve zaman 26
karakterlik bir diziye yerletirir.
clock_t clock(void)
Baar
durumunda
programn
Programn balangcndan itibaren geen saat balangcndan beri geen ilemci
ticklerinin saysn verir.
zaman deerine geri dner.
clock fonksiyonu iki olay arasndaki zamansal fark Baarszlk durumunda ilemci zaman
bulmak iin kullanlr. Elde edilen zaman deerini elde edilemiyorsa, ya da deeri elde
saniyeye evirmek iin, bu deeri CLK_TCK sembolik edilemiyorsa) 1 deerine geri dner.
sabitine blmek gerekir.
double difftime(time_t time2, time_t time1);
Geri dn deeri time1 ve time2
ki zaman arasndaki fark saniye olarak hesaplar.
zamanlar arasndaki saniye olarak
farktr.

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;

while (!kbhit() || getch() != 27) {


time(&timer);
tptr = localtime(&timer);
printf("%02d:%02d:%02d\r", tptr->tm_hour, tptr->tm_min, tptr->tm_sec);
}

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

C DLNN TARH VE ZAMAN LE LGL LEM YAPAN STANDART FONKSYONLARI

void delay(unsigned long n)


{
while (n-- > 0)
;
}

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

nDate(const DATE *date, int n);


randomDate(void);
totaltoDate(long totaldays);
randomDate(void);
259

26

/* global variables */
char *days[]

= {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};

char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",


"Aug", "Sep", "Oct", "Nov", "Dec"};
/* function definitions */
int main()
{
/* type your test code here */
}
/* Gnderilen argumann artk yl olup olmadgn test eder. Artk yl ise 1
degil ise 0 deerine geri dner. */
BOOL isleap(int year)
{
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)
return TRUE;
return FALSE;
}
/* Gnderilen adresteki DATE trnden yap nesnesine ilk 3 argumanndaki ay,
gn, yl deerlerini yerletirir. */
void setDate(int day, int month, int year, DATE *date)
{
date->day = day;
date->month = month;
date->year = year;
}
/* Gnderilen adresteki yap nesnesinin elemanlarn ekrana yazdrr. */
void displayDate(const DATE *date)
{
printf("%02d %02d %4d", date->day, date->month, date->year);
}
/* gnderilen adresteki yap nesnesinin saklad tarihi ingilizce format ile
ekrana yazar. rnek:
3 rd Sep 2000 Sunday */
void displayDate2(const DATE *date)
{
printf("%02d", date->day);
switch (date->day) {
case 1: case 21: case 31:
printf("st "); break;
case 2: case 22:
printf("nd "); break;
case 3: case 23:
printf("rd "); break;
default :
printf("th ");
}
printf("%s ", months[date->month - 1]);
printf("%d ", date->year);
printf("%s", days[Dateday(date)]);
}

260

C DLNN TARH VE ZAMAN LE LGL LEM YAPAN STANDART FONKSYONLARI


/* 01.01.1900 tarihinden adresi verilen tarihe kadar geen gn saysna geri
dner. */
long totaldays(const DATE *date)
{
long result = 0;
int year;
for (year = 1900; year < date->year; ++year)
result += 365 + isleap(year);
result += dayofyear(date);
return result;
}
/*
adresi gnderilen
olduunu bulur. */

yap

nesnesindeki

tarihin

ilgili

yln

kanc

gn

int dayofyear(const DATE *date)


{
int result = date->day;

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

int datedif(const DATE *date1, const DATE *date2)


{
return abs(totaldays(date1) - totaldays(date2));
}
/* Parametre deikenindeki gn saysn DATE trnden bir nesneye dntrerek
geri dn deeri olarak retir. */
DATE totaltoDate(long totaldays)
{
int months[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
DATE result;
int i = 0;
result.year = 1900;
while (totaldays > (isleap(result.year) ? 366 : 365)) {
totaldays -= isleap(result.year) ? 366 : 365;
result.year++;
}
months[1] += isleap(result.year);
while (totaldays > months[i]) {
totaldays -= months[i];
++i;
261

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

adresi gnderilen yap nesnesindeki tarihin hangi gn olduunu hesap eder.

DAYS Dateday(const DATE *date)


{
switch (totaldays(date) % 7) {
case 0: return SUN;
case 1: return MON;
case 2: return TUE;
case 3: return WED;
case 4: return THU;
case 5: return FRI;
case 6: return SAT;
}
return 0;
}
/* Adresleri gnderilen yap nesnelerindeki tarihleri karlatrr. */
int Datecmp(const DATE *date1, const DATE *date2)
{
if (date1->year != date2->year)
return date1->year - date2->year;
if (date1->month != date2->month)
return date1->month != date2->month;
if (date1->day != date2->day)
return date1->day - date2->day;
return 0;
}
/* Adresi gnderilen yap adresindeki tarihin gecerli bir tarih olup olmadn
test eder. */
BOOL validDate(const DATE *date)
{
int months[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
months[1] = 28 + isleap(date->year);

if (date->year < 1900)


return INVALID;
if (date->day > months[date->month - 1] || date->day <= 0)
return INVALID;
if (date->month < 1 || date-> month > 12)
return INVALID;
return VALID;

/* Tarihin hafta sonu olup olmadn test eder. */


BOOL isweekend(const DATE *date)
262

C DLNN TARH VE ZAMAN LE LGL LEM YAPAN STANDART FONKSYONLARI


{

DAYS result = Dateday(date);


if (result == SAT || result == SUN)
return TRUE;
return FALSE;

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

random.year = rand() % 101 + 1900;


months[1] += isleap(random.year);
random.month = rand() % 12 + 1;
random.day = rand() % months[random.month - 1] + 1;
return 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

typedef struct _PERSON {


char name[20];
int no;
struct _PERSON *next;
}PERSON;
PERSON *start = NULL;
void add_begin(void);
void display_list(void);
void add_end(void);
void delete_name(void);
void delete_no(void);
int get_option(void);
int main()
{
int option;
for (;;) {
option = get_option();
switch (option) {
case ADD_BEGIN : add_begin(); break;
case ADD_END
: add_end(); break;
263

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;

printf("\n[1] bal listenin bana ekle.\n");


printf("[2] bal listeye sondan ekle.\n");
printf("[3] bal listeden isme gre sil.\n");
printf("[4] bal listeden no'ya gre sil.\n");
printf("[5] bal listeyi listele.\n");
printf("[6] programdan k.\n");
option = getch() - '0';
return 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

C DLNN TARH VE ZAMAN LE LGL LEM YAPAN STANDART FONKSYONLARI


return;
}
for (cur = start; cur->next != NULL; cur = cur->next)
;
cur->next = new;
new->next = NULL;
}
/************************************************/
void display_list(void)
{
PERSON *cur;
printf("\n bilgiler listeleniyor :\n\n");
for (cur = start; cur != NULL; cur = cur->next)
printf("%-20s\t%05d\n", cur->name, cur->no);
}
/************************************************/
void delete_name(void)
{
PERSON *cur, *prev;
char nametemp[30];
printf("silinecek ismi girin : ");
fflush(stdin);
gets(nametemp);

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>

typedef struct _PERSON{


char name[20];
int no;
struct _PERSON *next;
}PERSON;
PERSON *start = NULL;
int get_option(void);
void add(void);
void display(void);
void delete_name(void);
void fill(void);
PERSON *find_name(char *name);
void del_list(void);
void search(void);
int main()
{
int option;
for (;;){
option = get_option();
switch (option){
case 1: add(); break;
case 2: display(); break;
case 3: delete_name(); break;
case 4: fill(); break;
case 5: search(); break;
case 6: del_list(); break;
case 0: goto EXIT;
default: printf("make your choice\n");
}
}
EXIT:
return 0;
}
/************************************************/
int get_option(void)
{
int option;
printf("\n[1] add a new name\n");
printf("[2] display list\n");
printf("[3] delete name\n");
printf("[4] fill the link list with test data\n");
printf("[5] find name\n");
printf("[6] delete list\n");
printf("[0] exit\n");
option = getch() - '0';
return option;
}

266

C DLNN TARH VE ZAMAN LE LGL LEM YAPAN STANDART FONKSYONLARI


/************************************************/
void add(void)
{
PERSON *prev, *cur, *_new;
char name[50];
fflush(stdin);
printf("name:");
gets(name);
for (prev = NULL, cur = start; cur != NULL && strcmp(name, cur->name) > 0;
prev = cur, cur = cur->next)
;
if (cur != NULL && !strcmp(name, cur->name)) {
printf("name already exists\n");
return;
}
if ((_new = (PERSON *) malloc(sizeof(PERSON))) == NULL) {
printf("not enough memory");
exit(EXIT_FAILURE);
}
strcpy(_new->name, name);
printf("number:");
scanf("%d", &_new->no);
_new->next = cur;
if (prev == NULL)
start = _new;
else
prev->next = _new;
}
/************************************************/
void display(void)
{
PERSON *cur;
putchar('\n');
for (cur = start; cur != NULL; cur = cur->next)
printf("%-20s %d\n", cur->name, cur->no);
printf("press any key to continue\n");
getch();
}
/************************************************/
void delete_name(void)
{
PERSON *cur, *prev;
char name[50];
fflush(stdin);
printf("name: ");
gets(name);
for (prev = NULL, cur = start;
cur != NULL && strcmp(cur->name, name);
prev = cur, cur = cur->next)
;
if (cur == NULL) {
printf("couldn't find\n");
return;
}
if (prev == NULL)
start = cur->next;
else
267

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

C DLNN TARH VE ZAMAN LE LGL LEM YAPAN STANDART FONKSYONLARI

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

27 . BLM : TR TANIMLAMALARI ve typedef


ANAHTAR SZC
C dilinde bir tre her bakmdan onun yerini tutabilen alternatif isimler verilebilir. Bu ilemler
typedef anahtar szc ile yaplr.
Genel biimi:
typdef <isim> <yeni isim>;
rnek :
typedef unsigned int UINT;
Bu bildirimden sonra UINT ismi derleyici tarafndan unsigned int trnn yeni bir ismi olarak
ele alnacaktr. Yani kaynak kod ierisinde UINT szc kullanldnda derleyici bunu
unsigned int olarak anlamlandracaktr.
UINT x, y, k;
Bildiriminde artk x, y, k deikenleri unsigned int trnden tanmlanm olurlar.
printf("%d\n", sizeof(UINT));
typedef anahtar szc ile yeni bir tr ismi yaratlmas bu tre ilikin nceki ismin
kullanlmasna engel olmaz. Yani yukardaki rnekte gsterilen typedef bildiriminin
yaplmasndan sonra
unsigned int result;
gibi bir bildirimin yaplmasna engel bir durum sz konusu deildir.
phesiz #define nilemci komutuyla da ayn i yaplabilirdi.
#define UINTunsigned int
Ancak typedef anahtar szc derleyici tarafndan ele alnrken #define ile tanmlanan
sembolik sabitler nilemciyi ilgilendirmektedir.
Kark tr tanmlamalarnda
ngelleyecektir.

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

TR TANIMLAMALARI ve typedef ANAHTAR SZC


gibi bir bildirim yaplabilir. Bildirim char *p ile ayn anlama gelir.
Bu rnekte yaplan tr tanmlamas #define nilemci komutuyla, yani sembolik sabit
tanmlamasyla yapldnda kodda yanllk olabilirdi.
#define pstr char *
gibi bir sembolik sabit tanmlamas yapldnda nilemci pstr grd yerde bunun yerine
char * yerletirecektir.
char *str;
gibi bir bildirimin
pstr str;
olarak yazlmasnda bir hata sz konusu olmaz nk nilemci pstr yerine char *
yerletirdiinde derleyiciye giden kod char *str haline gelir.
char *p1, *p2, *p3;
pstr nilemci sabitini kullanarak yukardaki gibi bir bildirimin yaplmak istendiini dnelim.
pstr p1, p2, p3;
yazldnda, nilemci yer deitirme ilemini yaptktan sonra derleyiciye verilen kod aadaki
biime dnecektir :
char *p1, p2, p3;
Bu tanmlama yaplmak istenen tanmlamaya eit deildir. Yukardaki bildirimde yalnzca p1
char trden bir gstericidir. p2 ve p3 char trden gstericiler deil char trden nesnelerdir.
Bu rnekte grld gibi, typdef anahtar szcnn ilevi #define nilemci komutuyla her
zaman yerine getirilemiyor.
Bir diziye ilikin tr tanmlamas da yaplabilir.
char isimdizi[20];
/* isimdizi char trden 20 elemanl bir dizidir. */
typedef isimdizi[20]; /* isimdizi 20 elemanl char trden bir dizi trdr. */
isimdizi a, b, c;

/* a, b ve c herbiri 20 elemanl char trden dizilerdir. */

Bir typedef ile birden fazla tr ismi tanmlanabilir.


typedef unsigned int WORD, UINT;
Bu tr tanmlamasyla hem WORD hem de UINT unsigned int trnn yerine geebilir.
WORD x, y;
...
UINT k, l;
10 elemanl char trden gsterici dizisi iin tr tanmlamasn yle yapabiliriz:
typedef char *PSTRARRAY[10];
Bu tr tanmlamasndan sonra
PSTRARRAY s;

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.

typedef Tr Tanmlamalarnn Yaplarla Birlikte Kullanm


C dilinde yaplar ayr bir veri trdr. Bu tr nce derleyiciye tantldktan sonra, bu tre ilikin
deikenler (nesneler) tanmlanabilir. rnein:
struct SAMPLE {
int a, b, c;
};
Yukardaki rnekte yeni bir veri tr yaratlmtr. Bu veri trnn ismi struct SAMPLE dr.
(SAMPLE deil) Yani bu veri trnnden bir nesne tanmlamak istersek tr ismi olarak struct
SAMPLE yazlmaldr. (Oysa C++ dilinde yap isimleri (structure tags) ayn zamanda trn de
ismidir ve struct anahtar szc olmadan kullanldnda bu trn ismi olarak derleyici
tarafndan kabul grr.)
Yukardaki bildirimden sonra rnein bir tanmlama yaplacak olsa
struct SAMPLE x;
eklinde yaplmaldr. C dilinde bu tanmlamann
SAMPLE x;
eklinde yaplmas derleme zamannda hata oluturacaktr. (Oysa C++ dilinde bu durum bir
hata oluturmaz.)
te struct anahtar szcnn, yap tanmlamlamalarnda yap isminden nce kullanlma
zorunluluunu ortadan kaldrmak iin programclar, typedef anahtar szcyle kendi
bildirdikleri yap (birlik, bit alanlar, enum trleri ) trlerine ilikin yeni tr isimleri olutururlar.
Bir yap trne ilikin yeni bir tr isminin tanmlanmas 2 ayr ekilde yaplabilir.
1. nce yap bildirimini yapmak, daha sonra bu yap trnden bir tr ismi tanmlamak.
struct PERSON {
char name[30];
int no;
};
typedef struct PERSON PER;
int main()
{
PER x = {Necati Ergin, 123};
printf(%s%d\n, x.name, x.no);
272

TR TANIMLAMALARI ve typedef ANAHTAR SZC


return 0;
}
2. typedef bildirimi ile yap bildirimini bir arada yapmak.
typedef struct PERSON {
char name[30];
int no;
} PER;
PER x;
Yap ismini (tag) hi belirtmeden de typedef bildirimi yaplabilirdi.
typedef struct {
char name[30];
int no;
} PER;
PER y;
Ancak yukardaki son durumda artk deiken bildiriminin yeni tanmlanan tr ismiyle
yaplmas zorunluluk haline gelir.
Programclarn ou yap isimleriyle (tag) tr isimleri iin farkl isimler bulmak yerine birka
karakter kullanarak aralarnda iliki kurarlar. ok kullanlan yntemlerden biri, yap isminin
bana bir alt tire konularak tr isminden ayrlmasdr :
typedef struct _EMPLOYEE {
int no;
char name[30];
double fee;
} EMPLOYEE;
(Yukardaki rnekte tamamen ayn isim [mesela EMPLOYEE] hem yap ismi hem de yeni tr
ismi olarak kullanlabilir. Bu durum derleme zamannda bir hataya yol amaz. )
typedef struct EMPLOYEE {
int no;
char name[30];
double fee;
} EMPLOYEE;
nk trn eski ismi EMPLOYEE deil struct EMPLOYEE dir. Yani struct EMPLOYEE trnn
ismi EMPLOYEE olarak typedef edilmitir ki bu durum bir saknca oluturmaz.
windows.h ierisinde yap ismi ile yeni tr isminin, yap ismine tag szc eklenerek
birbirinden ayrldn gryoruz.
typedef struct tagEMPLOYEE {
int no;
char name[30];
double fee;
} EMPLOYEE;

Balk Dosyalarnda Standart Olarak Bulunan Baz typedef Bildirimleri


Temel C Kurdu boyunca bildirimi bizim tarafmzdan yaplmam olan baz tr isimlerini
kullandk. typedef anahtar szc ile ilgili rendiklerimizden sonra bu tr isimlerinin ne
273

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

typedef ile Bildirimi Yaplan Tr simlerinin Faaliyet Alanlar


typedef isimleri iin de faaliyet alan kurallar geerlidir. Blok ierisinde tanmlanan bir
typedef ismi blok dnda tannmaz.
func()
{
typedef int WORD;
...
}
int main()
{
WORD x;
...
return 0;
}

/* hata */

Yukardaki programda
WORD x;

274

TR TANIMLAMALARI ve typedef ANAHTAR SZC


tanmlamasn gren derleyici bir hata mesaj retecektir. Zira WORD tr yalnzca func
fonksiyonunun ana blou iinde tannan ve anlamlandrlan bir veri trdr. Bu bloun dnda
tannmamaktadr.
C dilinde blok iinde yaplan bildirimler, bloklarn ilk ilemi olmak zorunda olduundan typedef
anahtar szcyle blok iinde yaplan tr bildirimleri de bloklarn ilk ilemi olmak zorundadr.
Aksi halde derleme zamannda hata oluacaktr.
Hemen her zaman typedef bildirimleri global olacak yaplmaktadr. Uygulamalarda typedef
bildirimleri genellikle, ya kaynak dosyann banda ya da balk dosyalar iinde tanmlanr.
Bir typedef isminin ayn faaliyet alan iinde (rnein global dzeyde) zde olmayacak ekilde
iki kere tanmlanmas derleme zamannda hata oluturacaktr :
typedef int WORD;
...
typedef long WORD; /* error */

typedef tanmlamalar ne amala kullanlr


1. Okunabilirlii artrmak iin. Baz trlere onlarn kullanm amalarna uygun isimler verilirse
kaynak kodu inceleyen kiiler kodu daha kolay anlamlandrr. rnein char tr genelde
karakter sabitlerinin atand bir trdr. Yazlacak bir kodda char tr yalnzca bir bytelk
bir alan olarak kullanlacaksa, yani karakter ilemlerinde kullanlmayacaksa aadaki gibi
bir tr tanmlamas yerinde olacaktr.
typedef char BYTE;
...
BYTE x;
2. Yazm kolayl salar. Karmak pek ok tr ifadesi typedef sayesinde kolay bir biimde
yazlabilmektedir. Program inceleyen kii karmak operatrler yerine onu temsil eden yaln
bir isimle karlar.
typedef struct PERSON EMPLOYEE[100];
...
EMPLOYEE manager;
3. Tr tanmlamalar tanabilirlii artrmak amacyla da kullanlrlar. Tr tanmlamalar
sayesinde kullandmz fonksiyonlara ilikin veri yaplar deise bile kaynak programn
deimesi gerekmez. rnein, kullandmz ktphanede birtakm fonksiyonlarn geri
dn deerleri unsigned int olsun. Daha sonraki uygulamalarnda bunun unsigned long
yapldn dnelim. Eer programc bu bu fonksiyonlara ilikin kodlarda tr tanmlamas
kullanmsa daha nce yazd kodlar deitirmesine gerek kalmaz, yalnzca tr
tanmlamasn deitirmek yeterlidir. rnein:
typedef unsigned int HANDLE;
...
HANDLE hnd;
hnd = GetHandle();
Burada GetHandle fonksiyonunun geri dn deerinin tr sonraki uyarlamalarda
deierek unsigned long yaplm olsun. Yalnzca tr tanmlamasnn deitirilmesi yeterli
olacaktr:
typedef unsigned long HANDLE;
Baka bir rnek :

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.

typedef le Gsterici Trlerine sim Verilmesi


typedef anahtar szc ile gsterici trlerine isim verilmesinde dikkat etmemiz gereken bir
nokta var. Belirleyiciler (specifiers) konusunda incelediimiz gibi C dilinde aadaki gibi bir
tanmlama yapldnda
const int *ptr;
ptr gstericisinin gsterdii yerdeki nesne deitirilemez. Yani
*ptr = 10;
gibi bir atama yaplmas durumunda derleme zamannda hata oluacaktr.
Ancak tanmlama
int *const ptr;
eklinde yaplrsa ptr gstericisinin gsterdii yerdeki nesnenin deeri deitirilebilir, ama ptr
gstericisinin iindeki adres deitirilemez, yani
ptr = (int *) 0x1F00;
gibi bir atama yaplmas durumunda derleme zamannda hata oluur.
276

TR TANIMLAMALARI ve typedef ANAHTAR SZC

typedef int * IPTR;


gibi bir tr tanmlanarak
const IPTR p;
eklinde bir tanmlama yapldnda, p gstericisinin deeri deitirilemez, p gstericisinin
gsterdii yerdeki nesnenin deeri deitirilebilir. (yani *p nesnesine atama yaplabilir.) Baka
bir deyile
const IPTR p;
deyimi ile
int *const ptr;
deyimi edeerdir.
Windows iletim sistemi altnda alacak C ya da C++ programlarnn yazlmasnda typedef
sklkla kullanlmaktadr. windows.h isimli balk dosyasnda temel veri trlerinin ouna
typedef'le yeni isimler verilmitir. Windows programlamada Windows.h dosyas kaynak koda
dahil edilmelidir. Bu dosyann ierisinde API fonksiyonlarnn prototipleri, eitli yap bildirimleri,
typedef isimleri, nemli sembolik sabitler bulunmaktadr.

windows.h erisinde Tanmlanan Typedef simleri


typedef int BOOL
Bu trle ilikili 2 sembolik sabit de tanmlanmtr.
#define FALSE
#define TRUE

0
1

BOOL tr, zellikle fonksiyonlarn geri dn deerlerinde karmza kar. Bu durum


fonksiyonun baarlysa 0 d bir deere, baarszsa 0 deerine geri dnecei anlamna gelir.
Baar kontrol, 1 deeriyle karlatrlarak yaplmamaldr.
Aadaki typedef isimleri, iaretsiz 1 byte, 2 byte ve 4 byte tam saylar temsil eder.
typedef
typedef
typedef
typedef

unsigned
unsigned
unsigned
unsigned

char BYTE;
short WORD;
long int DWORD;
int UINT;

Gstericilere ilikin typedef isimleri P harfiyle balar. LP uzak gstericileri belirtmek iin n ek
olarak 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];
};

Birlik Deikenlerinin Tanmlanmas


Birlik deikenlerinin tanmlanmas ayn yap deikenlerinde olduu gibidir. Tpk yaplarda
olduu gibi birliklerde de bellekte yer ayrma ilemi bildirim ile deil tanmlama ilemi ile
yaplmaktadr. Birlik deikeni tanmlamalarnn yap bildirimi tanmlamalarndan tek fark
struct anahtar szc yerine union anahtar szcnn kullanlmasdr. rnekler :
union DWORD a, b;
ile a ve b union DWORD trnden iki deiken olarak tanmlanmlardr.
union DBL_FORM x, y;
x ve y union DBL_FORM trnden iki deikendir. Yine tpk yaplarda olduu gibi birliklerde de
bildirim ile tanmlama ilemi birlikte yaplabilir :
union DBL_FORM {
double n;
unsigned char s[8];
} a, b, c;
Bu durumda a, b ve c deikenlerinin faaliyet alanlar birlik bildiriminin yapld yere bal
olarak yerel ya da global olabilir.
Birlik elemanlarna da yap elemanlarnda olduu gibi nokta operatryle eriilir. rnein
yukardaki tanmlama dikkate alnrsa a.n birliin double trnden ilk elemann belirtmektedir.
Benzer biimde birlik trnden gstericiler de tanmlanabilir. Ok operatr ile yine yaplarda
olduu gibi birliklerde de gsterici yoluyla birlik elemanlarna ulalabilir. rnein:

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.

Saylarn Bellekteki Yerleimleri


Bir bytedan daha byk olan saylarn bellee yerleim biimi kullanlan mikroilemciye gre
deiebilir. Bu nedenle saylarn bellekteki grnmleri tanabilir bir bilgi deildir.
Mikroilemciler iki tr yerleim biimi kullanabilirler:

Dk anlaml byte deerleri bellein dk anlaml adresinde bulunacak


biimde. (little endian)
80x86 ailesi Intel ilemcileri bu yerleim biimini kullanr. Bu ilemcilerin kullanld sistemlere
rnein
int x = 0x1234;
biimindeki bir x deikeninin bellekte 1FC0 adresinden balayarak yerletiini varsayalm:

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

...

Dk anlaml byte deerleri, bellein yksek anlaml adresinde bulunacak


ekilde (big endian)
Motorola ilemcileri bu yerleim biimini kullanr. rnein yukardaki kod Motorola ilemcilerinin
kullanld bir sistemde yazlm olsayd :

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

Birlik Elemanlarnn Bellekteki Organizasyonu


Birlik deikenleri iin birliin en uzun eleman kadar yer ayrlr. Birlik elemanlarnn hepsi ayn
orjinden balayacak ekilde bellee yerleirler. rnein :
union DWORD {
unsigned char byte;
unsigned int word;
unsigned long dword;
};
...
union DWORD a;
bildirimi ile a deikeni iin 4 byte yer ayrlacaktr. nk a deikeninin dword eleman 4 byte
ile birliin en uzun elemandr.
Birlik bir dizi ieriyorsa dizi tek bir eleman olarak alnr. rnein
A00
a.byte
1A01
1A02
1A03

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

Buna gre DBL_FORM X;


...
X.n = 10.2;
ile x.S[0], x.s[1], x.s[2], ....x.s[7] srasyla double elemannn byte deerlerini gstermektedir.
Birlik elemanlarnn ayn orjinden, yani ayn adresten balayarak yerletirilmesi bir elemann
deitirince dier elemanlarnn da ieriinin deiecei anlamna gelir. Zaten birliklerin
kullanlmasnn asl amac da budur. Birlik eleman olarak yaplarn kullanlmas uygulamada en
sk karlalan durumdur. rnein :
struct WORD {
unsigned char low_byte;
unsigned char high_byte;
};
union WORD_FORM {
unsigned int x;
struct WORD y;
};
bildirimlerinden sonra union WORD_FORM trnden bir birlik tanmlanrsa :
union WORD_FORM wf;
bu birliin alak (low_byte) ve yksek (high_byte) anlaml byte deerlerine ayr ayr eriebiliriz
ya da onu bir btn olarak kullanabiliriz :
Yani intel ilemcilerinin bulunduu 16 bit sistemlerde :
wf.y.low_byte = 0x12;
wf.y.high_byte = 0x34;
ilemlerinden sonra;
printf(%x\n, wf.x);
ile 3412 saysn ekrana yazdracaktr. (Motorola ilemcilerinde bellein dk anlaml
blgesinde dk anlaml byte deeri olacana gre saynn ters olarak grlmesi gerekir.
Birlik elemanlarnn bellekte ayn orjinden balanarak yerletirildiini aadaki kod parasndan
da rahatlkla grebiliriz :

282

BRLKLER

Birlik Nesnelerine lk Deer Verilmesi


ANSI ve ISO standartlarna gre birliknes nelerinin yalnzca ilk elemanlarna deer verilebilir.
Eer bir birlik nesnesinin birden fazla elemanna ilk deer verilmeye allrsa derleme
zamannda error oluacaktr:
union DWORD {
unsigned char byte;
unsigned int word;
unsigned long dword;
} x = {'m'};
union DWORD y = {'a', 18, 24L}; /* error */

Birlikler Neden Kullanlr


Birlikler iki amala kullanlabilir. Birincisi yer kazanc salamak iindir. Birlik kullanarak farkl
zamanlarda kullanlacak birden fazla deiken iin ayr ayr yer ayrma zorunluluu ortadan
kaldrlr. rnein bir hediyelik eya katalo ile 3 deiik rnn satldn dnelim: kitap,
tshort ve saat. Her bir rn iin bir stok numaras, fiyat bilgisi ve tip bilgisinin dnda rne
bal olarak baka zelliklerine de sahip olduunu dnelim:
kitaplar : isim, yazar, sayfa sayisi.
t-short : desen, renk, size.
saat : model
struct katalog {
int stok_no;
float fiyat;
int urun_tipi
char kitapisim[20];
char yazar[20];
int sayfa_sayisi;
char desen[20];
int renk;
int size;
char saatisim[20];
int model;
};
Yukardaki bildirimde urun_tipi eleman yalnzca KITAP, TSHORT ya da SAAT olabilecektir.
(Bunlarn sembolik sabit olarak tanmlandn dnelim.) Yukarda bildirilen yap rnlerin
btn zelliklerini tutabilmekle birlikte yle bir dezavantaj vardr :
Eer rn tipi KITAP deil ise isim[20], yazar[30] ve sayfa_sayisi elemanlar hi
kullanlmayacaktr. Yine rn tipi TSHORT deil ise desen[20], renk, size elemanlar hi
kullanlmayacaktr.
Ama katalog yapsnn iine birlikler yerletirirsek yer kazancmz olacaktr:
struct katalog {
int stok_no;
float fiyat;
int urun_tipi
union {
struct {
char isim[20];
char yazar[20];
int sayfa_sayisi;
} kitap;
283

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.

Birliklerin Kark Veri Yaplarnda Kullanlmas


Birlikleri kullanarak, elemanlar farkl trden olan diziler oluturabiliriz.
Belirli deerleri bir dizi iinde tutmak zorunda olduumuzu dnelim. Ancak dizi elemanlar
int, long, double trlerinden olabilsin. rnein dizinin, herhangi bir elemanna ulatmzda
bu eleman int ise onu int olarak, long ise long olarak ve double ise double olarak (bilgi
kayb olmakszn) kullanabilelim.
Diziyi double tr ile tanmlarsak, dizi elemanlarna atama yaptmz zaman, otomatik tr
dnm sonucunda btn elemanlar double trne evrileceinden dizi elemanlarnn tr
bilgisini kaybetmi olurduk.
Ancak aadaki ekilde bir birlik oluturabiliriz :
union DEGER {
int i;
long l;
double d;
};
union DEGER trnden her bir nesne bellekte, en uzun eleman kadar, yani 8 byte yer
kaplayacak, ve her bir eleman (member) ayn adresten balayacaktr.
imdi double trden bir dizi amaktansa union DEGER trnden bir dizi aabiliriz. Dizinin her
bir elemannn, istediimiz alt elemanna deer atamas yapabiliriz :

284

BRLKLER
main()
{
union DEGER s[100];
s[0].i = 3;
s[1].d = 6.
s[2].l = 12L
...

/* s[0] int trden bir deeri tutuyor */


/* s[1] double trden bir deeri tutuyor */
/* s[2] long trden bir deeri tutuyor */

}
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

29 . BLM : BTSEL OPERATRLER


Bitsel operatrler (Bitwise operators) bir tamsaynn bitleri zerinde ilem yapan operatrlerdir,
daha ok sistem programlarnda kullanlrlar. Bitsel operatrlern ortak zellikleri operandlar
olan tamsaylar bir btn olarak deil,
bit bit ele alarak ileme sokmalardr. Bitsel
operatrlerin operandlar tamsay trlerinden olmak zorundadr. Operandlar tamsay
trlerinden birinden deilse derleme zamannda hata oluur.
C dilinde toplam 11 tane bitsel operatr vardr. Bu operatrler, kendi aralarndaki ncelik
srasna gre, aadaki tabloda verilmitir:
2
5
8
9
10
14

~
<<
>>
&
^
|
<<=
>>=
&=
^=
|=

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 :

Bitsel Deil Operatr


Dier tm tek operand alan operatrler gibi operatr ncelik tablosunun ikinci seviyesindedir.
Yan etkisi yoktur. (side effect) Operand bir nesne ise, bu nesnenin bellekteki deerini
deitirmez. rettii deer, operand olan tamsaynn bitleri zerinde 1'e tmleme ilemi
yaplarak elde edilen deerdir. Yani operand olan ifade deerinin 1 olan bitleri 0, 0 olan bitleri
1 yaplarak deer retilir.
#include <stdio.h>
int main()
{
unsigned int x = 0x1AC3;
unsigned int y;

/* x = 0001 1010 1100 0011

*/

y = ~x;
/* y = 1110 0101 0011 1100 */
printf("y = %x\n", y);
/* y = 0xE53C */
return 0;

Bitsel Kaydrma Operatrleri (bitwise shift operators)


ki adet bitsel kaydrma operatr vardr:
Bitsel saa kaydrma operatr >> (bitwise right shift)
Bitsel sola kaydrma operatr << (bitwise left shift)
Her iki operatr de operatr ncelik tablosunun 5. seviyesinde bulunmaktadr. (Dolaysyla bu
operatrlerin ncelii tm aritmetik operatrlerden daha aada fakat karlatrma
operatrlerinden daha yukardadr. Bitsel kaydrma operatrleri binary infix operatrlerdir. (ki
operand alan araek konumundaki operatrlerdir.)

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;

/* x = 0000 0000 0011 0100 */


/* z = 0000 0000 1101 0000
/* z = 208 */

*/

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

/* x = 0000 0000 0011 0100 */


/* z = 0000 0000 0000 1101 */
/* z = 13 */

Bitsel Ve Operatr (bitwise and)


Operatr ncelik tablosunun 8. seviyesindedir. ncelik yn soldan saadr. Yan etkisi yoktur,
operandlar nesne gsteren bir ifade ise bellekteki deerlerini deitirmez. Deer retmek iin
operand olan tamsaylarn karlkl bitlerini Ve ilemine tabi tutar. Ve ilemine ait doruluk
tablosu aada tekrar verilmektedir:
x
y
x&y
1
1
1
1
0
0
0
1
0
0
0
0
Bitsel ve operatrnn rettii
sokulmasyla elde edilen deerdir.

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;

/* x = 0001 1011 1100 0101 */


/* y = 0011 1010 0000 1101 */

/* z = 0001 1010 0000 0101 */

printf("z = %xn", Z);


return 0;

/* z = 0x1A05 */

1 biti bitsel ve ileminde etkisiz elemandr.


0 biti bitsel ve ileminde yutan elemandr.

Bitsel zel Veya Operatr (bitwise exor)


Operatr ncelik tablosunun 9. seviyesindedir. ncelik yn soldan saadr. Yan etkisi yoktur,
operandlar nesne gsteren bir ifadeyse bellekteki deerlerini deitirmez. Deer retmek iin
operand olan tamsaylarn karlkl bitlerini zel veya (exclusive or) ilemine tabi tutar. Bitsel
zel veya ilemine ilikin doruluk tablosu aada verilmektedir:
x
1
1
0
0

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;

/* x = 0001 1011 1100 0101 */


/* y = 0011 1010 0000 1101 */

/* z = 0010 0001 1100 1000 */


/* z = 0x21C8 */

}
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

Baz ifreleme algoritmalarnda zel veya ileminin bu zelliinden faydalanlmaktadr.


bitsel exor operatr tamsay trlerinden iki deikenin deerlerinin, geici bir deiken
olmakszn swap edilmesinde (deerlerinin deitirilmesinde) de kullanlabilir. Aadaki
programda x ve y deikenlerini deerleri bitsel exor operatrnn kullanlmasyla swap
edilmektedir :
#include <stdio.h>
int main()
{
int x = 10;
int y = 20;
x ^= y ^= x^= y;
printf("x = %d\n y = %d\n", x, y);
return 0;
}

Bitsel Veya Operatr (bitwise or operator)


Operatr ncelik tablosunun 10. seviyesindedir. ncelik yn soldan saadr. Yan etkisi
yoktur, operandlar nesne gsteren bir ifade ise bellekteki deerlerini deitirmez. Deer
retmek iin operand olan tamsaylarn karlkl bitlerini veya ilemine tabi tutar. Veya
ilemine ait doruluk tablosu aada verilmektedir:
x
1
1
0
0

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;

/* x = 0001 1011 1100 0101 */


/* y = 0011 1010 0000 1101 */

z = x | y;

/* z = 0011 1011 1100 1101*/

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


return 0;

/* z = 0x3BCD */

0 biti bitsel veya ileminde etkisiz elemandr.


1 biti bitsel ve ileminde yutan elemandr.

Bitsel Operatrlere likin lemli Atama Operatrleri


Bitsel deil operatrnn dnda tm bitsel operatrlere ilikin ilemli atama operatrleri
vardr. Daha nce de sylendii gibi bitsel operatrlerin yan etkileri (side effect) yoktur. Bitsel
operatrler operandlar olan nesnelerin bellekteki deerlerini deitirmezler. Eer operandlar
olan nesnelerin deerlerinin deitirilmesi isteniyorsa bu durumda ilemli atama operatrleri
kullanlmaktadr.

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.

Bitsel Operatrlerin Kullanlmasna likin Baz Temalar


Bitsel operatrlerin kullanlmasna daha ok sistem programlarnda raslanr. Sistem
programlarnda bir saynn bitleri zerinde baz ilemler yaplmas sklkla gerekli olmaktadr.
Aada bitsel dzeyde yaplan ilemlerden rnekler verilmektedir.

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

0000 0000 0100 0001


0000 0000 0010 0000

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

Bir Saynn Belirli Bir Bitinin Deerinin Test Edilmesi (0 m 1 mi)


Bir saynn belirli bir bitinin 0 m 1 mi oldugunun renilmesi iin, sz konusu say, if deyiminin
koul ifadesi olarak (if parantezi iinde) ilgili biti 1 olan ve dier bitleri 0 olan bir sayyla bitsel
ve ilemine tabi tutulmaldr. nk bitsel ve ileminde 0 yutan eleman 1 ise etkisiz elemandr.
programn ak if deyiminin doru ksmna giderse, ilgili bitin 1, yanl ksmna gider ise ilgili
bitin 0 oldugu sonucu karlacaktr.
x bir tamsay olmak zere, bir saynn herhangi bir bitinin 1 ya da 0 olduunu anlamak iin
aadaki ifadeyi yazabiliriz.
if (x & 1 << k)
/* k. bit 1 */
else
/* k. bit 0 */

Bir Saynn Belirli Bir Bitini Ters evirmek (toggle)


Baz uygulamalarda bir saynn belirli bir bitinin deerinin deitirilmesi istenebilir. Yani sz
konusu bir 1 ise 0 yaplacak, sz konusu bit 0 ise 1 yaplacaktr. Bu amala bitsel zel veya
operatr kullanlr. Bitsel zel veya operatrnde 0 biti etkisiz elemandr. Bir saynn k.bitinin
deerini deitirmek iin, say, k.biti 1 dier bitleri 0 olan bir say ile bitsel zel veya ilemine
tabi tutulur.
x bir tamsay olmak zere, bir saynn herhangi bir bitinin deerini deitirmek iin aadaki
ifadeyi yazabiliriz.
x ^= 1 << k;
Bir tamsaynn belirli bitlerini sfrlamak iin ne yapabiliriz? rnein int trden bir nesnenin 7.,
8. ve 9.bitlerini sfrlamak isteyelim (tabi dier bitlerini deitirmeksizin). 7., 8. ve 9. bitleri 0
olan dier bitleri 1 olan bir say ile bitsel ve ilemine tabi tutarz. rnein 16 bitlik int saylarn
kullanld bir sistemde bu say aadaki bit dzenine sahip olacaktr.
1111 1100 0111 1111

(bu say 0xFC7F deilmidir?)

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

for (k = startbit; k <= endbit; ++k)


*ptr &= ~(1 << k);

Benzer ekilde setbits fonksiyonunu da yazabiliriz :


void setbits (int *ptr, int startbit, int endbit)
{
int k;

for (k = startbit; k <= endbit; ++k)


*ptr |= 1 << k;

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

void putvalue(int *ptr, int startbit, int endbit, int value);


{
int temp = value << startbit;

clearbits(ptr, startbit, endbit);


*ptr |= temp;

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;

clearbits(&temp, endbit + 1, sizeof(int) * 8 - 1);


return temp;

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;

for (; i >= 0; --i)


if (x >> i & 1 == 1)
putchar('1');
else
putchar('0');

Bu fonksiyonu aadaki ekilde de yazabilirdik:


#include <stdio.h>
void showbits2(int x)
{
unsigned i = (~((unsigned)~0 >> 1));
while (i) {
if (x & i)
putchar('1');
else
putchar('0');
i >>= 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 no_of_setbits(int value)


{
int counter = 0;
int k;

for (k = 0; k < sizeof(int) * 8; ++k)


if (value & 1<<k)
counter++;
return counter;

int main()
{
int number;

printf("bir say girin : ");


scanf("%d", &number);
printf("saynzn %d biti 1n", no_of_setbits(number));
return 0;

Daha hzl alacak bir fonksiyon tasarlamaya ne dersiniz?


#include <stdio.h>
int no_of_setbits(int value)
{
static int bitcounts[] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};
int counter = 0;
for (; value != 0; value >>= 4)
counter += bitcounts[value & 0x0F];
return counter;
}

294

BT ALANLARI

30 . BLM : BT ALANLARI
konu eklenecek

295

31

31 . BLM : KOMUT SATIRI ARGUMANLARI


Bir program altrdmz zaman, programn almasn ynlendirecek ya da deitirecek
birtakm parametre(leri) alacak programa gndermek isteyebiliriz. Bu parametreler bir dosya
ismi olabilecei gibi, programn deiik biimlerde almasn salayacak bir seenek de
olabilir. UNIX iletim sistemindeki ls komutunu dnelim. Eer ls programn
ls
yazarak altrrsak, bulunulan dizin iindeki dosyalarn isimleri listelenir. (DOS'daki dir komutu
gibi). Ama ls yerine
ls -l
yazlarak program altrlrsa bu kez yalnzca dosya isimleri deil, dizindeki dosyalarn
bykln , dosyalarn sahiplerini, yaratlma tarih ve zamanlarn vs. gsteren daha ayrntl
bir liste ekranda grntlenir. ls programn yine
ls -l sample.c
yazarak altrrsak, yalnzca sample.c dosyasna ilikin bilgiler grntlenecektir. te bir
program altrrken program isminin yanna yazlan dier parametrelere komut satr
argumanlar (command line arguments) denilmektedir.
Komut satr argumanlar yalnzca iletim sistemi komutlar iin geerli deildir. Tm
programlar iin komut satr argumanlar kullanlabilir. Komut satr argumanlarna C dili
standartlarnda program parametreleri (program parameters) denmektedir.
C programlarnn almaya balad main fonksiyonu da istee bal olarak iki parametre
alabilir. Bu parametreler geleneksel olarak argc ve argv olarak isimlendirilirler.
int main(int argc, char *argv[])
{
...
}
argc (argument count) komut satr argumanlarnn saysn gsterir. Bu sayya programn ismi
de dahildir. argv ise , stringler eklinde saklanan komut satr argumanlarn gsteren, char
trden bir gsterici dizisidir. Bu durumda arg[0] gstericisini programn ismini tutan stringi,
argv[1] den argv[argc - 1] e kadar olan gstericiler ise program ismini izleyen dier
argumanlarn tutulduklar stringleri gsterirler. argv[argc] ise her zaman bir NULL gstericiyi
gstermektedir.
Yukardaki rnekte kullanc ls programn
ls -l sample.c eklinde altrdnda
argc 3 deerini alr.
argv[0] program ismini gsterir. argv[1] = "ls";
argv[1] program ismini izleyen 1. arguman gsterir. argv[1] = "-1";
argv[2] program ismini izleyen 2. arguman gsterir. argv[2] = "sample.c";
argv[argc] yani argv[3] ise NULL adresini gsterecektir.
komut satr argumanlar boluklarla birbirinden ayrlm olmaldr. Yukardaki rnekte program
ls -lsample.c eklinde altrlrsa
argc = 2 olurdu.

296

KOMUT SATIRI ARGUMANLARI


Komut satr argumanlarnn ikincisi karakter trnden bir gstericiyi gsteren gstericidir. Yani
argv[0], argv[1], argv[2]... herbiri char trden bir gstericidir. Komut satr argmalar NULL
ile sonlandrlm bir biimde bu adreslerde bulunurlar. argv[0] src ve dizin dahil olmak
zere (full path name) programn ismini vermektedir. Dier argmanlar srasyla argv[1],
argv[2], argv[3], ... adreslerindedir.
Komut satr argumanlar iletim sistemi tarafndan komut satrndan alnr ve derleyicinin
rettii giri kodu yardmyla main fonksiyonuna parametre olarak kopyalanr.
Aada komut satr argmanlarn basan rnek bir program gryorsunuz:
#include <stdio.h>
int main(int argc, char *argv[])
{
int i;
for (i = 0; i < argc; ++i)
printf("argv[%d] : %s\n", i, argv[i]);
return 0;
}
phesiz bu kodu aadaki ekilde de yazabilirdik .
int main(int argc, char *argv[])
{
int i;
for (i = 0; argv[i] != NULL ; ++i)
printf("argv[%d] : %s\n", i, argv[i]);
return 0;
}
Komut satr argumanlarnn isimleri argc ve argv olmak zorunda deildir. Bunlar yerine
herhangi iki isim de kullanlabilir. Ancak argc ve argv isimleri "argument counter" ve "argument
vector" szcklerinden ksaltlmtr. Bu isimler programclar tarafndan geleneksel olarak
kullanlmaktadr.
Komut satr argmanlarn alan programlar genellikle, nce girilen argumanlar yorumlar ve
test ederler. rnein :
int main(int argc, char *argv[])
{
if (argc == 1) {
printf("ltfen bir argumanla altrnz!..\n");
exit(1);
}
if (argc == 2) {
printf("ltfen bir argumanla altrnz!..\n");
exit(1);
}
return 0;
}
Yukardaki rnekte program bir komut satr arguman verilerek altrlmadysa (yani eksik
argumanla altrldysa) bir hata mesajyla sonlandrlyor. Benzer biimde fazla sayda
argman iin de byle bir kontrol yaplmtr.
DOS'ta olduu gibi baz sistemlerde main fonksiyonu nc bir parametre alabilir. nc
parametre sistemin evre deikenlerine ilikin bir karakter trnden gstericiyi gsteren
gstericidir.
297

31

int main(int argc, char *argv[], char *env[])


{
...
return 0;
}
main fonksiyonuna tm parametreler geilmek zorunda deildir. rnein :
int main(int argc)
{
...
return 0;
}
gibi yalnzca birinci parametrenin kullanld bir tanmlama geerlidir. Ancak yalnzca ikinci
parametre kullanlamaz. rnein:
int main(char *argv[])
{
...
return 0;
}

Komut Satr Argumanlarnn Kullanlmasna Bir rnek


Komut satrndan alan basit bir hesap makinas
#include
#include
#include
#include

<stdio.h>
<conio.h>
<stdlib.h>
<math.h>

int main(int argc, char *argv[])


{
char ch;
int op1, op2;

if (argc != 4) {
printf("usage : cal Op1 Operator Op2\n");
exit(EXIT_FAILURE);
}
op1 = atoi(argv[1]);
op2 = atoi(argv[3]);
ch = argv[2][0];
printf(" = ");
switch (ch) {
case '+'
: 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.

Dosyalara likin Temel Kavramlar


Dosyann Almas
Bir dosya zerinde ilem yapmadan nce dosya almaldr. Dosya aabilmek iin iletim
sisteminin dosya a isimli bir sistem fonksiyonu kullanlr. Dosyann almas srasnda dosya
ile ilgili eitli ilk ilemler iletim sistemi tarafndan yaplr.
Bir dosya aldnda, dosya bilgileri, ismine Dosya Tablosu (File table) denilen ve iletim
sisteminin ierisinde bulunan bir tabloya yazlr. Dosya tablosunun biimi sistemden siteme
deiebilir. rnein tipik bir dosya tablosu adaki gibi olabilir :
Dosya tablosu (File table)
Sra No Dosya ismi
0
1
...
12
...

AUTOEXEC.BAT

Dosyann
Diskteki Yeri

Dosyann
zellikleri

Dierleri

...

...

...

Sistem fonksiyonlarnn da parametreleri ve geri dn deerleri vardr. "Dosya a" sistem


fonksiyonunun parametresi alacak dosyann ismidir.Fonksiyon, dosya bilgilerinin yazld sra
numaras ile geri dner ki bu deere "file handle" denir. Bu handle deeri dier dosya
fonksiyonlarna parametre olarak geirilir. Dosyann almas srasnda buna ek olarak baka
nemli ilemler de yaplmaktadr.

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.

Dosyaya Bilgi Yazlmas ve Okunmas


letim sistemlerinin dosyaya n byte veri yazan ve dosyadan n byte veri okuyan sistem
fonksiyonlar vardr. Yazma ve okuma ilemleri bu fonksiyonlar kullanlarak yaplr.

299

32

Dosya pozisyon gstericisi (file pointer)


Bir dosya bytelardan oluur. Dosyadaki her bir bytea 0dan balayarak artan srada bir say
karlk getirilmitir. Bu sayya ilgili byten ofset numaras denir. Dosya pozisyon gstericisi
long trden bir saydr ve bir ofset deeri belirtir. Dosyaya yazan ve dosyadan okuma yapan
fonksiyonlar bu yazma ve okuma ilemlerini her zaman dosya pozisyon gstericisinin gsterdii
yerden yaparlar. rnein dosya gstericisinin gsterdii yer 100 olsun. Dosyadan 10 byte bilgi
okumak iin sistem fonksiyonu arldnda, 100. ofsetden itibaren 10 byte bilgi okunur.
letim sisteminin dosya gstericisini konumlandran bir sistem fonksiyonu vardr. Dosya ilk
aldnda dosya gstericisi 0. ofsetdedir. rnein bir dosyann 100. Ofsetinden itibaren 10
byte okunmak istenirse sras ile u ilemlerin yaplmas gerekir:
lgili dosya alr.
Dosya pozisyon gstericisi 100. Offsete konumlandrlr.
Dosyadan 10 byte okunur.
Dosya kapatlr.
C dilinde dosya ilemleri 2 biimde yaplabilir :
1. letim sisteminin sistem fonksiyonlar dorudan arlarak.
2. Standart C fonksiyonlar kullanlarak.
Prototipleri stdio.h ierisinde olan standart dosya fonksiyonlarnn hepsinin ismi f ile balar.Tabi
standart C fonksiyonlar da ilemlerini yapabilmek iin aslnda iletim sisteminin sistem
fonksiyonlarn armaktadr. letim sisteminin sistem fonksiyonlar tanabilir deildir.
simleri ve parametrik yaplar sistemden sisteme deiebilir. Bu yzden standart C
fonksiyonlarnn kullanlmas tavsiye edilir.

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;

if ((f = fopen(data, w)) ==NULL) {


printf(cannot open file...\n);
exit(1);
}
fclose(f);
return 0;

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

Text ve Binary Dosya Kavramlar


DOS VE WINDOWS iletim sistemlerinde bir dosya text ve binary modda alabilir. Varsaylan
a modu textdir. Yani dosyann hangi modda ald ak bir ekilde belirtilmezse dosyann
text modda ald varsaylacaktr. Dosyay binary modda aabilmek iin a modunun
sonuna b eklemek gerekir. rnein :
f = fopen(data, r) text modda
f = fopen(data, rb) binary modda
DOSda bir dosya type edildiinde bir karakter aa satrn banda grnyorsa bunu
salamak iin o karakterden nce CR (carriage return) ve LF (line feed) karakterlerinin
bulunmas gerekir. CR karakteri Cde \r ile belirtilir. 13 numaral ASCII karakteridir. LF
karakteri Cde \n ile belirtilir. 10 numaral ASCII karakteridir. rnein bir dosya type
edildiinde grnt
a
b
eklinde olsun. Dosyadaki durum a\r\nb eklindedir. Oysa UNIX sistemlerinde aa satrn
bana geebilmek iin sadece LF karakteri kullanlmaktadr. UNIX de
a
b
grntsnn dosya karl
a\nb biimindedir.
DOSda LF karakteri bulunulan satrn aasna ge CR karakteri ise bulunulan satrn bana
ge anlamndadr. rnein DOS da bir bir dosyann ierii a\nb biiminde ise dosya type
edildiinde
a
b
grnts elde edilir. Eer dosyann ierii a\rb biiminde ise dosya type edildiinde
b
grnts elde edilir.
printf fonksiyonunda \n ekranda aa satrn bana geme amacyla kullanlr. Aslnda biz
printf fonksiyonunun 1. parametresi olan stringin iine \n yerletirdiimizde
UNIX'de
yalnzca \ni DOS'da ise \r ve\n ile bu gei salanr.
Text dosyalar ile rahat alabilmek iin dosyalar text ve binary olarak ikiye ayrlmtr. Bir
dosya text modunda aldnda dosyaya \n karakteri yazlmak istendiinde dosya fonksiyonlar
otomatik olarak \r ve \n karakterlerini dosyaya yazarlar. Benze r bir biimde dosya text modda
almsa dosya gstericisi \r\n iftini gsteriyorsa dosyadan yalnzca /n karakteri okunur. DOS
iletim sisteminde text ve binary dosyalar arasndaki baka bir fark da, CTRL Z (26 numaral
ASCII karakterinin) dosyay sonlandrdnn varsaylmasdr. Oysa dosya binary modda
aldnda byle bir varsaym yaplmaz.

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

/* simdi '\x1A' karakterinin text modunda dosyay sonlandrmas zellii


test ediliyor */
fp = fopen("deneme", "w");
if (fp == NULL) {
printf("dosya alamyor\n");
exit(EXIT_FAILURE);
}
/* dosyaya 5 tane 'A' karakteri yazdrlyor */
for (k = 0; k < 5; ++k)
fputc('A', fp);
/* dosyaya '\x1A' karakteri yazdrlyor */
fputc('\x1a', fp);
/* dosyaya 10 tane 'A' karakteri yazdrlyor. */
for (k = 0; k < 5; ++k)
fputc('A', fp);
fclose(fp);
printf("\ndosya binary modda alarak yazdrlyor :\n");
fp = fopen("deneme", "rb");
if (fp == NULL) {
printf("dosya alamyor\n");
exit(EXIT_FAILURE);
}
while ((ch = fgetc(fp)) != EOF)
printf("%d ", ch);
/* ekran kts
65 65 65 65 65 26 65 65 65 65 65
*/
printf("\ndosya
kapatld,
imdi
yazdrlyor\n");
fp = fopen("deneme", "r");
if (fp == NULL) {
printf("dosya alamyor\n");
exit(EXIT_FAILURE);
}
while ((ch = fgetc(fp)) != EOF)
printf("%d ", ch);
/* ekran kts
65 65 65 65 65 26 65 65 65 65 65
*/
fclose(fp);
return 0;
}

307

dosya

text

modunda

alarak

32

EOF (END OF FILE) DURUMU


Dosyann sonunda hibir zel karakter yoktur. letim sistemi dosyann sonuna gelinip
gelinmediini dosyann uzunluuna bakarak anlayabilir. EOF durumu dosya pozisyon
gstericisinin dosyada olmayan son karakteri gstermesi durumudur. EOF durumunda dosya
pozisyon gstericisinin offset deeri dosya uzunluu ile ayn deerdedir. EOF durumunda
dosyadan okuma yaplmak istenirse dosya fonksiyonlar baarsz olur. Ancak a modu
uygunsa dosyaya yazma yaplabilir ve bu durumda dosyaya ekleme yaplr.
Daha nce sylendii gibi C dilinde alan bir dosya ile ilgili bilgiler FILE trnden bir yap
nesnesi iinde tutulur. Bu yapnn her bir eleman dosyann bir zellii hakknda bilgi
vermektedir. C programcs bu yapnn elemanlarnn deerleri ile dorudan ilgilenmez, zira
fopen fonksiyonunun geri dn deeri bu yap nesnesini gsteren FILE yaps trnden bir
gstericidir ve C dilinin dosyalarla ilgili ilem yapan fonksiyonlar ounlukla bu adresi
parametre olarak alarak, istenilen dosyaya ularlar.
Sz konusu FILE yapsnn elemanlarndan biri de flag olarak kullanlan EOF indikatrdr.
(aslnda int trden bir flag'in yalnzca belirli bir bitidir.) C dilinin dosyalarla ilgili ilem yapan
baz fonksiyonlar EOF indikatrnn deerini deitirirler. (set ya da clear ederler. Set edilmesi
bu indikatre 1 deerinin atanmas clear edilmesi ise 0 deerinin atanmasdr. Bu indikatrn
set edilmesi demek dosya pozisyon gstericisinin dosyann sonunu gstermesi demektir.
Dosya aan fonksiyonlar FILE yapsndaki EOF indikatrn sfrlarlar. Bu fonksiyonlar dnda
fseek fonksiyonu ve clearerr fonksiyonlar da EOF indikatrn sfrlarlar. (clear ederler).
fseek fonksiyonu :
Bu fonksiyon dosya pozisyon gstericisini istenilen bir offsete konumlandrmak amacyla
kullanlr. Bu fonksiyonun kullanlmasyla, alm bir dosyann istenilen bir yerinden okuma
yapmak ya da istenilen bir yerine yazmak mmkn hale gelir. Prototipi :
int fseek(FILE *f, long offset, int origin);
Fonksiyonun ikinci parametresi konumlandrma ileminin yaplaca offset deeridir.
Fonksiyonun 3. parametresi 0, 1, veya 2 olabilir. Bu deerler stdio.h dosyasnda
#define SEEK_SET
#define SEEK_CUR
#define SEEK_END

0
1
2

biiminde sembolik sabitlerle tanmlanmtr ve fseek fonksiyonun arlmasnda daha ok bu


sembolik sabitler kullanlmaktadr.
son parametre 0 ise, konumlandrma dosya bandan itibaren yaplr. Bu durumda 2.
parametre >= 0 olmaldr. rnein:
fseek(f, 10L, 0);
ile dosya gstericisi 10. offsete konumlandrlr. Ya da
fseek(f, 0, 0);
ile dosya gstericisi dosyann bana konumlandrlr. Dosya pozisyon gstericisinin dosyann
bana konumlandrlmas iin rewind fonksiyonu da kullanlabilir:
void rewind(FILE *fp);
rewind(f);
fonksiyonun 3. parametre deikenine geilen deer 1 ise (SEEK_CUR) , konumlandrma dosya
gstericisinin en son bulunduu yere gre yaplr. Bu durumda ikinci parametre pozitif ya da

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

fread fonskiyonu dosya pozisyon gstericisinin gsterdii yerden, 2. ve 3. parametresine


kopyalanan deerlerin arpm kadar byte' , RAM'de 1. parametresinin gsterdii adresten
balayarak kopyalar. Geleneksel olarak fonksiyonun 2. parametresi veri yapsnn bir
elemannn uzunluunu, 3. parametresi ile para says biiminde girilir.
Bu fonksiyonlar sayesinde diziler ve yaplar tek hamlede dosyaya transfer edilebilirler. rnein
10 elemanl bir dizi aadaki gibi tek hamlede dosyaya yazlabilir.
int a[5] = {3, 4, 5, 7, 8};
fwrite (a, sizeof(int), 5, f);
Yukardaki rnekte, dizi ismi olan a int trden bir adres bilgisi olduu iin, fwrite fonksiyonuna
1. arguman olarak gnderilebilir. FILE trnden f gstericisi ile ilikilendirilen dosyaya RAM'deki
a adresinden toplam sizeof(int) * 5 byte yazlmaktadr.
Ancak tabi fwrite fonskiyonu saylar bellekteki grnts ile dosyaya yazar. (yani fprintf
fonksiyonu gibi formatl yazmaz.) rnein:
int i = 1535;
fwrite(&i, sizeof(int), 1, f);
Burada dosya type edilirse 2 byte uzunluunda rasgele karakterler grnr. nk DOS'da int
tr 2 byte uzunluundadr. Bizim grdmz ise 1525'in rasgele olan bytelardr. Bilgileri
ASCII karlklar ile dosyaya yazmak iin fprintf fonksiyonu kullanlabilir..
fread ve fwrite fonksiyonlar bellekteki bilgileri transfer ettiine gre dosyalarn da binary
modda alm olmas uygun olacaktr.
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *f;
int i;
int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int b[10];
if ((f = fopen("data", w+b")) == NULL) {
printf("cannot open file...\n");
exit(EXIT_FAILURE);
}
fwrite (a, sizeof(int), 10, f);
fseek(f, 0, SEEK_SET);
fread(b, sizeof(int), 10, f);
for (i = 0; i < 10; ++i)
printf("%d\n", b[i]);
}
fread ve fwrite fonksiyonlarnn geri dn deerleri 3. parametresi ile belirtilen okunan ya da
yazlan para saysdr. rnein
n = fread(a, sizeof(int), 10, f);
ifadesinde fonksiyon btn saylar okuyabildiyse 10 saysna geri dner. Eer dosyadaki kalan
byte says okunmak istenen saydan az ise fonksiyon btn byte'lar okur ve geri dn deeri

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;

printf("kaynak dosya : ");


gets(s);
printf("ama dosya : ");
gets(d);
if ((fs = fopen(s, "rb")) == NULL) {
printf("cannot open file ...\n");
exit(EXIT_FAILURE);
}
if ((fd = fopen(d, "wb")) == NULL) {
printf("cannot open file ...\n");
fclose(fs);
exit(EXIT_FAILURE);
}
while ((n = fread(buf, 1, BLOCK_SIZE, fs)) > 0)
fwrite(buf, 1, n, fd);
fclose(fs);
fclose(fd);
printf("1 file copied...\n");
return 0;

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;

printf("Ad soyad : ");


fflush(stdin);
gets(per.name);
printf("No : ");
scanf("%d", &per.no);
per.delflag = NORMALREC;
fseek(f, 0, SEEK_END);
fwrite(&per, sizeof(PERSON), 1, f);

void FindRec(void)
{
PERSON per;
315

32
char name[30];

printf("ltfen kayt ismini giriniz :");


fflush(stdin);
gets(name);
fseek(f, 0, SEEK_SET);
while (fread(&per, sizeof(PERSON), 1, f) > 0) {
if (per.delflag != NORMALREC)
continue;
if (!stricmp(per.name, name)) {
printf("\n%s
%d\n\n", per.name, per.no);
return;
}
}
printf("\nKayt bulunamad...\n\n");

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;

printf("\n1) Kayt Ekle\n");


printf("2) Kayt Listele\n");
printf("3) Kayt Bul\n");
printf("4) Kayt Sil\n");
printf("5) Kayt deitir\n");
printf("6) Pack\n");
printf("7) Srala\n");
printf("8) k\n");
printf("\nSeiminiz :");
scanf("%d", &option);
if (option < 0 || option > 8)
return INVALID;
return 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;

if ((fnew = fopen("temp", "wb")) == NULL) {


printf("cannot create temporary file!..\n");
exit(EXIT_FAILURE);
}
fseek(f, 0l, SEEK_SET);
while (fread(&per, sizeof(PERSON), 1, f) > 0) {
if (per.delflag == NORMALREC)
fwrite(&per, sizeof(PERSON), 1, fnew);
}
fclose(fnew);
fclose(f);
if (unlink(fname)) {
printf("Fatal Error : Cannot open database file!..\n");
exit(EXIT_FAILURE);
}
if (rename("temp", fname)) {
printf("fatal Error: cannot delete database file!..\n");
exit(EXIT_FAILURE);
}
if ((f = fopen(fname, "r+b")) == NULL) {
printf("Fatal Error : Cannot open database file!..\n");
exit(EXIT_FAILURE);
}
printf("Pack operation succesfully completed!..\n");

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

Uygulama 2: developer's back up program (G. Aslan)

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

*Buffer, *in_buf, *out_buf;


CmpFile[128], OutFile[128];

int filecmp(FILE *fi, FILE *fo)


{
int c1, c2;
long l1, l2;
l1 = filelength(fileno(fi));
l2 = filelength(fileno(fo));
if (l1 != l2)
return FAIL;
rewind(fi);
rewind(fo);
for (;;) {
c1 = getc(fi);
c2 = getc(fo);
if (c1 != c2) {
return FAIL;
}

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

if ((fo = fopen(OutFile, "wb")) == NULL) {


ptr = OutFile;
goto OPN_ERR;
}
setvbuf(fo, out_buf, _IOFBF, FBUFSIZ);
if (filecopy(fi, fo)) {
fprintf(stderr, "File copy error!\n");
return 4;
}
fcloseall();
}

return 0;

Uygulama 3 : bol.c ve bir.c programlar :


bir dosyann belirkli byte byklnde n kadar sayda dosyaya blnmesi ve daha sonra baka bir
programla bu dosyalarn tekrar birletirilmesi.

/*******bol.c *******************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define

MAX_LEN

80

int main(int argc, char **argv)


{
FILE *fs, *fd;
char fsname[MAX_LEN];
char fdname[MAX_LEN] = "dos0001.xxx";
int chunk;
long no_of_chars = 0L;
int no_of_files = 0;
int ch;
if (argc != 3) {
printf("bolunecek dosyanin ismini giriniz : ");
gets(fsname);
printf("kac byte'lik parcalara bolmek istiyorsunuz?");
scanf("%d", &chunk);
}
else {
strcpy(fsname, argv[1]);
chunk = atoi(argv[2]);
}
printf("%s dosyasi %d uzunlugunda dosyalara bolunecek!\n", fsname, chunk);
fs = fopen(fsname, "rb");
if (fs == NULL) {
printf("%s dosyasi acilamiyor!\n", fsname);
exit(EXIT_FAILURE);
}
fd = NULL;
while ((ch = fgetc(fs)) != EOF) {
321

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

printf("%ld uzunlugunda %s dosyasi %d uzunlugunda


bolundu!\n",
no_of_chars, fsname, chunk, no_of_files);
}

return 0;

/*******bir.c *******************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define

MAX_LEN

80

int main(int argc, char **argv)


{
FILE *fs, *fd;
char fdname[MAX_LEN];
char fsname[MAX_LEN] = "dos0001.xxx";
int ch;
int no_of_files = 0;
long no_of_chars = 0L;
int k;
if (argc != 2) {
printf("birlestirilecek dosyanin ismini giriniz : ");
gets(fdname);
}
else {
strcpy(fdname, argv[1]);
}
fd = fopen(fdname, "wb");
if (fd == NULL) {
printf("%s dosyasi yaratilamiyor!\n", fdname);
exit(EXIT_FAILURE);
}

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

33 . BLM : enum TR VE enum SABTLER


Yazlan bir ok programda, yalnzca belirli anlaml deerler alabilen deikenler kullanma
ihtiyac duyulur. rnein bir "Boolean" deikeni, yalnzca iki deere sahip olabilmektedir
(doru ve yanl deerleri) C dilinde Boolean diye bir veri tipinin olmadn hatrlayalm. Baka
bir rnek olarak bir oyun kadnn rengini tutacak bir deikeni verebiliriz. Byle bir deiken
yalnzca 4 deiik deer alabilecektir : Sinek, Karo, Kupa, Maa. Uygulamalarda yaplacak olan,
deikene tamsay deerleri vermek ve her tamsayy deikenin alaca deerle
ilikilendirmektir. rnein:
int renk;

/* renk deikeni iskambil kadnn renk bilgisini tutacak */

renk = 1;

/* 1 tamsay sabitinin karoyu temsil ettiini varsayalm */

Byle bir teknik uygulamalarda pekala kullanlabilir. Ancak bu tekniin


alglanabilmesinin ve okunabilmesinin zor olmasdr. Program okuyacak kii

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.

enum Trnn ve enum Trne likin enum Sabitlerinin Bildirimi


enum [trn ismi] {esabit1, esabit2, ......};
enum bir anahtar szcktr. Derleyici kme parantezleri arasnda isimlendirilmi sembolik
sabitlere 0 deerinden balayarak artan srada bir tamsay karlk getirir. rnek:

324

enum TR VE enum SABTLER


enum RENK {Sinek, Karo, Kupa, Maca};
gibi bir bildirim yapldnda Sinek enum sabiti 0, Karo enum sabiti 1, Kupa enum sabiti 2,
Maca enum sabiti ise 3 deerini alr.
enum BOOL {FALSE, TRUE};
burada TRUE enum sabiti 1 FALSE enum sabiti ise 0 deerini alacaktr.
enum MONTHS {January, February, March, April, May, June, July, August,
September, October, November, December};
Bu bildirimde January = 0, February = 1, ... December = 11 olacak ekilde enum sabitlerine
0 deerinden balatarak ardl olarak deer verilir.
Eer enum sabitlerine atama operatr ile kme parantezleri iinde deerler verilirse, bu
ekilde deer verilmi enum sabitinden sonraki sabitlerin deerleri birer artarak otomatik
olarak verilmi olur:
enum MONTHS {January = 1, February, March, April, May, June, July, August,
September, Oktober, November, December};
Artk ayn rnek iin enum sabitlerinin deerleri January = 1, February = 2, ... December = 12
olmutur.
enum sabitlerine int tr say snrlar ierisinde pozitif ya da negatif deerler verilebilir :
enum Sample {
RT1 = -127,
RT2,
RT3,
RT4 = 12,
RT5,
RT6,
RT7 = 0,
RT8,
RT9 = 90
};
Yukardaki tanmlamada sabitlerin alaca deerler aadaki gibi olacaktr :
RT1 = -127, RT2 = -126, RT3 = -125, RT4 = 12, RT5 = 13, RT6 = 14, RT7 = 0, RT8 = 1, RT9
= 90
Grld gibi bir enum sabitine atama operatr ile atama yapld zaman onu izleyen
enum sabitlerinin alaca deerler, bir sonraki atamaya kadar, ardl olarak deerleri 1'er
artarak biimde oluturulur.
Yukardaki ifadelerin hepsi bildirim ifadeleridir, tanmlama ilemi deildir. Bir baka deyile
derleyici bir nesne yaratmamakta ve dolaysyla bellekte bir yer ayrmamaktadr.
enum bildirimi tr bildirmektedir. Bildirilen tr enum trnn yaratlmasnda kullanlan enum
tr ismidir. (enumeration tag). Tpk yaplarda ve birliklerde olduu gibi bu trden bir nesne de
tanmlanabilir:
enum
enum
enum
enum

Sample rst;
MONTHS this_month;
RENK kart1, kart2, kart3;
BOOL flag1, openflag, endflag, flag2;

325

33

Bildirimlerde enum tr ismi (enumeration tag) hi belirtilmeyebilir. Bu durumda genellikle


kme parantezinin kapanmasndan sonra o enum trnden nesne(ler) tanmlanarak ifade
noktal virgl ile sonlandrlr.
enum {Sunday = 1, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday} day1, day2,
day3;
Yukardaki rnekte day1, day2, day3 bildirimi yaplm enum trnden (belirli bir enum tr
ismi yok) yaratlm deikenlerdir. Byle bir tanmlama ileminin dezavantaj, artk bir daha
ayn enum trnden baka bir deikenin yaratlmamasdr.
enum trnden bir nesne iin derleyici, kullanlan sistemde int trnn uzunluu ne kadar ise,
o uzunlukta bir yer ayrr. Derleyici iin enum trden bir nesne ile int trden bir nesne
arasnda herhangi bir fark bulunmamaktadr.
rnein DOS altnda:
sizeof(rst) == sizeod(rst) == sizeof(this_month) == sizeof(kart1) == sizeof(flag1) == 2
olacaktr.
enum ile bir tr tanmlandna gre, bu trden nesne yaratlabilecei gibi fonksiyonlarn geri
dn deerleri ve / veya parametre deikenleri de enum ile yaratlm trden olabilirler.
rnein :
RENK kartbul (RENK kart1, RENK kartt2);
Kartbul fonksiyonu enum RENK trnden iki parametre almakta ve enum RENK trnden bir
deere ger dnmektedir.
Aadaki program parasn inceleyelim:
...
enum RENK {Sinek = 0, Karo, Kupa, Maca};
RENK kartbul(RENK kart1, RENK kart2);
...
{
RENK kartx, karty, kartz;
....
kartx = kartbul(karty, kartz);
if (kartx == Sinek){
...
}
}
kartx, karty, kartz deikenleri enum RENK trndendir. Prototipini grdmz kartbul
fonksiyonu da enum RENK trnden iki parametre almakta ve enum KART trnden bir
deere geri dnmektedir. Dolaysyla program paras iinde kartx deikenine enum RENK
trnden bir deer atanm olacaktr.
enum sabitleri ve #define nilemci komutuyla tanmlanm sembolik sabitler nesne
belirtmezler. rnein:
enum METAL {Demir, Bakir, Kalay, Cinko, Kursun};
...
Bakir = 3;
/* hata oluturur. nk enum sabitleri sol taraf deeri deillerdir. */

326

enum TR VE enum SABTLER

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

enum Trnn ve enum Sabitlerinin Kullanmna likin Uyarlar


enum tr ile bildirilen tr ismi kapsamnda bildirimi yaplan sembolik sabitlerin tamsay olarak
derleme aamasnda deerlendirildii sylenmiti. enum trnden tanmlanan bir deikene
enum ablonunda belirtilen sembolik sabitler yerine tamsaylar ile atama yaplabilir.
enum BOOL {TRUE, FALSE} flag1;
327

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

Yukardaki makro tanmlamasnda x ve y makroya ilikin parametrelerdir. nilemci yukardaki


satr grdkten sonra kaynak kod iinde bu makronun arldn tespit ederse, makroyu
yukardaki ablona gre aacaktr. rnein kaynak kod ierisinde
a = Alan(b, c);
eklinde bir deyimin yer aldn dnelim. Bu durumda nilemci Alan makrosunun
arldn anlar. Ve ifadeyi aadaki ekilde aar :
a = ((b) * (c));
Makro almnn sadece metinsel bir yer deitirme oldugunu bilmeliyiz. Yani yukardaki deyim
rnein :
a = Alan(7 + 3, 8 + 1);
eklinde olsayd, nilemci bunu
a = ((7 + 3) * (8 + 1));
eklinde aacakt. Yer deitirme ilemcinin derlemenin n modl olan nilemci tarafndan
derleme ncesi yapldn ve derleyicinin object kod oluturmak iin ele ald kaynak kodun
nilemci modlnn kts olduunu hatrlatalm. Yani derleyicinin ele ald kodda artk
makro armlar deil makrolarn nilemci tarafndan alm biimleri bulunacaktr.
Baka bir makroyu inceleyelim :
#include <stdio.h>
#define Kare_fark(x, y)

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

((y) % 4 == 0 && (y) % 100 != 0 || (y) % 400 == 0)

Makrolar Ne Amala Tanmlanr


Makrolar fonksiyonlara bir alternatif olarak kullanlmaktadr. Yukardaki rnekleri tekrar
inceleyelim. Alan makrosu yerine:
int alan(int en, int boy)
{
return en * boy;
}
Kare_fark makrosu yerine:
int Kare_fark(int a, int b);
{
return (a - b) * (a + b);
}
is_leap makrosu yerine:
int is_leap(int year)
{
return year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
}
fonksiyonlar tanmlanabilirdi.
Baka bir rnek olarak da toupper fonksiyonunun makro biiminde tanmlanm olmas
verilebilir. (toupper derleyicilerin ounda fonksiyon olarak deil makro biiminde
tanmlanmtr.)
#define TOUPPER(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
Aada fonksiyon tanmlamalarna alternatif olacak baz basit makrolar tanmlanmaktadr:
#define
#define
#define
#define

ISUPPER(c)
ISLOWER(c)
ISDIGIT(c)
ISEVEN(x)

((c) >= 'A' && (c) >= 'Z')


((c) >= 'a' && (c) >= 'z')
((c) >= '0' && (c) >= '9')
((x) % 2 == 0)

Bir makronun parametresi olmayabilir. rnein:


330

MAKROLAR

#define getchar()

getc(stdin)

Yukardaki makro yerine sembolik sabit de kullanlabilirdi. Ancak fonksiyon yapsna benzetmek
amacyla parametresi olmayan bir makro olarak tanmlanmtr.

Makrolarla Fonksiyonlar Arasndaki Farkllklar Nelerdir


Makrolar fonksiyonlara alternatif olarak kullanulmalarna karlk, makrolar ile fonksiyonlar
arasnda ok nemli farklar bulunmaktadr:
1. Makrolar kaynak kodu dolaysyla da alabilir (exe) kodu bytrler. Makrolar nilemci
aamasnda deerlendirilir. rnein is_leap makrosunun #define nilemci komutuyla
tanmlandktan sonra kaynak kod iinde yz kere arldn dnelim. nilemci kaynak
kodu ele aldnda yz tane arlma ifadesinin her biri iin makroyu aacaktr. Derleyici
modl kaynak kodu ele aldnda artk makrolar deil makrolarn alm eklini
grecektir. Makro almlar kaynak kodu bytecektir. Kaynak kodun bymesinden dolay
alabilen dosyann boyutu da byyecektir. Oysa makro yerine bir fonksiyon
tanmlansayd, Fonksiyon arlmas durumunda yalnzca arlma bilgisi kayanak koda
yazlmaktadr.
2. Makrolarn en byk avantaj, fonksiyon arma ilemindeki greli yavalktan kaynaklanr.
Fonkiyon armas sembolik makine dili (assembler) dzeyinde ele alndnda, baz ilave
makine komutlar da icra edilmekte ve bu makine komutlarnn icras ve yaplan baz ilave
ilemler icra sresini uzatacaktr.
Fonksiyon arlrken CALL ve geri dnte RET makine komutlar icra edilmektedir.
Fonksiyon arm iin ayrca parametre aktarm ve stack dzenlemesi ilemleri
yaplmaktadr. Makrolarn almas metinsel bir yer deitirme olduu iin, yukarda
anlatlan ilave ilemler yaplmaz. Byece programn hz grece olarak artacaktr.
3. Makrolar trden bamszdr. (generic). Makrolar metinsel bir yer deitirme olduundan
fonksiyonlar gibi belirli bir tre bal deildirler. rnein iki saydan byne geri dnen
bir fonksiyon yazmak istersek bu fonksiyonun parametre deikenleri belirli bir trden
olmak zorundadr:
int max_of_two(int number1, int number2)
{
return (number1 > number2 ? number1 : number2);
}
Yukardaki fonksiyon int trden deerler iin yazIlmtr. Baka trden deerler fonlksiyona
arguman olarak gnderildinde tr dnm kurallar ileyecek ve argumanlarn tr
parametre deikenlerinin trlerine dntrlecektir. Oysa yukardaki fonksiyon yerine bir
makro tanmlanm olmas durumunda bu makro trden bamsdz olacaktr :
#define max_of_two(a, b)

((a) > (b) ? (a) : (b))

Yukardaki makro aadaki ekillerde arlabilir:


int x, y, z;
char c1, c2, c3;
double d1, d2,d3;
...
x = max_of_two(y, z);
c1 = max_of_two(c2, c3);
d1 = max_of_two(d2, d3);
4. Fonksiyonlar kendilerine gnderilen argumanlar bir kez ele alrlar ancak makrolar
argumanlarn birden fazla ele alabilirler:

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

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

rnein kaynak kod ierisinde


int result = 5;
PRINT_INT(result);

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.

Makro tanmlamalarnda nelere dikkat edilmelidir?


Makro tanmlamalarnda en sk yaplan hatalar makro alm neticesinde, operatr ncelikleri
yznden alm kodun beklenilmeyen ekilde deer retmesidir. rneklerle aklayalm :
#define ALAN(a)

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)

eklinde tanmlansayd makro arm nilemci tarafndan aldnda

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

eklinde tanmlanm olsayd


x = 72 / ((y + 5) * (y + 5) );
makro nilemci tarafndan yukardaki gibi alacakt ve bu kodun icras ile x deikenine
gerekten 2 deeri atanacakt.
Makrolarla ilgili olarak sk yaplan baka bir hata da makro tanmlamasnda makro ismi ile
makro parametre parantezi arasnda boluk brakmaktr. ALAN makrosunun yanllkla
aadaki gibi tanmlandn dnelim.
#define ALAN (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)

((a) * (a))(x + 3);

ayn isimli makro ve fonksiyonlar


Bir makro ile ayn isimli bir fonksiyon kaynak kod iinde yer alabilir. Bu durumda bu isimle bir
arm yapldnda ne olacaktr. makro mu fonksiyon mu arlm olacaktr?
#define max(x, y)

((x )> (y) ? (x) : (y))

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.

uzun makrolarn yazlmas


Daha ilevsel makrolarn yazlmasnda virgl operatr kullanlabilir. Aadaki makroyu
dnelim:
#define ECHO(s)

(gets(s), puts(s))

Fonksiyon armlar da birer ifade olduundan, fonksiyon arm ifadelerinin virgl


operatryle birletirilmesi tamamen legaldir. Yukardaki makroyu bir fonksiyonmu gibi
arabiliriz:
char *ptr = "Ahmet";
ECHO(str);
nilemci makroyu aadaki ekilde aacaktr :
char *ptr = "Ahmet";
(gets(str), puts(str));
Ancak bir makronun bir seri deyimi ierdiini dnelim. fade yerine belirli sayda deyimin
olmas, baz durumlarda virgl operatrnn kullanlmasna izin vermeyebilir. nk virgl
operatrnn operandlar deyim deil ifadelerdir.
Uzun ve ilemsel makrolarn yazlmasnda virgl operatrnn kullanlmas yerine makro
deitirme listesini en dtan kme parantezleri iine de alabilirdik :
#define ECHO(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)

\
\
\
\

(#define nilemci komutunun kullanlmasnda satr sonunda yer alan "\"


komutun bir sonraki satrda devam edeceini gsterdiini hatrlayalm)

karakterinin

artk yukardaki makro


ECHO(str);
eklinde arldnda, makro nilemci tarafndan aldktan sonra,
arma ifadesinin
sonundaki sonlandrc (;) do while deyiminin sentaksnda bulunan while parantezini izleyen
sonlandrc olacaktr.
2. Makro almnda if deyimi kullanmak:
#define ECHO(s)
if (1)
{
gets(s);
puts(s);
}
else

\
\
\
\
\

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

DER NLEMC KOMUTLARI

35 . BLM : DER NLEMC KOMUTLARI


Daha nceki derslerimizde nilemci kavramn incelemi ve nilemciye ilikin iki komutu
incelemitik. Bu komutlar #include ve #define nilemci komutlaryd. nilemciye ilikin
dier komutlar da bu desimizde ele alacaz.

Koullu derlemeye ilikin nilemci komutlar


Koullu derlemeye ilikin komutlar #if #ifdef ve #ifndef olmak zere tanedir. Koullu
derleme komutuyla karlaan nilemci, koulun salanmas durumunda belirlenmi program
blounu derleme ilemine dahil eder, koul salanmyorsa ilgili program blounu kartarak
derleme ilemine dahil etmez.

#if nilemci Komutu


Genel biimi yledir:
#if <sabit ifadesi>
...
...
#else
...
..
#endif
Sabit ifadesinin saysal deeri sfr d bir deer ise (sabit ifadesi doru olarak deerlendirilerek
) #else anahtar szcne kadar olan ksm, eer sabit ifadesinin saysal deeri 0 ise (sabit
ifadesi yanl olarak deerlendirilerek) #else ile #endif arasndaki ksm derleme ilemine
dahil edilir. rnek :
#include <stdio.h>
int main()
{
#if 1
printf("bu blm derleme ilemine sokulacak\n");
#else
printf("bu blm derleme ilemine sokulmayacak\n");
#endif
}
nilemci, program # ieren satrlardan arndrarak aadaki biimde derleme modlne
verecektir:
[stdio.h dosyasnkn ierii ]
void main()
{
printf("bu blm derleme ilemine sokulacak\n");
}
#if komutunun sandaki sabit ifadesi operatr ierebilir ancak deiken ieremez. rnein:
#define MAX
100
...
#if MAX > 50
...
#else
...
#endif
Tpk C dilinde olduu gibi nilemci komutlarnda da #else - #if merdivenlerine sk raslanr.
337

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.

#ifdef ve #ifndef nilemci Komutlar


Belli bir sembolik sabitin tanmland durumda #else anahtar szcne kadar olan ksm,
tanmlanmad durumda #else ve #endif arasndaki ksm derleme ilemine dahil edilir. Genel
biimi aadaki gibidir :
#ifdef <sembolik sabit>
...
#else
...
#endif
rnein:
#include <stdio.h>
#define SAMPLE
void main()
{
#ifdef SAMPLE
printf("SAMPLE tanmlanm");
#else
printf("SAMPLE tanmlanmam");
#endif
}
Burada SAMPLE #define ile tanmland iin #ifdef doru olarak ele alnr ve derleme
ilemine ilk printf() dahil edilir. #ifdef ile sorgulama yaplrken sembolik sabitin ne olarak
tanmlandnn bir nemi yoktur.

338

DER NLEMC KOMUTLARI

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

defined() nilemci Operatr


defined bir sembolik sabitin tanmlanp tanmlanmadn anlamak iin kullanlan bir nilemci
operatrdr. Parantez ierisindeki sembolik sabit tanmlanmsa 1 deerini tanmlanmamsa
0 deerini retir. rnein
#if defined(MAX)
...
#endif
Burada MAX tanmlanmsa defined nilemci operatr 1 deerini retecektir. Bu deer de
#if tarafndan doru olarak kabul edilecektir. Burada yaplmak istenen #ifdef ile aadaki gibi
de elde edilebilirdi:
#ifdef MAX
...
#endif

339

35

Koullu Derlemeye likin nilemci Komutlar Nerelerde Kullanlr


1. Debug Amacyla
Bir program yazarken, programn doru alp almadn test etmek amacyla birtakm
ilave kodlar yazabiliriz. Bu tr test kodlarnn biz program test ettiimiz srece almasn
anak programnz yazp bitirdikten sonra, yapacamz son derlemede, bu test kodlarnn
derleme ilemine sokulmamasn isteriz. Test amac ile yazlan kod paracklar derleme
ilemine DEBUG adl bir sembolik sabitin deerine bal olarak aadaki ekilde derleme
ilemine katlr ya da katlmaz.
#if DEBUG
...
#endif
Eer DEBUG nilemci sabitinin deeri 0 ise #if ile #endif arasndaki kod paral derlemeye
ilemine katlmaz.

2. Birden Fazla Makinede ya da letim Sisteminde alacak Programlarn


Yazlmasnda
#if defined(WINDOWS)
...
#elif defined(DOS)
...
#elif defined(OS2)
...
#endif

3. Bir Programn Farkl Derleyicilerde Derlenmesi Durumunda


#ifdef
...
#else
...
#endif

__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

DER NLEMC KOMUTLARI


dosyas iinde bir yapnn, birliin, bit alannn ya da enum trnn bildirimi yaplm ise
derleme zamannda error olulacaktr. Dolaysyla balk dosyasnn ikinci kez kaynak
koda eklenmesi engellenmelidir.
Bir balk dosyasnn kaynak koda birden fazla eklenmesi aadaki gibi engellenebilir:
/* GENERAL. H

BR BALIK DOSYASI RNE */

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

Genel nilemci Komutlar


#undef nilemci komutu
Bir sembolik sabitin ilki ile zde olmayan bir biimde ikinci kez tanmlanmas C nilemcisi
tarafndan "uyar " olarak deerlendirilir. Bu durumda ilk tanmlanann m ikinci tanmlanann
m geerli olaca tanabilir bir zellik deildir. (Derleyiciler genellikle ikinci tanmlanma
noktasna kadar ilkinin, ikinci tanmlanma noktasndan sonra ise ikincinin geerliliini kabul
ederler.)
rnein aadaki gibi bir tanmlama ilemi uyar gerektirir.
#define MAX100
...
#define MAX200
Bir sembolik sabitin ilki ile zde olarak tanmlanmasnda herhangi bir problem kmayacaktr.
Bir sembolik sabit ikinci kez tanmlanmak isteniyorsa nce eski tanmlamay ortadan kaldrmak
gerekmektedir. Bu ilem #undef nilemci komutu ile yaplr. #undef nilemci komutunun
yanna geerlilii ortadan kaldrlacak sembolik sabitin ya da makronun ismi yazlmaldr.
rnein :
#undef MAX
#define
MAX200
nce
MAX sembolik sabitinin tanmlanmas iptal edilmi, sonra 200 olarak yeniden
tanmlanmtr. #undef ile tanmlanmas kaldrlmak istenen sembolik sabit, daha nce
tanmlanm olmasa bile bu durum bir probleme yol amaz. rnein yukardaki rnekte MAX
tanmlanmam olsayd bile bir uyar ya da hataya yol amazd.

#error nilemci komutu


nilemci #error komutunu grnce bu komutu izleyen mesaj basarak derleme ilemibne son
verir. rnein:
#ifdef
#error
#endif

__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

DER NLEMC KOMUTLARI

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

You might also like