programlama ve c

Transkript

programlama ve c
PROGRAMLAMA VE C
1 . BÖLÜM : PROGRAMLAMA VE C
Yazýlým Nedir
Yazýlým (software) programlama ve programlamayla ilgili konularýn geneline verilen isimdir.
Yazýlým denince ilk olarak aklýmýza programlama dilleri, bu diller kullanýlarak yazýlmýº kaynak
programlar ve çeºitli amaçlar için oluºturulmuº dosyalar gelir.
Donaným Nedir
Donaným (hardware) : Bilgisayarýn elektronik kýsmý, yapýsýna verilen isimdir.
Yazýlýmýn Sýnýflandýrýlmasý
Yazýlýmý uygulama alanlarýna göre 5 gruba ayýrabiliriz :
1. Bilimsel ve mühendislik yazýlýmlarý (scientific & engineering software).
Bilimsel ve mühendislik konularýndaki problemlerin çözülmesinde kullanýlan programlardýr.
Bu tür programlarda veri miktarý göreli olarak düºüktür ancak matematiksel ve istatistiksel
algoritmalar yoðun olarak kullanýlabilir.Tamamen hesaplama aðýrlýklý iºlemler içerir. Bu tür
programlar aðýrlýklý olarak bilgisayarýn Merkezi ݺlem Birimini (CPU) kullanýrlar. Elektronik
devrelerin çözümünü yapan programlarý, istatistik analiz paketlerini bu tür programlara
örnek olarak verebiliriz.
2. Mesleki yazýlýmlar (Business software).
Veri tabaný aðýrlýklý yazýlýmlardýr. Genel olarak verilerin yaratýlmasý, iºlenmesi ve dosyalarda
saklanmasý ile ilgilidir. Bu tür programlara örnek olarak stok kontrol programlarý, müºteri
takip programlarý, muhasebe programlarýný verebiliriz.
3. Yapay zeka yazýlýmlarý (artificial intelligence software).
Ýnsan davranýºlarýný taklit etmeyi amaçlayan yazýlýmlardýr. Örnek olarak robot yazýlýmlarý,
satranç ya da briç oynatan programlar vs. verilebilir.
4. Görüntüsel yazýlýmlar.
Görüntüsel iºlemlerin ve algoritmalarýn çok yoðun olarak kullanýldýðý programlardýr. Örnek
olarak oyun ve animasyon yazýlýmlarýný verebiliriz. Bu yazýlýmlar aðýrlýklý olarak bilgisayarýn
grafik arabirimini kullanýrlar.
5. Sistem yazýlýmlarý (system software):
Bilgisayarýn elektronik yapýsýný yöneten yazýlýmlardýr. Derleyiciler, haberleºme programlarý,
iºletim sistemi birer sistem yazýlýmýdýr. Örneðin text editörü de bir sistem yazýlýmýdýr.
Uygulama programlarýna göre daha düºük seviyeli iºlem yaparlar.
Programlama Dillerinin Sýnýflandýrýlmasý
Programlama dillerini çeºitli açýlardan sýnýflandýrabiliriz. En sýk kullanýlan sýnýflandýrmalar:
1. Seviyelerine göre sýnýflandýrma.
2. Uygulama alanlarýna göre sýnýflandýrma.
Bilgisayar Dillerinin Seviyelerine Göre Sýnýflandýrmasý ve Seviyelerine Göre
Bilgisayar Dillerinin Geliºimi
Bir programlama dilinin seviyesi deyince o programlama dilinin insan algýsýna olan yakýnlýðýnýn
derecesini anlýyoruz. Bir programlama dili insan algýlasýna ne kadar yakýnsa o kadar yüksek
seviyeli demektir (high level). Yine bir programlama dili bilgisayarýn elektronik yapýsýna ve
çalýºma biçimine ne kadar yakýnsa o kadar düºük seviyeli (low level) demektir. Yüksek seviyeli
dillerle çalýºmak programcý açýsýndan kolaydýr. Algoritma yoktur. Bu dillerde yalnýzca nelerin
yapýlacaðý programa bildirilir ama nasýl yapýlacaðý bildirilmez. Genel olarak programlama dilinin
seviyesi yükseldikçe , o dilin öðrenilmesi ve o dilde program yazýlmasý kolaylaºýr.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
1
Buy RoboPDF
1 . BÖLÜM :
Bir bilgisayar yalnýzca kendi makine dilini doðrudan anlayabilir. Makine dili bilgisayarýn doðal
dilidir ve bilgisayarýn donanýmsal tasarýmýna baðlýdýr. Bilgisayarlarýn geliºtirilmesiyle birlikte
onlara iº yaptýrmak için kullanýlan ilk diller de makine dilleri olmuºtur. Bu yüzden makine
dillerine 1. kuºak diller de diyebiliriz.
Makine dilinin programlarda kullanýlmasýnda karºýlaºýlan iki temel problem vardýr. Makine
dilinde yazýlan kodlar doðrudan makinanýn iºlemcisine, donaným parçalarýna verilen
komutlardýr. Deðiºik bir CPU kullanýldýðýnda ya da bellek organizasyonu farklý bir ºekilde
yapýldýðýnda artýk program çalýºmayacak ve programýn tekrar yazýlmasý gerekecektir. Çünkü
makine dili yalnýzca belirli bir CPU ya da CPU serisine uygulanabilir. Makine dili taºýnabilir
(portable) deðildir. Diðer önemli bir problem ise, makine dilinde kod yazmanýn çok zahmetli
olmasýdýr.Yazmanýn çok zaman alýcý ve uðraºtýrýcý olmasýnýn yaný sýra yazýlan programý okumak
ya da algýlamak da o denli zordur. Özellikle program boyutu büyüdüðünde artýk makine dili
programlarýný geliºtirmek, daha büyütmek iyice karmaºýk bir hale gelir.
Baºlangýçta yalnýzca makine dili vardý. Bu yüzden makine dilleri 1. kuºak diller olarak da
isimlendirilir. Yazýlýmýn ve donanýmýn tarihsel geliºimi içerisinde makine dilinden, insan
algýlamasýna çok yakýn yüksek seviyeli dillere (4. kuºak diller) kadar uzanan bir süreç söz
konusudur. Bu tarihsel süreci ana hatlarýyla inceleyelim :
1950 li yýllarýn hemen baºlarýnda makine dili kullanýmýn getirdiði problemleri ortadan
kaldýrmaya yönelik çalýºmalar yoðunlaºtý. Bu yýllarda makine dilleri bilgisayarýn çok sýnýrlý olan
belleðine yükleniyor ve programlar böyle çalýºtýrýlýyordu. Ýlk önce makine dilinin algýlanma ve
anlaºýlma zorluðunu kýsmen de olsa ortadan kaldýran bir adým atýldý. Sembolik makine dilleri
geliºtirildi. Sembolik makine dilleri (Assembly languages) yalnýzca 1 ve 0 dan oluºan makine
dilleri yerine Ýngilizce bazý kýsaltma sözcüklerden oluºuyordu. Sembolik makine dillerinin
kullanýmý kýsa sürede yaygýnlaºtý. Ancak sembolik makine dillerinin makine dillerine göre çok
önemli bir dezavantajý söz konusuydu. Bu dillerde yazýlan programlar makine dilinde yazýlan
programlar gibi bilgisayarýn belleðine yükleniyor ancak programýn çalýºtýrýlma aºamasýnda
yorumlayýcý (interpreter) bir program yardýmýyla sembolik dilin komutlarý, bilgisayar tarafýndan
komut komut makine diline çevriliyor ve oluºan makine kodu çalýºtýrýlýyordu. Yani bilgisayar,
programý çalýºma aºamasýnda önce yorumluyarak makine diline çeviriyor daha sonra makine
diline çevrilmiº komutlarý icra ediyordu. Bu ºekilde çalýºtýrýlan programlarýn hýzý neredeyse 30
kat yavaºlýyordu.
Bu dönemde özellikle iki yorumlayýcý program öne çýkmýºtý: John Mauchly nin UNIVAC 1 için
yazdýðý yorumlayýcý (1950) ve John Backus tarafýndan 1953 yýlýnda IBM 701 için yazýlan
"Speedcoding" yorumlama sistemi. Bu tür yorumlayýcýlar makine koduna göre çok yavaº
çalýºsalar da programcýlarýn verimlerini artýrýyorlardý. Ama özellikle eski makine dili
programcýlarý yorumlayýcýlarýn çok yavaº olduklarýný, yalnýzca makine dilinde yazýlanlarýn gerçek
program deneceðini söylüyorlardý.
Bu sorunun da üstesinden gelindi. O zamanlar için çok parlak kabul edilebilecek fikir ºuydu:
Her defasýnda yazýlan kod, kodun çalýºtýrýlmasý sýrasýnda makine diline çevireceðine,
geliºtirilecek bir baºka program sembolik dilinde yazýlan kodu bir kez makine diline çevirsin ve
artýk program ne zaman çalýºtýrýlmak istense, bilgisayar yorumlama olmaksýzýn yalnýzca
makine kodunu çalýºtýrsýn. Bu fikiri geliºtiren Grace Hopper isimli bir bayandý. Grace Hopper'ýn
buluºuna "compiler" derleyici ismi verildi. (Grace Hopper ayný zamanda Cobol dilini geliºtiren
ekipten biridir, bug(böcek) sözcüðünü ilk olarak Grace Hopper kullanmýºtýr.) Artýk programcýlar
sembolik sözcüklerden oluºan Assembly programlarýný kullanýyor. Yazdýklarý programlar
derleyici tarafýndan makine koduna dönüºtürülüyor ve makine kodu eski hýzýndan birºey
kaybetmeksizin tam hýzla çalýºýyordu. Assembly diller 2. kuºak diller olarak tarihte yerini aldý.
Assembly dillerinin kullanýlmaya baºlamasýyla bilgisayar kullanýmý hýzla arttý. Ancak en basit
iºlemlerin bile bilgisayara yaptýrýlmasý için bir çok komut gerekmesi, programlama prosesini
daha hýzlý bir hale getirmek için arayýºlarý baºlatmýº, bunun sonucunda da daha yüksek seviyeli
programlama dilleri geliºtirilmeye baºlanmýºtýr.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
2
Buy RoboPDF
PROGRAMLAMA VE C
Tarihsel süreç içinde Assembly dillerinden daha sonra geliºtirilmiº ve daha yüksek seviyeli diller
3. kuºak diller sayýlmaktadýr. Bu dillerin hepsi algoritmik dillerdir. Bugüne kadar geliºtirilmiº
olan yüzlerce yüksek seviyeli programlama dilinden yalnýzca pek azý bugüne kadar varlýklarýný
sürdürebilmiºtir:
FORTRAN dili (FORmula TRANslator) kompleks matematiksel hesaplamalar gerektiren
mühendislik ve bilimsel uygulamalarda kullanýlmak üzere 1954 - 1957 yýllarý arasýnda IBM
firmasý için John Backus tarafýndan geliºtirilmiºtir. FORTRAN dili, yoðun matematik
hesaplamalarýn gerektiði bilimsel uygulamalarda halen yaygýn olarak kullanýlmaktadýr.
FORTRAN dilinin FORTRAN IV ve FORTRAN 77 olmak üzere iki önemli versiyonu bulunmaktadýr.
Doksanlý yýllarýn baºlarýnda FORTRAN - 90 isimli bir versiyon için ISO ve ANSI standartlarý
kabul edilmiºtir. FORTRAN dili 3. seviye dillerin en eskisi kabul edilmektedir.
COBOL (COmmon Business Oriented Language) 1959 yýlýnda, Amerika'daki bilgisayar
üreticileri, özel sektör ve devlet sektöründeki bilgisayar kullanýcýlarýndan oluºan bir grup
tarafýndan geliºtirilmiºtir. COBOL'un geliºtirilme amacý veri yönetimi ve iºlemenin gerektiði
ticari uygulamalarda kullanýlacak taºýnabilir bir programlama dili kullanmaktýr. COBOL dili de
halen yaygýn olarak kullanýlmaktadýr.
ALGOL (The ALGOritmick Language) 1958 yýlýnda Avrupa'da bir konsorsiyum tarafýndan
geliºtirilmeye baºlanmýºtýr. IBM Firmasý FORTRAN dilini kendi donanýmlarýnda kullanýlacak ortak
programlama dili olarak benimsediðinden, Avrupa'lýlar da alternatif bir dil geliºtirmek
istemiºlerdi. ALGOL dilinde geliºtirilen bir çok prensip modern programlama dillerinin hepsinde
kullanýlmaktadýr.
60'lý yýllarýn baºlarýnda programlama dilleri üzerinde yapýlan çalýºmalar yapýsal programlama
kavramýný gündeme getirmiºtir. Bu dillerden bazýlarýna kýsaca göz atalým:
PASCAL dili 1971 yýlýnda akademik çevrelere yapýsal programlama kavramýný tanýtmak için
Profesör Niclaus Wirth tarafýndan geliºtirilmiº (Dilin yaratýcýsý, dile matematikçi ve filozof Blaise
Pascal'ýn ismini vermiºtir.) ve bu dil kýsa zaman içinde üniversitelerde kullanýlan programlama
dili haline gelmiºtir.
Pascal dilinin ticari ve endüstriyel uygulamalarý desteklemek için sahip olmasý gereken bir
takým özelliklerden yoksun olmasý bu dilin bu uygulamalarda fazla kullanýlmamasýna yol
açmýºtýr. Modula ve Modula-2 dilleri Pascal dili baz alýnarak geliºtirilmiºtir.
BASIC dili 1960'lý yýllarýn ortalarýnda John Kemeney ve Thomas Kurtz tarafýndan geliºtirilmiºtir.
Her ne kadar BASIC isminin "Beginner's All_purpose Symbolic Instruction Code" sözcüklerinin
baº harflerinden oluºturulduðu söylense de, bu sözcüklerin daha sonradan uydurulduðu açýktýr.
Yüksek seviyeli dillerin en eski ve en basit olanlarýndan biridir.Tüm basitliðine karºýn, bir çok
ticari uygulamada kullanýlmýºtýr. BASIC dili de ANSI tarafýndan standartlaºtýrýlmýºtýr. Ancak
BASIC dilinin ilave özellikler içeren bir sürü versiyonu söz konusudur. Örneðin Microsoft
firmasýnýn çýkarttýðý Visual Basic diline Nesne Yönelimli Programlamaya iliºkin birçok özellik
eklenmiºtir. Ayrýca BASIC dilinin bazý versiyonlarý uygulama programlarýnda (Örneðin MS Excel
ve MS Word'de) kullanýcýnýn özelleºtirme ve otomatikleºtirme amacýyla yazacaðý makrolarýn
yazýlmasýnda kullanýlan programlama dili olarak da genel kabul görmüºtür.
ADA dili ise Amerikan Savunma Departmaný (Department of Defence -DoD) desteði ile 70 li
yýllar ve 80'li yýllarýn baºlarýnda geliºtirilmiºtir. Dod dünyadaki en büyük bilgisayar
kullanýcýlarýndan biridir. Bu kurum farklý yazýlýmsal gereksinimleri karºýlamak için çok sayýda
farklý programlama dili kullanýyordu ve tüm gereksinmelerini karºýlayacak bir dil arayýºýna girdi.
Dilin tasarlanmasý amacýyla uluslararasý bir yarýºma düzenledi. Yarýºmayý kazanan ºirket (CIIHoneywell Bull of France) Pascal dilini baz olarak alan çalýºmalar sonucunda Ada dilini
geliºtirdi. Ada dilinin dökümanlarý 1983 yýlýnda yayýmlanmýºtýr.(Ada ismi, ºair Lord Byron'un kýzý
olan Lady Ada Lovelace'ýn isminden alýntýdýr. Ada Lovelace delikli kartlarý hesap makinalarýnda
ilk olarak kullanýlan Charles Babbage'in yardýmcýsýydý. Charles Babbage hayatý boyunca "Fark
makinasý" (Difference Engine) ve "Analitik Makine" (Analytical Engine) isimli makinalarýn yapýmý
üzerinde çalýºtý ama bu projelerini gerçekleºtiremeden öldü. Yine de geliºtirdiði tasarýmlar
modern bilgisayarlarýn atasý kabul edilmektedir. Ada Lovelace Charles Babbage'ýn makinasý için
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
3
Buy RoboPDF
1 . BÖLÜM :
delikli kartlarý ve kullanýlacak algoritmalarý hazýrlýyordu. Bu bayanýn 1800'lü yýllarýn baºýnda ilk
bilgisayar programýný yazdýðý kabul edilmektedir.) Ada dili genel amaçlý bir dildir, ticari
uygulamalardan roketlerin yönlendirilmesine kadar birçok farklý alanda kullanýlmaktdýr. Dilin
önemli özelliklerinden bir tanesi gerçek zaman uygulamalarýna (real-time applications /
embedded systems) destek vermesidir. Baºka bir özelliði de yüksek modülaritesi nedeniyle
büyük programlarýn yazýmýný kolaylaºtýrmasýdýr. Ancak büyük ve karmaºýk derleyicilere ihtiyaç
duymasý, C, Modula-2 ve C++ dillerine karºý rekabetini zorlaºtýrmýºtýr.
Çok yüksek seviyeli ve genellikle algoritmik yapý içermeyen programlarýn görsel bir ortamda
yazýldýðý diller ise 4. kuºak diller olarak isimlendirilirler. Genellikle 4GL olarak kýsaltýlýrlar.
(fourth generation language). Ýnsan algýsýna en yakýn dillerdir. RPG dili 4. kuºak dillerin ilki
olarak kabul edilebilir.Özellikle küçük IBM makinalarýnýn kullanýcýlarý olan ºirketlerin, rapor
üretimi için basit bir dil istemeleri üzerine IBM firmasý tarafýndan geliºtirilmiºtir.
Programlama dillerini seviyelerine göre 5 ana gruba ayýrabiliriz:
1. Çok yüksek seviyeli diller ya da görsel diller (visual languages):
Access, Foxpro, Paradox, Xbase, Visual Basic, Oracle Forms.
2. Yüksek seviyeli diller (Bunlara algoritmik diller de denir):
Fortran, Pascal, Basic, Cobol.
3. Orta seviyeli programlama dilleri:
Ada, C. Orta seviyeli diller daha az kayýpla makine diline çevrilebildiðinden daha hýzlý çalýºýr.
4. Alçak seviyeli programlama dilleri:
Sembolik makine dili (Assembly language).
5. Makine dili:
En aºaðý seviyeli programlama dili. (Saf makine dili tamamen 1 ve 0 lardan oluºuyor.)
Uygulama Alanlarýna Göre Sýnýflandýrma
1. Bilimsel ve mühendislik uygulama dilleri:
Pascal, C (C programlama dili üniversitelerdeki akademik çalýºmalarda da yoðun olarak
kullanýlýyor.), FORTRAN
2. Veri tabaný dilleri:
XBASE, (Foxpro, Dbase, CA-Clipper), Oracle Forms, Visual Foxpro.
3. Genel amaçlý 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.
Günümüzde sistem yazýlýmlarýn neredeyse tamamýnýn C dili ile yazýldýðýný söyleyebiliriz.
Örnek vermek gerekirse UNIX iºletim sisteminin % 80'i C dili ile geri kalaný ise sembolik
makine dili ile yazýlmýºtýr. Bu iºletim sistemi ilk olarak BELL labaratuarlarýnda
oluºturulmuºtur. Kaynak kodlarý gizli tutulmamýº, böylece çeºitli kollardan geliºtirilmesi
mümkün olmuºtur. Daha sonra geliºtirilen UNIX bazlý iºletim sistemi uygulamalarýna deðiºik
isimler verilmiºtir.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
4
Buy RoboPDF
PROGRAMLAMA VE C
C bilimsel ve mühendislik alanlarýna kullanýlabilen genel amaçlý bir sistem programlama dilidir.
Programlama Dillerinin Deðerleme Ölçütleri
Kaynaklar ºu an halen kullanýmda olan yaklaºýk 1000 - 1500 programlama dilinin varlýðýndan
söz ediyor. Neden bu kadar fazla programlama dili var? Bu kadar fazla programlama dili
olmasýna karºýn neden halen yeni programlama dilleri tasarlanýyor? Bir programlama dilini
diðerine ya da diðerlerine göre daha farklý kýlan özellikler neler olabilir? Bir programlama dilini
tanýmlamak istesek hangi sýfatlarý kullanabiliriz? Programlama dilleri hakkýndaki bu sorulara
yanýt verebilmemiz için elimizde deðerlendirme yapmamýza olanak saðlayacak ölçütler
olmalýdýr. Bu ölçütleri kýsaca inceleyelim:
Verimlilik (efficiency)
Bu özelliðe programýn hýzlý çalýºma özelliði diyebiliriz. Programýn çalýºma hýzý pek çok faktöre
baðlýdýr. Algoritmanýn da hýz üzerinde etkisi vardýr. Çalýºmanýn yapýldýðý bilgisayarýn da doðal
olarak hýz üzerinde etkisi vardýr. Verimliliði bir programlama dilinde yazýlmýº bir programýn hýzlý
çalýºmasý ile ilgili bir kavram olarak düºünebiliriz. Bu açýdan bakýldýðýnda C verimli bir dildir.
Veri türleri ve yapýlarý (data types and structures)
Çeºitli veri türlerini (tamsayý, gerçek sayý, karakter...) ve veri yapýlarýný (diziler, yapýlar vs.)
destekleme yeteneðidir. Veri yapýlarý, veri türlerinin oluºturduðu mantýksal birliklerdir. Örneðin
C ve Pascal dilleri veri yapýlarý bakýmýndan zengin dillerdir.
Alt programlama yeteneði (Modularity)
Bir bütün olarak çözülmesi zor olan problemlerin parçalara ayrýlmasý ve bu parçalarýn ayrý ayrý
çözümlenmesinden sonra parçalar arasýndaki koordinasyonun saðlanmasý programada sýk
baºvurulan bir yöntemdir. Bir programlama dili buna olanak saðlayacak araçlara sahipse alp
programlama yeteneði vardýr diyebilirriz. Alt programlama yeteneði bir programlama dilinin,
programý parçalar halinde yazmayý desteklemesi anlamýna gelir. (C modülaritesi çok yüksek bir
dildir)
Alt programlama Yapýsal Programlama tekniði'nin de ayrýlmaz bir parçasýdýr. Alt
programlamanýn getirdiði bazý önemli avantajlar vardýr. Alt programlar kodu küçültür. Çok
tekrarlanan iºlemlerin alt programlar kullanýlarak yazýlmasý çalýºabilir programýn kodunu
küçültür. Çünkü alt programlar yalnýzca bir kere çalýºabilir kod içine yazýlýrlar. Ama program
kodu alt programýn olduðu yere atlatýlarak bu bölgenin defalarca çalýºtýrýlmasý saðlanabilir.
Alt programlama algýlamayý kolaylaºtýrýr, okunabilirliði artýrýr. Alt programlama kaynak kodun
test edilebilirliðini artýrýr. Kaynak kodun daha kolay güncelleºtirilmesi ve yeniden kullanýlabilme
olanaðýný artýrýr. Alt programlamanýn en önemli avantajlarýndan biri de genel amaçlý kodlar
yazarak bu yazýlan kodlarý birden fazla projede kullanabilmektir. (reusability)
C alt programlama yeteneði yüksek bir dildir. C'de alt programlara fonksiyon denir.
Fonksiyonlar C Dili'nin yapýtaºlarýdýr.
Yapýsallýk (structural programming support)
Yapýsallýk bir programlama tekniðidir. Bugün artýk hemen hemen bütün programlama dilleri
yapýsal programlamayý az çok destekleyecek bir ºekilde geliºtirilmiºtir. Yapýsal Programlama
fikri 1960'lý yýllarda geliºtirilmiºtir. Yapýsal programlama tekniði dört ana ilke üzerine
kurulmuºtur :
1. Böl ve üstesinden gel (divide and conquer)
Yapýsal programlama tekniðinde, tek bir bütün olarak çözüm getirmek zor olan programlar,
daha küçük ve üstesinden daha kolay gelinebilecek parçalara bölünürler. Bu parçalar
fonksiyon, prosedür, subroutine, alt program vs. olarak isimlendiriler. Alt program yapýsýnýn
getirdiði avantajlar modularite konusunda yukarýda açýklanmýºtýr.
2. Veri gizleme (Data hiding)
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
5
Buy RoboPDF
1 . BÖLÜM :
Yapýsal programlama tekniðinde, programýn diðer parçalarýndan ulaºýlamayan, yalnýzca belli
bir faaliyet alaný olan, yani kodun yalnýzca belli bir kýsmýnda faaliyet gösterecek deðiºkenler
tanýmlanabilir. Bu tür deðiºkenler genel olarak "yerel deðiºkenler" (local variables) olarak
isimlendirilirler. Deðiºkenlerin faaliyet alanlarýnýn kýsýtlanabilmesi hata yapma riskini
azalttýðý gibi, programlarýn daha kolay deðiºtirilebilmesini ve program parçalarýnýn baºka
programlarda tekrar kullanabilmesini de saðlar. Alt programlarýn, ve daha geniº ºekliyle
modüllerin, bir iºi nasýl yaptýðý bilgisi, o alt programýn ya da modülün kullanýcýsýndan
gizlenir. Kullanýcý için (client) alt programýn ya da modülün iºi nasýl yaptýðý deðil, ne iº
yaptýðý önemlidir.
3. Tek giriº ve Tek çýkýº (single entry single exit)
Yapýsal programlama tekniðini destekleyen dillerde her bir altprogram parçasýna girmek için
tek bir giriº ve tek bir çýkýº mekanizmasý vardýr. Bu mekanizma programýn yukarýdan aºaðý
olarak akýºý ile uyum halindedir. Program parçalarýna ancak tek bir noktadan girilebilir.
4. Döngüler ve diðer kontrol yapýlarý.
Artýk hemen hemen kullanýmda olan bütün programlama dilleri az ya da çok Yapýsal
Programlama tekniðini desteklemektedir. Zira bu teknik 60'lý yýllar için devrim
niteliðindeydi.
Esneklik (flexibility)
Esneklik programlama dilinin programcýyý kýsýtlamamasý anlamýna gelir.Esnek dillerde birçok
iºlem, hata yapma riski artmasýna karºýn raðmen kullanýcý için serbest býrakýlmýºtýr. Programcý
bu serbestlikten ancak yetkin bir programcýysa bir fayda saðlayabilir. Fakat programcý
deneyimsiz ise bu esneklikten zarar görebilir.
Öðrenme ve öðretme kolaylýðý (pedagogy)
Her programlama dilini öðrenmenin ve öðrenilen programlama dilinde uygulama
geliºtirebilmenin
zorluðu ayný deðildir. Genel olarak programlama dillerinin seviyesi
yükseldikçe, öðrenme ve bu programlama dilini baºkalarýna öðretme kolaylaºýr, öðrenme için
harcanacak çaba ve zaman azalýr. Bugün yaygýn olarak kullanýlan yüksek seviyeli programlý
dillerinin bu derece popüler olmasýnýn önemli bir nedeni de bu dillerin çok kolay
öðrenilebilmesidir. Ne yazýk ki C öðrenimi zor ve zahmetli bir dildir.
Genellik (generality)
Programlama dillerinin çok çeºitli uygulamalarda etkin olarak kullanýlabilmesidir. Örneðin
COBOL mühendislik uygulamalarýnda tercih edilmez zaten ticari uygulamalar için
tasarlanmýºtýr, Clipper ya da FOXPRO veri tabaný dilleridir. Oysa PASCAL, BASIC daha genel
amaçlý dillerdir. C dili de bir sistem programlama dili olarak doðmasýna karºýn, güçlü yapýsýndan
dolayý, kýsa bir süre içinde, genel amaçlý bir dil haline gelmiºtir.
Giriº / Çýkýº (input / output, I / O facility) kolaylýðý
Sýralý, indeksli ve rasgele dosyalara eriºme, veritabaný kayýtlarýný geri alma, güncelleºtirme ve
sorgulama yeteneðidir. Veritabaný programlama dillerinin (DBASE, PARADOX vs.) bu
yetenekleri diðerlerinden daha üstündür ve bu dillerin en tipik özelliklerini oluºturur. Fakat C
giriº çýkýº kolaylýðý kuvvetli olmayan bir dildir. C'de veri tabanlarýnýn yönetimi için özel
kütüphanelerin kullanýlmasý gerekir.
Okunabilirlik (readability)
Okunabilirlik, kaynak kodun çabuk ve iyi bir biçimde algýlanabilmesi anlamýna gelen bir
terimdir. Kaynak kodun okunabilirliðinde sorumluluk büyük ölçüde programý yazan kiºidedir.
Fakat yine verimlilik de olduðu gibi dillerin bir kýsmýnda okunabilirliði güçlendiren yapý ve
mekanizmalar bulunduðu için bu özellik bir ölçüde dilin tasarýmýna da baðlýdýr. En iyi program
kodu, sanýldýðý gibi "en zekice yazýlmýº fakat kimsenin anlayamayacaðý" kod deðildir.
Birçok durumda iyi programcýlar okunabilirliði hiçbirºeye feda etmek istemezler. Çünkü
okunabilir bir program kolay algýlanabilme özelliðinden dolayý seneler sonra bile
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
6
Buy RoboPDF
PROGRAMLAMA VE C
güncelleºtirmeye olanak saðlar. Birçok kiºinin ortak kodlar üzerinde çalýºtýðý geniº kapsamlý
projelerde okunabilirlik daha da önem kazanmaktadýr.
C de okunabilirlik en fazla vurgulanan kavramlardan biridir. Biz de kursumuz boyunca
okunabilirlik konusuna sýk sýk deðineceðiz ve C programlarýnýn okunabilirliði konusunda bazý
temel prensipleri benimseyeceðiz.
Taºýnabilirlik (portability)
Bir sistem için yazýlmýº olan kaynak kodun baºka bir sisteme götürüldüðünde, hatasýz bir
biçimde derlenerek, doðru bir ºekilde çalýºtýrýlabilmesi demektir.
Taºýnabilirlik standardizasyon anlamýna da gelir. Programlama dilleri (ISO International
Standard Organization) ve ANSI (American National Standard Institute) tarafýndan standardize
edilirler. 1989 yýlýnda standartlaºtýrma çalýºmalarý biten C Dili, diðer programlama dillerinden
daha taºýnabilir bir programlama dilidir.
Nesne Yönelimlilik (object orientation)
Nesne yönelimlilik de bir programlama tekniðidir.
Yapýsal programlama Tekniði 1960 yýlarýnda gündeme
Programlama Tekniði 1980'li yýllarda popüler olmuºtur.
gelmiºken,
Nesne
Yönelimli
Bu teknik kaynak kodlarýn çok büyümesi sonucunda ortaya çýkan gereksinim yüzünden
geliºtirilmiºtir. C dilinin geliºtirildiði yýllarda, akla gelebilecek en büyük programlar ancak onbin
satýrlar mertebesindeydi, ancak kullanýcýlarýn bilgisayar programlarýndan beklentilerinin artmasý
ve grafik arayüzünün artýk etkin olarak kullanýlmasýyla, bilgisayar programlarýnýn boyutu çok
büyümüº, yüzbin satýrlarla hatta milyon satýrlarla ölçülebilir hale gelmiºtir.
Nesne yönelimli programlama Tekniði, herºeyden önce büyük programlarýn yazýlmasý için
tasarlanmýº bir tekniktir. C dilinin yaratýldýðý yýllarda böyle bir tekniðin ortaya çýkmasý söz
konusu deðildi, çünkü zaten programlar bugünkü ölçülere göre çok küçüktü.
Nesne yönelimli programlama Tekniðinin yaygýn olarak kullanýlmaya baºlanmasýyla birlikte bir
çok programlama dilinin bünyesine bu tekniðin uygulanmasýný kolaylaºtýrýcý araçlar eklenek,
yeni versiyonlarý oluºturulmuºtur. Örneðin C'nin
nesne yönelimli programlama tekniðini
uygulayabilmek için Bjarne Stroustrup tarafýndan geliºtirilmiº haline C++ denmektedir. C++
dili C dili baz olarak alýnýp, geliºtirilmiº yeni bir programlama dilidir. C++ dilini iyi öðrenebilmek
için öncelikle C dilini çok iyi öðrenmek gerekir.
Pascal diline eklemeler yapýlarak Delphi dili, Cobol dilinden yenilemesiyle OOCobol, Ada dilinin
yenilenmesiyle ise ADA 95 dilleri geliºtirilmiºtir.
Bazý programlama dilleri ise doðrudan N.Y.P.T'ni destekleyecek ºekilde tasarlanarak
geliºtirilmiºtir. Örneðin JAVA dili C++ dilinin basitleºtirilmiº biçimi olup daha çok Internet
uygulamalarýnda kullanýlmaktadýr. Baºka bir örnek olarak da Eiffel dili verilebilir.
C Nasýl bir Programlama Dilidir?
Bütün bunlardan sonra yukarýda açýkladýðýmýz kavramlarý da kullanarak C dilini aºaðýdaki
ºekilde tanýmlayabiliriz :
C orta seviyeli bir programlama dilidir. Yapýsal diðer programlama dillerine göre C dilinin
seviyesi daha düºüktür. C dili hem yüksek seviyeli dillerin, kontrol deyimleri, veri yapýlarý gibi
avantajlarýný bünyesinde barýndýrýyor, ayný zamanda bitsel operatörler gibi makine kodu
deyimlerini yansýtan operatörlerlere sahip. Yani hem makinaya yakýn hem de insan
algýlamasýna. Zaten çok tercih edilmesinin en önemli nedenlerinden biri de bu.
C bir sistem programlama dilidir. Sistem Programlama ne anlama geliyor? Donanýmýn
yönetilmesi, kontrolu ve denetimi için yazýlan, doðrudan donanýmla iliºkiye giren programlara
sistem programý diyoruz. Örneðin, iºletim sistemleri, derleyiciler, yorumlayýcýlar, aygýt
sürücüleri (device drivers), bilgisayarlarýn iletiºimine iliºkin programlar, otomasyon
programlarý, sistem programlarýdýr. Diðer uygulama programlarýna destek veren yazýlýmlar da
çoðunlukla sistem programlarý olarak ele alýnýrlar.
C'den önce sistem programlarý assembly dillerle yazýlýyordu.Sistem programlarýnýn
yazýlmasýnda hemen hemen alternatifsiz olduðunu söyleyebiliriz. Bugün cep telefonlarýndan,
uçaklara kadar her yerde C kodlarý çalýºmaktadýr. Örneðin Boeing uçaklarýnda 100.000 satýrdan
fazla C kodu çalýºtýðý bilinmektedir.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
7
Buy RoboPDF
1 . BÖLÜM :
C algoritmik bir dildir. C'de program yazmak için yalnýzca dilin sentaks ve sementik yapýsýný
bilmek yetmez genel bir algoritma bilgisi de gerekir.
C diðer dillerle kýyaslandýðýnda taºýnabilirliði çok yüksek olan bir dildir. Çünkü 1989 yýlýndan bu
yana genel kabul görmüº standartlara sahiptir. Ýfade gücü yüksek , okunabilirlik özelliði güçlü
bir dildir.
C çok esnektir. Diðer dillerde olduðu gibi programcýya kýsýtlamalar getirmez.
Güçlü bir dildir. Çok iyi bir biçimde tasarlanmýºtýr. C'ye iliºkin operatörlerin ve yapýlarýn bir çoðu
daha sonra baºka programlama dilleri tarafýndan da benimsenmiºtir.
C verimli bir dildir. Seviyesinden dolayý hýzlý çalýºýr. Verimlilik konusunda assembly diller ile
rekabet edebilir.
C doðal bir dildir. C bilgisayar sisteminin biçimiyle uyum içindedir.
C küçük bir dildir. Yeni sistemler için derleyici yazmak zor deðildir.
C'nin eðitimi diðer bilgisayar dillerine göre daha zordur.
C Programlama Dili'nin Tarihi
C dilinin tarihini incelediðimizde C dilinin UNIX iºletim sisteminin bir yan ürünü olarak
doðduðunu söyleyebiliriz. UNIX iºletim sisteminin orjinal ilk versiyonunu
Bell
Labaratuarlarý'nda çalýºan Ken Thompson tek baºýna yazmýºtý ve UNIX'in bu ilk versiyonu DEC
PDP-7 isimli bilgisayarda çalýºýyordu. DEC PDP-7 ilk mini bilgisayarlardan biriydi ve ana belleði
yalnýzca 16 K (16 MB deðil!). Yýllardan 1969'du.
Zamanýnýn diðer iºletim sistemleri gibi UNIX de assembly dilinde yazýlmýºtý. Assembly dilinde
yazýlan programlarý geliºtirmek çok zor ve zahmetli olduðundan, Thompson UNIX iºletim
sistemini daha geliºtirebilmek için, makine dilinden daha yüksek seviyeli bir dile gereksinim
duydu. Bu amaçla küçük bir programlama dili tasarladý. Kendi dilini tasarlarken Thompson,
1960 yýllarýnýn ortalarýnda Martin Richards tarafýndan geliºtirilmiº BCPL dilinden yola çýktý.
(BCPL = Business Common Programming Language. Bu dil de CPL = Cambridge Programming
Language'den türetilmiºtir. CPL'in kaynaðý da tüm zamanlarýn en eski ve en etkili dillerinden
biri olan ALGOL 60'dýr. ALGOL 60 Pascal, ADA, Modula2 dillerinin de atasýdýr, bu dillere bu
yüzden C dilinin kuzenleri de diyebiliriz. Aºaðýda ALGOL 60 dil ailesi görülmektedir:
Algol 60
Algol 68
Algol W
Simula 67
BCPL
C
Pascal
C++
Modula-2
Ada
Java
Delphi
Oberon
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
8
Buy RoboPDF
PROGRAMLAMA VE C
Thompson geliºtirdiði bu dilin ismini B koydu. Dennis Ritchie UNIX projesine katýlýnca B dilinde
programlamaya baºladý. B dili daha da geliºtirilmiºti ve artýk daha yeni teknoloji olan PDP-11
bilgisayarlarda çalýºýyordu. Thompson UNIX iºletim sisteminin bir kýsmýný B dilinde tekrar yazdý.
Artýk 1971 yýlýna gelindiðinde B dilinin PDP-11 bilgisayarlar ve UNIX iºletim sisteminin
geliºtirilmesi için çok uygun olmadýðý iyice ortaya çýktý. Bu yüzden Ritchie B programlama
dilinin daha ileri bir versiyonunu geliºtirmeye baºladý. Oluºturduðu dili ilk önce NB (new B)
olarak isimlendirdi. Ama geliºtirdiði dil B dilinden iyice kopmaya ve ayrý bir karakter
göstermeye baºlayýnca dilin ismini de C olarak deðiºtirdi. 1973 yýlýnda UNIX iºletim sisteminin
büyük bir kýsmý C dili ile tekrar yazýldý.
Ken Thompson ve Dennis Ritchie Unix
ݺletim Sistemi üzerinde çalýºýrken (Yýl:
1972)
C'nin evrimi ve geliºmesi 70'li yýllarda
da devam etti. Geniº kitleler tarafýndan
tanýnmasý ve kullanýlmaya baºlamasý
1978 yýlýnda Dennis Ritchie ve Brian
Kernighan tarafýndan yazýlan "The C
Programming Language" kitabý ile
olmuºtur. Bu kitap ayný zamanda
yazýlým konusunda yazýlan en iyi
eserlerden
biri
olarak
deðerlendirilmektedir.
C'nin
standardize edilmesine kadar olan dönemde bu kitap çoðunluðun benimsediði genel kabul
gören gayriresmi bir standard vazifesi de görmüºtür.
1970'li yýllarda C programcýlarýnýn sayýsý azdý ve bunlardan çoðu
UNIX kullanýcýlarýydý. Ama artýk 80'li yýllar gelince C nin
kullanýmý UNIX sýnýrlarýný aºtý, ve farklý iºletim sistemlerinde
çalýºan derleyiciler piyasaya çýktý, C dili de IBM PC'lerde yoðun
olarak kullanýlmaya baºladý.
C'nin artan popülaritesi problemleri de beraberinde getirdi.
Derleyici yazan kiºiler, referans olarak Ritchie ve Kernighan'ýn
kitabýný esas alýyorlardý ama söz konusu kitapta bazý noktalar
çok da detaylý bir biçime açýklanmamýºtý. Özellikle hangi
noktalarýn C dilinin bir özelliði hangi noktalarýn ise UNIX iºletim
sisteminin bir özelliði olduðu o kadar açýk olmadýðý için bir takým
karýºýklýklar ortaya çýkýyordu. Böylece derleyici yazanlarýn
ürünlerinde de farklýlýklar ortaya çýkýyordu. Ayrýca kitabýn
yayýnlanmasýndan sonra da dilde bir takým geliºtirmeler,
iyileºtirmeler, deðiºiklikler yapýldýðý için, birbirinden çok farklý
derleyiciler piyasada kullanýlmaya baºlanmýºtý.
Artýk C dilinin standardizasyonu neredeyse zorunlu bir hale gelmiºti! C'nin standardizasyon
çalýºmalarý 1983 yýlýnda ANSI (American National Standards Institute ) gözetiminde ve
desteðinde baºladý. Yapýlan birçok deðiºiklikten sonra standart çalýºmalarý 1988 yýlýnda sona
erdi ve 1989 yýlýnýn Aralýk ayýnda ANSI C standardý Jim Brodie baºkanlðýnda X3.159 - 1989
numarasýyla resmi olarak onaylandý. 1990 yýlýnda ise ISO/IEC 9899 - 1990 numarasýyla ISO
(International
Standards
Organization)
tarafýndan
standardizasyonu
kabul
edildi.
Standardizasyonu tamamlandýktan sonra C yüksek oranda taºýnabilir bir sistem programlama
dili haline gelmiºtir. Günümüzde de sistem programlarýnýn (derleyiciler, editörler, iºletim
sistemleri) çoðu C dili ile yazýlmaktadýr.
Fotoðraflar
Dennis M. Ritchie
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
9
Buy RoboPDF
1 . BÖLÜM :
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
10
Buy RoboPDF
SAYI SÝSTEMLERÝ
2 . BÖLÜM : SAYI SÝSTEMLERÝ
Günlük hayatta 10’luk sayý sistemini kullanýyoruz. 10 luk sistemde bir sayýnýn deðeri aslýnda her bir basamak
deðerinin 10 sayýsýnýn ilgili kuvvetiyle çarpýmlarýnýn toplanmasýyla elde edilir.
Örneðin 1273 = (3 * 1) + (7 * 10 ) + (2 * 100) + (1 * 1000)
Ancak bilgisayar sistemlerinde bütün bilgiler ikilik sistemde(binary system) ifade edilir.
Genel olarak sayý sistemi kaçlýksa o sayý sisteminde o kadar sembol bulunur.
Örneðin 10’luk sistemde 10 adet sembol vardýr ve bu semboller 0, 1, 2, 3, 4, 5, 6, 7, 8, 9’dur.
Ayný ºekilde ikilik sayý sisteminde yalnýzca iki adet sembol bulunur. Yani yalnýzca 0 ve 1.
Bir sayýyý baºka bir sayý sisteminde ifade etmek o sayýnýn deðerini deðiºtirmez. Yalnýzca sayýnýn gösteriliº
biçimi deðiºir. Örneðin onluk sayý sisteminde sayýsal deðeri 32 olan büyüklüðü çeºitli farklý sayý sistemlerinde
farklý biçimlerde gösterebiliriz ama sayýnýn büyüklüðünü deðiºtirmiº olmayýz.
Ýkilik sistemde her bir basamaða 1 bit denir. Bit kelimesi binary digit sözcüklerinden
türetilmiºtir.
Örneðin 1011 sayýsý 4 bittir. (Ya da 4 bit uzunluðundadýr).
11011001 sayýsý 8 bittir.
8 bitlik bir büyüklük bir byte olarak isimlendirilir.
1 kilobyte 1K = 1024 byte dýr. (yani 2 byte)
20
1 mega byte 1 MB = 1024 Kilo byte dýr. (yani 2 byte)
30
1 gigabyte 1 GB = 1024 MB dýr. (yani 2 byte)
40
1 terabyte 1 TB = 1024 GB dýr. (yani 2 byte)
50
1 petabyte 1PB = 1024 TB dýr. (yani 2 byte)
60
1 exabyte 1EB = 1024 PB dýr. (yani 2 byte)
70
1 zettabyte 1ZB = 1024 EB dir.( yani 2 byte)
80
1 yottabyte 1YB = 1024 ZB dýr.( yani 2 byte)
10
Kilo büyüklük olarak 1000 kat anlamýna gelmektedir, ancak bilgisayar alanýnda Kilo 2'nin 1000'e en yakýn
10
kuvveti olan 2 yani 1024 kat olarak kullanýlýr.
4 bit 1 Nybble (Nibble ºeklinde de yazýlýr)
8 bit 1 byte
16 bit
1 word
32 bit
1 double word
64 bit
1 quadro word
olarak da isimlendirilmektedir.
ikilik sisteme iliºkin genel iºlemler
i. Ýkilik sistemdeki bir sayýnýn 10 luk sistemde ifade edilmesi:
ikilik sayý sisteminde ifade edilen bir sayýnýn 10’luk sistemdeki karºýlýðýný hesaplamak için en saðdan
baºlayarak bütün basamaklarý tek tek 2’nin artan kuvvetleriyle çarpýlýr. Örneðin :
0
1
2
3
1 0 1 1 = 1 * 2 + 1 * 2 + 0 * 2 + 1 * 2 = 11
0010 1001 = (1 * 1) + (1 * 8) + (1 * 32) = 41
Bu arada sýk kullanýlan iki terimi de açýklayalým. Ýkilik sayý sisteminde yazýlan bir sayýnýn en solundaki bit,
yukarýdaki örnekten de görüldüðü gibi en yüksek sayýsal deðeri katýyor. Bu bite en yüksek anlamlý bit (most
significant digit) diyeceðiz ve bu bit için bundan sonra MSD kýsaltmasýný kullanacaðýz.
Ýkilik sayý sisteminde yazýlan bir sayýnýn en saðýndaki bit, yine yukarýdaki örnekten de görüldüðü gibi en
düºük sayýsal deðeri katýyor. Bu bite en düºük anlamlý bit (least significant digit) diyeceðiz ve bu bit için
bundan sonra LSD kýsaltmasýný kullanacaðýz.
Örnek :
0101 1101 sayýsý için
MSD = 0
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
11
Buy RoboPDF
2 . BÖLÜM :
LSD = 1
Ýkilik sayý sisteminde yazýlan bir sayýnýn belirli bir basamaðýndan (bitinden) söz ettiðimizde, hangi bitten söz
edildiðinin doðru bir ºekilde anlaºýlmasý için basamaklar numaralandýrýlýr.
8 bitlik bir sayý için, sayýnýn en saðýndaki bit (yani (LSD) sayýnýn 0. bitidir. Sayýnýn en solundaki bit (yani
MSD) sayýnýn 7. bitidir.
ii. 10’luk sistemdeki bir sayýnýn 2’lik sistemde ifadesi :
Sayý sürekli olarak 2 ye bölünür. Her bölümden kalan deðer( yani 1 ya da 0) oluºturulacak sayýnýn 0. bitinden
baºlayarak, basamaklarýný oluºturacaktýr. Bu iºleme 0 sayýsý elde edilinceye kadar devam edilir. Örnek:
87 sayýsýný ikilik sayý sisteminde ifade etmek isteyelim:
87 / 2 = 43 (kalan 1) Sayýnýn 0. biti 1
43 / 2 = 21 (kalan 1) Sayýnýn 1. biti 1
21 / 2 = 10 (kalan 1) Sayýnýn 2. biti 1
10 / 2 = 5 (kalan 0) Sayýnýn 3. biti 0
5 / 2 = 2 (kalan 1) Sayýnýn 4. biti 1
2 / 2 = 1 (kalan 0) Sayýnýn 5. biti 0
1 / 2 = 0 (kalan 1) Sayýnýn 6. biti 1
87 = 0101 0111
Ýkinci bir yöntem ise 10 luk sistemde ifade edilen sayýdan sürekli olarak 2'nin en büyük kuvvetini çýkarmaktýr.
2’nin çýkarýlan her bir kuvveti için ilgili basamaða 1 deðeri yazýlýr. Bu iºleme 0 sayýsý elde edilene kadar
devam edilir. Örnek:
Yine 87 sayýsýný ikilik sayý sisteminde ifade etmek isteyelim:
6
87'den çýkarýlabilecek, yani 87'den büyük olmayan ikinin en büyük kuvveti nedir? Cevap 64. O zaman 64 = 2
olduðuna göre 6.bit 1 deðerini alacak.
4
87 - 64 = 23. ªimdi 23'den çýkarýlabilecek ikinin en büyük kuvvetini bulalým. Bu say1 16'dýr. Yani 2 'dür. O
zaman sayýmýzýn 4. biti de 1 olacak.
2
23 - 16 = 7. 7'den çýkarýlabilecek ikinin en büyük kuvveti 4'dür ve 4 = 2 'dir. Sayýmýzýnj 2. biti de 1 olacak.
7 - 4 = 3.
1
3 - 2 = 1 (2 = 2 ) Sayýmýzýn 1. biti 1 olacak.
0
1 - 1 = 0 (1 = 2 ) Sayýmýzýn 0. biti 1 olacak.
1 deðeri olmayan tüm bitleri 0 bitiyle doldurarak sayýmýzý ikilik sistemde ifade edelim:
87 = 0101 0111
iii. Ýkilik sistemde ifade edilen bir sayýnýn 1’e tümleyeni. Sayýnýn tüm bitlerinin tersinin
alýnmasýyla elde edilir. Yani sayýdaki 1’ler 0 ve 0’lar 1 yapýlýr.
Bir sayýnýn 1’e tümleyeninin 1’e tümleyeni sayýnýn yine kendisidir.
iv. Ýkilik sistemde ifade edilen bir sayýnýn 2’ye tümleyeninin bulunmasý:
Önce sayýnýn 1’e tümleyeni yukarýdaki gibi bulunur. Daha sonra elde edilen sayýya 1 eklenirse sayýnýn 2’ye
tümleyeni bulunmuº olur. 2'ye tümleyeni bulmak için daha daha pratik bir yol daha vardýr : Sayýnýn en
solundan baºlayarak ilk defa 1 biti görene kadar (ilk görülen 1 dahil) sayýnýn aynýsý yazýlýr, daha sonraki tüm
basamaklar için basamaðýn tersi yazýlýr. (Yani 1 için 0 ve 0 için 1) Örneðin :
1110 0100 sayýsýnýn ikiye tümleyeni 0001 1100 dýr.
0101 1000 sayýsýnýn ikiye tümleyeni 1010 1000 dýr.
Bir sayýnýn ikiye tümleyeninin ikiye tümleyeni sayýnýn kendisidir. (Deneyiniz)
8 bitlik bir alana yazýlacak en büyük tam sayý kaçtýr?
1111 1111 = 255 dir. (1 + 2 + 4 + 8 + 16 + 32 + 64 + 128 = 255)
8 bitlik bir alana yazýlacak en küçük tam sayý kaçtýr?
0000 0000 = 0’dýr.
Negatif bir tamsayý ikilik sistemde nasýl gösterilir?
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
12
Buy RoboPDF
SAYI SÝSTEMLERÝ
Negatif tamsayýlarýn da ifade edildiði ikilik sayý sistemine iºaretli ikilik sayý sistemi (signed binary system)
denir. ݺaretli ikilik sayý siteminde, negatif sayýlarý göstermek için hemen hemen tüm bilgisayar sistemlerinde
aºaðýdaki yol izlenir:
Sayýnýn en yüksek anlamlý biti iºaret biti (sign bit) olarak kabul edilir. Ve bu bit 1 ise sayý negatif, bu bit 0 ise
sayý pozitif olarak deðerlendirilir. Ýkilik sistemde bir negatif sayý ayný deðerdeki pozitif sayýnýn ikiye
tümleyenidir. Örnek olarak, ikilik sistemde yazacaðýmýz –27 sayýsý yine ikilik sistemde yazýlan 27 sayýsýnýn
ikiye tümleyenidir.
Pozitif olan sayýlarýn deðerini týpký iºaretsiz sayý sisteminde olduðu gibi elde ederiz:
0001 1110 iºaretli sistemde pozitif bir sayýdýr. (Decimal olarak 29 sayýsýna eºittir.)
Ancak negatif olan sayýlarýn deðerini ancak bir dönüºümle elde edebiliriz:
1001 1101 iºaretli sistemde negatif bir sayýdýr. (Çünkü iºaret biti 1)
2lik sistemde ifade edilen negatif bir sayýnýn 10’luk sistemde hangi negatif sayýya eºit olduðunu nasýl
bulunur?
Sayýnýn en yüksek anlamlý biti (MSD) iºaret bitidir. Bu bit 1 ise sayý negatifdir. Sayýnýn kaça eºit olduðunu
hesaplamak için ilk önce sayýnýn 2’ye tümleyeni bulunur. Ve bu sayýnýn hangi pozitif sayýya karºýlýk geldiðini
hesap edilir. Elde etmek istenen sayý, bulunan pozitif sayý ile ayný deðerdeki negatif sayý olacaktýr.
Örneðin 1001 1101 sayýsýnýn 10’luk sistemde hangi sayýya karºýlýk geldiði bulunmak istenirse:
Sayýnýn en soldaki biti 1 olduðuna göre bu sayý negatif bir sayý olacaktýr. Hangi negatif sayý olduðunu bulmak
için sayýnýn 2’ye tümleyenini alýnýr.
1001 1101 sayýsýnýn ikiye tümleyeni 0110 0011 sayýsýdýr.
Bu sayýnýn 10'luk sistemde hangi sayýya denk olduðu hesaplanýrsa :
(1 * 1 + 1 * 2 + 0 * 4 + 0 * 8 + 0 * 16 + 1 * 32 + 1 * 64 = 99)
ilk yazýlan sayýnýn -99 olduðu anlaºýlmýº olur.
10'luk sistemde ifade edilen negatif sayýlarýn iºaretli ikilik sistemde yazýlmasý :
Önce sayýnýn ayný deðerli fakat pozitif olaný ikilik sistemde ifade edilir : Daha sonra yazýlan sayýnýn ikiye
tümleyenini alýnarak, yazmak istenilen sayý elde edilir.
Örnek : Ýkilik sistemde –17 yazmak istenirse;
önce 17 yazýlýr.
bu sayýnýn 2'ye tümleyeni alýnýrsa
0001 0001
1110 1111 sayýsý elde edilir.
Sayý deðeri ayný olan Negatif ve Pozitif sayýlar birbirlerinin ikiye tümleyenleridir.
Ýkilik sistemde gösterilmiº olsa da ayný sayýnýn negatifiyle pozitifinin toplamý 0 deðerini verecektir.
(Deneyiniz!)
Bir byte’lýk (8 bitlik) bir alana yazabileceðimiz (iºaret bitini dikkate almadan) en büyük sayý 255 (1111 1111)
ve en küçük sayý ise 0’dýr.(0000 0000). Peki iºaret biti dikkate alýndýðýnda 1 byte’lýk alana yazýlabilecek en
büyük ve en küçük sayýlar ne olabilir?
En büyük sayý kolayca hesaplanabilir. iºaret biti 0 olacak (yani sayý pozitif olacak) ve sayý deðerini en büyük
hale getirmek için diðer bütün bit deðerleri 1 olacak, bu sayý 0111 1111 sayýsýdýr. Bu sayýyý desimal sisteme
dönüºtürürsek 127 olduðunu görürüz. Peki ya en küçük negatif sayý kaçtýr ve nasýl ifade edilir?
0111 1111 sayýsýnýn ikiye tümleyenini alýndýðýnda –127 sayýsýný elde edilir.
1000 0001 (127) Bu sayýdan hala 1 çýkartabilir.
1000 0000 (-128) 1 byte alana yazýlabilecek en küçük negatif sayýdýr.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
13
Buy RoboPDF
2 . BÖLÜM :
Burada dikkat edilmesi gereken iki önemli nokta vardýr :
1 byte alana yazýlabilecek en büyük sayý sýnýrý aºýldýðýnda negatif bölgeye geçilir.
0111 1111 (en büyük pozitif tamsayý)
1 (1 toplarsak)
1000 0000 (-128 yani en küçük tamsayý)
yani 1 byte alana yazýlabilecek en büyük tamsayýya 1 eklendiðinde 1 byte alana yazýlabilecek en küçük
tamsayýyý elde ederiz.
1 byte alana yazýlabilecek en küçük tamsayýdan 1 çýkardýðýmýzda da 1 byte alana yazýlabilecek en büyük
tamsayýyý elde ederiz.
Yukarýda anlattýklarýmýza göre -1 sayýsýnýn iºaretli ikilik sayý sisteminde 8 bitlik bir alanda aºaðýdaki ºekilde
ifade edilecektir.
-1 = 1111 1111
Yani iºaretli ikilik sayý sisteminde tüm bitleri 1 olan sayý -1'dir. Ýleride bu sayýyla çok iºimiz olacak!
16’lýk sayý sistemi (hexadecimal numbering system) ve 8’lik sayý
sistemi (octal system)
Bilgisayarlarýn tamamen 2’lik sistemde çalýºtýðýný söylemiºtik, ama yukarýda görüldüðü gibi 2’lik sistemde
sayýlarýn ifade edilmesi hem çok uzun hem de zahmetli. Bu yüzden, yazým ve algýlama kolaylýðý saðlamak
için 16’lýk ve 8’lik sayý sistemleri de kullanýlmaktadýr.
16'lýk ve 8’lik sayý sistemlerinde sayýlar daha yoðun olarak kodlanýp kullanabilir.
Baºta da söz edildiði gibi 10 luk sistemde 10, 2’lik sistemde ise 2 sembol bulunmaktadýr. Bu durumda 16’lýk
sayý sisteminde de 16 sembol bulunur.
ilk 10 sembol 10'luk sistemde kullanýlan sembollerle tamamen aynýdýr :
1, 2, 3, 4, 5, 6, 7, 8, 9,
Daha sonraki semboller
A
B
C
D
E
F
= 10
= 11
= 12
= 13
= 14
= 15
16’lýk sayý sisteminde yazýlmýº bir sayýyý 10’luk sisteme çevirmek için, en saðdan baºlayarak basamak
deðerleri 16’nýn artan kuvvetleriyle çarpýlýr :
01AF = (15 * 1) + (10 * 16) + (1 * 256) + (0 * 4096) = 431
10’luk sistemde yazýlmýº bir sayýyý 16’lýk sisteme çevirmek için 10 luk sistemden 2’lik sisteme yapýlan
dönüºümlerdekine benzer ºekilde sayý sürekli 16 ya bölünerek, kalanlar soldan saða doðru yazýlýr.
Pratikte 16 lýk sayý sistemlerinin getirdiði önemli bir avantaj vardýr. Bu avantaj 16 lýk sayý sistemi ile 2’lik sayý
sistemi arasýndaki dönüºümlerin kolay bir ºekilde yapýlmasýdýr.
16’lýk sistemdeki her digit 2’lik sistemdeki 4 bit (1 Nibble) alan ile ifade edilebilir :
0001
0010
0011
0100
0101
0110
0111
1
2
3
4
5
6
7
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
14
Buy RoboPDF
SAYI SÝSTEMLERÝ
1000
1001
1010
1011
1100
1101
1110
1111
8
9
A
B
C
D
E
F
Örnek : 2ADFH sayýsýnýn (en sondaki H sayýnýn hexadecimal olarak gösterildiðini anlatýr yani sayýya iliºkin
bir sembol deðildir) 16'lýk sistemde ifadesi :
2
A
D
F
=
=
=
=
0010
1010
1101
1111
Bu durumda 2ADFH = 0010 1010 1101 1111
2’lik sistemden 16’lýk sisteme yapýlacak dönüºümler de benzer ºekilde yapýlabilir :
Önce sayýlarý saðdan baºlayarak dörder dörder ayýrýrýz (en son dört eksik kalýrsa sýfýr ile tamamlarýz.) Sonra
her bir dörtlük grup için doðrudan 16'lýk sayý sistemindeki karºýlýðýný yazarýz.
1010 1110 1011 0001
0010 1101 0011 1110
= AEB1H
= 2D3EH
soru : 16'lýk sayý sisteminde 2 byte'lýk bir alanda yazýlmýº olan 81AC H sayýsý pozitif mi negatif midir?
cevap : Sayýnýn yüksek anlamlý biti 1 olduðu için, iºaretli sayý sistemlerinde sayý negatif olarak
deðerlendirilecektir. (1001 0001 1010 1100)
16 bitlik bir alanda ve iºaretli sayý sisteminde -1 sayýsýný nasýl ifade edebiliriz :
Cevap : FFFF
8’lik sayý sistemi (octal numbering system)
Daha az kullanýlan bir sayý sistemidir.
8 adet sembol vardýr. (0 1 2 3 4 5 6 7)
8’lik sayý sisteminin her bir digiti 2’lik 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 kullanýlma nedeni, 2'lik sayý sistemine göre daha yogun bir ifade tarzý olmasý, ve ikilik
sayý sistemiyle, 8'lik sayý sistemi arasýnda yapýlacak dönüºümlerin çok kolay bir biçimde yapýlabilmesidir.
GERÇEK SAYILARIN BELLEKTE TUTULMASI
Sistemlerin çoðu gerçek sayýlarý IEEE 754 standardýna göre tutarlar. (Institute of Electrical and
Electronics Engineers) Bu standarda göre gerçek sayýlar için iki ayrý format belirlenmiºtir:
single precision format (tek hassasiyetli gerçek sayý formatý)
Bu formatta gerçek sayý 32 bit (8 byte) ile ifade edilir.
32 bit üç ayrý kýsma ayrýlmýºtýr.
1. ݺaret biti (sign bit) (1 bit)
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
15
Buy RoboPDF
2 . BÖLÜM :
Aºaðýda S harfi ile gösterilmiºtir.
ݺaret biti 1 ise sayý negatif, iºaret biti 0 ise sayý pozitiftir.
2. Üstel kýsým (exponent) (8 bit)
Aºaðýda E harfleriyle gösterilmiºtir.
3. Ondalýk kýsým (fraction) (23 bit)
Aºaðýda F harfleriyle gösterilmiºtir.
S
31
EEEEEEEE
30-----------23
FFFFFFFFFFFFFFFFFFFFFFF
22-------------------------------------0
Aºaðýdaki formüle göre sayýnýn deðeri hesaplanabilir :
V sayýnýn deðeri olmak üzere:
E = 255 ise ve F 0 dýºý bir deðer ise V = NaN (Not a number) bir gerçek sayý olarak kabul edilmez. Örnek :
0 11111111 00001000000100000000000
1 11111111 00010101010001001010101
= Sayý deðil
= Sayý deðil
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
S
(E -127)
V = (-1) * 2
* (1.F)
Önce sayýnýn fraction kýsmýnýn baºýna 1. eklenir. Daha sonra bu sayý 2
ile çarpýlarak noktanýn yeri
ayarlanýr. Noktadan sonraki kýsým 2'nin artan negatif kuvvetleriyle çarpýlarak elde edilecektir. Örnekler :
(E-127)
0 10000000 00000000000000000000000 = +1 * 2
= 2 * 1.0
= 10.00
=2
(128 - 127)
* 1.0
0 10000001 10100000000000000000000 = +1 * 2
2
= 2 * 1.101
= 110.100000
= 6.5
(129 - 127)
* 1.101
1 10000001 10100000000000000000000 = -1 * 2
2
= -2 * 1.101
= 110.100000
= -6.5
(129 - 127)
0 00000001 00000000000000000000000 = +1 * 2
-126
=2
(1 - 127)
* 1.101
* 1.0
E = 0 ve F sýfýr dýºý bir deðer ise
V = (-1) * 2
S
(-126)
* (0.F)
Örnekler :
-126
* 0.1
-126
0. 00000000000000000000001
0 00000000 10000000000000000000000 = +1 * 2
=
0 00000000 00000000000000000000001 = +1 * 2
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
16
Buy RoboPDF
SAYI SÝSTEMLERÝ
=2
-149
(en küçük pozitif deðer)
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 gerçek sayý formatý)
Bu formatta gerçek sayý 64 bit (8 byte) ile ifade edilir.
64 bit üç ayrý kýsýma ayrýlmýºtýr.
1. ݺaret biti (sign bit) (1 bit)
Aºaðýda S harfi ile gösterilmiºtir.
ݺaret biti 1 ise sayý negatif, iºaret biti 0 ise sayý pozitiftir.
2. Üstel kýsým (exponent) (11 bit)
Aºaðýda E harfleriyle gösterilmiºtir.
3. Ondalýk kýsým (fraction) (52 bit)
Aºaðýda F harfleriyle gösterilmiºtir.
S EEEEEEEEEEE FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
63 62------------------52 51-----------------------------------------------------------------------------0
Aºaðýdaki formüle göre sayýnýn deðeri hesaplanabilir :
Aºaðýdaki formüle göre sayýnýn deðeri hesaplanabilir :
V sayýnýn deðeri olmak üzere:
E = 2047 ise ve F 0 dýºý bir deðer ise V = NaN (Not a number) bir gerçek 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
S
(E -1023)
V = (-1) * 2
* (1.F)
Önce sayýnýn fraction kýsmýnýn baºýna 1. eklenir. Daha sonra bu sayý 2
ile çarpýlarak noktanýn yeri
ayarlanýr. Noktadan sonraki kýsým 2'nin artan negatif kuvvetleriyle çarpýlarak elde edilecektir.
(E-1023)
E = 0 ve F sýfýr dýºý bir deðer ise
S
(-126)
V = (-1) * 2
* (0.F)
E = 0 ve F = 0 ve S = 1 ise V = -0
E = 0 ve F = 0 ve S = 0 ise V = 0
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
17
Buy RoboPDF
2 . BÖLÜM :
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
18
Buy RoboPDF
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
Buy RoboPDF
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
20
Buy RoboPDF
GENEL KAVRAMLAR
3 . BÖLÜM : GENEL KAVRAMLAR
ATOM KAVRAMI VE ATOM TÜRLERÝ
Bir programlama dilinde yazýlmýº programý en küçük parçalara bölmeye çalýºalým. Öyle bir noktaya geleceðiz
ki, artýk bu parçalarý daha da bölmeye çalýºtýðýmýzda anlamsýz parçalar oluºacak. ݺte bir programlama
dilinde anlam taºýyan en küçük birime atom (token) denir.
Atomlar daha fazla parçaya bölünemezler.
Yazdýðýmýz kaynak kod (program) derleyici tarafýndan ilk önce atomlarýna ayrýlýr. (Tokenizing). Atom
yalnýzca C diline iliºkin bir kavram deðildir. Tüm programlama dilleri için atom kavramý söz konusudur, ama
farklý programlama dillerinin atomlarý birbirlerinden farklý olabilir.
Atomlarý aºaðýdaki gibi gruplara ayýrabiliriz :
1. Anahtar Sözcükler (keywords, reserved words)
Bu atomlar dil için belli bir anlam taºýrlar. Deðiºken olarak kullanýlmalarý yasaklanmýºtýr. Yani programcý bu
anahtar sözcükleri kendi tanýmlayacaðý deðiºkenlere isim olarak veremez.
Standard ANSI C dilinde 32 tane anahtar sözcük bulunmaktadýr.(Derleyici yazan firmalar kendi yazdýklarý
derleyiciler için ilave anahtar sözcükler tanýmlayabilmektedir.)
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 sözcüklerin küçük ya da büyük harf olmasý fark etmemektedir. Ama
C’de bütün anahtar sözcükler küçük harf olarak tanýmlanmýºtýr. C büyük harf küçük harf duyarlýðý olan bir
dildir. (case sensitive) bir dildir. Ama diðer programlama dillerinin çoðunda büyük - küçük harf duyarlýðý
yoktur. (case insensitive)
Örneðin, programcý olarak biz kullanacaðýmýz bir deðiºkene “register” ismini vermeyiz. Çünkü bu bir anahtar
sözcüktür. (C dili tarafýndan rezerve edilmiºtir) Ama buna karºýn biz istediðimiz bir deðiºkene REGISTER,
Register, RegisTER vs. gibi isimler verebiliriz, çünkü bunlar artýk anahtar sözcük sayýlmazlar. Anahtar
sözcük olan yalnýzca tamamen küçük harf ile yazýlan "register" dir.
2. Ýsimlendirilenler (identifiers)
Deðiºkenlere, fonksiyonlara, makrolara, yapý ve birliklere vs. programlama dili tarafýndan belirlenmiº
kurallara uyulmak ºartýyla, istediðimiz gibi isim verebiliriz. Bu atomlar genellikle bellekte bir yer belirtirler.
C dilinde deðiºkenlerin isimlendirilmesine iliºkin kurallar vardýr. Bunu ileride detaylý olarak göreceðiz.
3. Operatörler (Operators)
Operatörler önceden tanýmlanmýº birtakým iºlemleri yapan atomlardýr.
Örneðin +, -, *, / , >=, <= birer operatördür.
Programlama dillerinde kullanýlan operatör sembolleri birbirinden farklý olabileceði gibi, operatör
tanýmlamalarý da birbirinden farklý olabilir. Örneðin birçok programlama dilinde üs alma operatörü
tanýmlanmýºken C dilinde böyle bir operatör yoktur. Üs alma iºlemi operatör ile deðil bir fonksiyon yardýmýyla
yapýlabilir.
C dilinde bazý operatörler iki karakterden oluºmaktadýr bu iki karakter bitiºik yazýlmalýdýr aralarýna space
karakteri koyarsak operatör anlamýný yitirir.
4. Sabitler (Constants)
Doðrudan iºleme sokulan deðiºken bilgi içermeyen atomlardýr.
Örneðin SAYAC = SON + 10 gibi bir ifadede 10 sabiti doðrudan SON deðiºkeni ile toplanmaktadýr.
5. Stringler (String literals)
Ýki týrnak içindeki ifadelere string denir. Stringler programlama dillerinin çoðunda tek bir atom olarak alýnýrlar,
daha fazla parçaya bölünemezler.
“STRÝNGLER DE BÝRER ATOMDUR” ifadesi bir stringdir.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
21
Buy RoboPDF
3 . BÖLÜM :
6. Ayýraçlar ya da noktalama iºaretleri (Separators, Punctuators,
Delimiters)
Yukarýda sayýlan atom sýnýflarýnýn dýºýnda kalan tüm atomlarý bu gruba sokabiliriz. Genellikle diðer atomlarý
birbirinden ayýrma amacýyla kullanýldýklarý için ayýraç olarak isimlendirilirler.
örnek bir C programýnýn atomlarýna ayrýlmasý:
Aºaðýda 1 den kullanýcýnýn klavyeden girdiði bir tamsayýya kadar olan tamsayýlarý toplayan ve sonucu ekrana
yazdýran bir C programý görülüyor. Bu kaynak kodu atomlarýna ayýralým. Amacýmýz söz konusu programý
açýklamak deðil, atomlar hakkýnda gerçek bir programdan örnek vermek.
#include <stdio.h>
main()
{
int number, k, total = 0;
printf("lütfen bir sayý giriniz\n");
scanf("%d", &number);
for(k = 1; k<= number; ++k)
total += k;
printf("toplam = %d\n", toplam);
return 0;
}
#
include
<
stdio.h
>
main
,
k
,
total
=
0
;
printf
(
"lütfen bir sayý giriniz\n"
&
number
)
;
for
(
k
=
1
;
k
total
+=
k
;
printf
(
"toplam = %d\n"
,
<=
(
)
{
)
;
scanf
;
toplam
int
(
number
"%d"
++
k
)
)
;
}
,
programda yer alan atomlardan
anahtar sözcükler
include int
for
return
isimlendirilenler (identifiers / variables)
main n k
toplam
printf
scanf
operatörler
= <= ++
sabitler
0
1
+=
0
stringler
("lütfen bir sayý giriniz\n"
)
"%d"
"toplam = %d\n"
ayýraçlar noktalama iºaretleri
< > ( ) , ; {
}
NESNE (OBJECT)
Bellekte yer kaplayan ve içeriklerine eriºilebilen alanlara nesne denir. Bir ifadenin nesne olabilmesi için
bellekte bir yer belirtmesi gerekir. Programlama dillerinde nesnelere isimlerini kullanarak eriºebiliriz.
a = b + k; örneðinde a, b ve k birer nesnedir. Bu ifadede a nesnesine b ve k nesneleriine ait deðerlerin
toplamý atanmaktadýr.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
22
Buy RoboPDF
GENEL KAVRAMLAR
sonuc = 100;
sonuc isimli nesneye 100 sabit deðeri atanmaktadýr.
nesnelerin bazý özelliklerinden söz edilebilir :
Ýsimleri (name) :
Nesneyi temsil eden karakterlerdir. Nesnelere isimleri programcý tarafýndan verilir. Her dil için nesne
isimlendirmede bazý kurallar söz konusudur.
VERGI = 20000; (Burada VERGI bir nesne ismidir.)
Nesne ile Deðiºken kavramlarý birbirine tam olarak eºdeðer deðildir. Her deðiºken bir nesnedir ama her
nesne bir deðiºken deðildir. Deðiºkenler, programcýnýn isimlendirdiði nesnelerdir. Peki programcýnýn
isimlendirmediði de nesneler var mýdýr? Evet, göstericiler konusunda da göreceðimiz gibi, deðiºken olmayan
nesneler de vardýr, nesne kavramý deðiºken kavramýný kapsamaktadýr.
Deðerleri (value) :
Nesnelerin içlerinde tuttuklerý bilgilerdir. Baºka bir deyiºle nesneler için bellekte ayrýlan yerklerdeki 1 ve 0
larýn yorumlanýº biçimi ilgili nesnenin deðeridir. Bu deðerler programlama dillerinin kurallarýna göre ,
istenildikleri zaman programcý tarafýndan deðiºtirilebilirler. C dilinde bazý nesneler ise bir kez deðer
verildikten sonra bir daha deðiºtirilemezler.
Türleri (Type) :
Nesnenin türü derleyiciye o nesnenin nasýl yorumlanacaðý hakkýnda bilgi verir. Yine bir nesnenin türü onun
bellekteki uzunluðu hakkýnda da bilgi verir. Her türün bellekte ne kadar uzunlukta bir yer kapladýðý
programlama dillerinde önceden belirtilmiºtir. Bir nesnenin türü, ayrýca o nesne üzerinde hangi iºlemlerin
yapýlabileciði bilgisini de verir.
Tür nesnenin ayrýlmaz bir özelliðidir, türsüz bir nesne kavramý söz konusu deðildir.
Türleri ikiye ayýrabiliriz :
1. Önceden tanýmlanmýº veri türleri (default types)
Bu türler programlama dilinin tasarýmýnda var olan veri türleridir. Örneðin C dilinde önceden
tanýmlanmýº 11 ayrý veri türü vardýr.
2. Programcý tarafýndan tanýmlanan veri türleri (user defined types)
Programlama dillerinin çoðunda programcýnýn tür tanýmlamasýna izin vermektedir. Örneðin C dilinde yapýlar,
birlikler, bit alanlarý, C++ dilinde de sýnýflar programcý tarafýndan tanýmlanan veri türleridir.
Programlama dillerindeki tür tanýmlamalarý birbirlerinden farklý olabilir. Örneðin bazý programlama dillerinde
Boolean isimli (Mantýksal Doðru ya da Yanlýº deðerlerini alan) bir türdür tanýmlanmýºtýr. Ama C dilinde böyle
bir tür doðrudan tanýmlanmamýºtýr.
Faaliyet alanlarý (scope / visibility) :
Nesnenin, dilin derleyicisi ya da yorumlayýcýsý tarafýndan tanýnabildiði program alanýdýr. (ileride detaylý
inceleyeceðiz)
Ömürleri (storage duration / lifespan) :
Programýn çalýºtýrýlmasý sýrasýnda nesnenin varlýðýný sürdürdüðü zaman parçasýdýr. (Ýleride detaylý
inceleyeceðiz)
Baðlantýlarý (linkage)
Nesnelerin programý oluºturan diðer modüllerde tanýnabilme özelliðidir. (Ýleride detaylý inceleyeceðiz)
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
23
Buy RoboPDF
3 . BÖLÜM :
ÝFADE (Expression)
Deðiºken, operatör ve sabitlerin kombinasyonlarýna ifade denir.
a+b/2
c * 2, d = h + 34
var1
geçerli ifadelerdir.
DEYÝM (statement)
Derleyicinin, bilgisayara bir iº yaptýracak ºekilde kod üretmesine (yani icra edilebilecek bir kod üretmesine)
yol açan ifadelere deyim denir.
Örneðin C dilinde
; ile sonlandýrýlmýº ifadelere deyim diyoruz.
result = number1 * number2
bir ifadedir. Ancak
result = number1 * number2;
bir deyimdir. Bu deyim derleyicinin, number1 ve number2 deðiºkenlerin deðerlerinin çarpýlarak, elde edilen
deðerin result deðiºkenine atanmasýný saðlayacak ºekilde kod üretmesine neden olacaktýr.
Deyimleri Ýleride detaylý olarak inceleyeceðiz.
SOL TARAF DEÐERÝ (Left Value)
Nesne gösteren ifadelere denir. Bir ifadenin sol taraf deðeri olabilmesi için mutlaka bir nesne göstermesi
gerekir. Bir ifadenin Sol taraf deðeri olarak isimlendirilmesinin nedeni o ifadenin atama operatörünün sol
tarafýna getirilebilmesidir.
Örneðin a ve b nesneleri tek baºýna sol taraf deðerleridir. Çünkü bu ifadeler atama operatörünün sol tarafýna
getirilebilirler.
Örneðin a = 17, ya da b = c * 2 denilebilir.
Ama a + b bir sol taraf deðeri deðildir. Çünkü a + b = 25 denilemez.
Deðiºkenler her zaman sol taraf deðeridirler.
sabitler sol taraf deðeri olamazlar.
SAÐ TARAF DEÐERÝ (Rigth Value)
Daha az kullanýlan bir terimdir. Nesne göstermeyen ifadeler sað taraf deðeri olarak isimlendirilirler. Tipik
olarak, atama operatörünün sol tarafýnda bulunamayan yalnýzca sað tarafýnda bulunabilen ifadelerdir.
Sabitler her zaman sað taraf deðeri oluºtururlar.
(Bir ifade sol taraf deðeri deðilse sað taraf deðeridir. Sað taraf deðeri ise sol taraf deðeri
deðildir.Her ikisi birden olamaz. Yani atama operatörünün sað tarafýna gelebilen her ifade sað
taraf deðeri olarak isimlendirilmez.) Sað taraf deðeri, genellikle bir ifadenin nesne
göstermediðini
vurgulamak
için
kullanýlýr.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
24
Buy RoboPDF
VERÝ TÜRLERÝ
4 . BÖLÜM : VERÝ TÜRLERÝ
Nesne (Object) kavramýný incelediðimiz zaman, nesnelerin en önemli özelliklerinden birinin nesnenin türü
olduðunu belirtmiºtik. Tür (type) nesnenin olmazsa olmaz bir özelliðidir ve türü olmayan bir nesneden söz
etmek mümkün deðildir. Derleyiciler nesnelerle ve verilerle ilgili kod üretirken, tür bilgisinden faydalanýrlar.
Tür bilgisinden, söz konusu veriyi bellekte ne ºekilde tutacaklarýný, verinin deðerini ne ºekilde
yorumlayacaklarýný, veriyi hangi iºlemlere tabi tutabileceklerini öðrenirler.
Programlama dilleri açýsýndan baktýðýmýz zaman türleri iki ayrý gruba ayýrabiliriz.
1. Önceden tanýmlanmýº veri türleri (Doðal veri türleri)
(Basic tpes, default types, built-in types, primitive types)
Programlama dilinin tasarýmýndan kaynaklanan ve dilin kurallarýna göre varlýðý garanti altýna alýnmýº olan
türlerdir. Her programlama dili programcýnýn doðrudan kullanabileceði, çeºitli özelliklere sahip veri türleri
tanýmlar. C dilinde de önceden tanýmlanmýº 11 adet veri türü vardýr.
2. Programcýnýn tanýmlanmýº olduðu veri türleri (user defined types)
Programlama dillerinin çoðu, önceden tanýmlanmýº veri türlerine ek olarak, programcýnýn da yeni türler
tanýmlanmasýna izin vermektedir. Programcýnýn tanýmlayacaðý bir nesne için önceden tanýmlanmýº veri
türleri yetersiz kalýyorsa, programcý kendi veri türünü yaratabilir. C dilinde de programcý yeni bir veri türünü
derleyiciye tanýtabilir ve tanýttýðý veri türünden nesneler tanýmlayabilir.
Farklý programlama dillerindeki önceden tanýmlanan veri türleri birbirlerinden farklý olabilir. Daha önce
öðrenmiº olduðunuz bir programlama dilindeki türlerin aynýsýný C dilinde bulamayabilirsiniz.
C dilininin önceden tanýmlanmýº 11 veri türü vardýr. Bu veri türlerinden 8 tanesi tamsayý türünden verileri
tutmak için, kalan 3 tanesi ise gerçek sayý türünden verileri tutmak için tasarlanmýºtýr. Biz bu türlere sýrasýyla
"Tamsayý veri türleri" (integer types) ve "gerçek sayý veri türleri" (floating types) diyeceðiz.
tamsayý veri türleri (integer types)
C dilinin toplam 4 ayrý tamsayý veri türü vardýr ancak her birinin kendi içinde iºaretli ve iºaretsiz biçimi
olduðundan, toplam tamsayý türü 8 kabul edilir.
ݺaretli (signed) tamsayý türlerinde pozitif ve negatif tam sayý deðerleri tutulabilirken, iºaretsiz (unsigned) veri
türlerinde negatif tamsayý deðerleri tutulamaz.
Bu türleri sýrasýyla inceleyelim:
iºaretli ve iºaretsiz char veri türü :
ªüphesiz char sözcüðü ingilizce character sözcüðünden kýsaltýlmýºtýr ve türkçe "karakter" anlamýna
gelmektedir. Ancak bu türün ismini, bundan sonraki derste C dilinin bir anahtar sözcüðü olduðunu
öðreneceðimiz char sözcüðü ile özdeºleºtirip, "char türü" (çar diye okuyunuz) diye söyleyeceðiz. ݺaretli
char türünden bir nesnenin bir byte'lýk bir alanda tutulmasý C standartlarýnca garanti altýna alýnmýºtýr.
1 byte'lýk bir alaný iºaretli olarak kullandýðýmýzda yazabileceðimiz deðerlerin -128 / 127 deðerleri arasýnda
deðiºebileceðini sayý sistemleri dersimizden hatýrlayalým.
iºaretsiz char veri türünün iºaretli olandan farký 1 byte'lýk alanýn iºaretsiz olarak, yani yalnýzca 0 ve pozitif
sayýlarýn ifadesi için kullanýlmasýdýr. Bu durumda iºaretsiz char türünde 0 - 255 arasýndaki tamsayý deðerleri
tutulabilir.
iºaretli ve iºaretsiz short int veri türü (iºaretli kýsa tamsayý türü - iºaretsiz
kýsa tamsayý türü) :
Yine bundan sonraki derste öðreneceðimiz gibi, short ve int sözcükleri C dilinin anahtar sözcüklerinden
olduðu için bu türün ismini genellikle short int, ya da kýsaca short türü olarak telaffuz edeceðiz.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
25
Buy RoboPDF
4 . BÖLÜM :
iºaretli ve iºaretsiz short veri türünden bir nesne tanýmlandýðý zaman, nesnenin bellekte kaç byte yer
kaplayacaðý sistemden sisteme deðiºebilir. Sistemlerin çoðunda, short int veri türünden yaratýlan nesne
bellekte 2 byte'lýk bir alan kaplayacaktýr. iºaretli short int veri türünden bir nesne -32768 - +32767
aralýðýndaki tamsayý deðerlerini tutabilirken, iºaretsiz short türü söz konusu olduðýundan tutulabilecek
deðerler 0 - +65535 aralýðýnda olabilir.
iºaretli int (signed int) türü ve iºaretsiz int (unsigned int) türü :
iºaretli ve iºaretsiz int veri türünden bir nesne tanýmlandýðý zaman, nesnenin bellekte kaç byte yer
kaplayacaðý sistemden sisteme deðiºebilir. Çoðunlukla 16 bitlik sistemlerde, int veri , 32 bitlik sistemlerde ise
int veri türü 4 byte yer kaplamaktadýr.
16 bitlik sistem, 32 bitlik sistem ne anlama geliyor.
16 bitlik sistem demekle iºlemcinin yazmaç (register) uzunluðunun 16 bit oldugunu anlatýyoruz.
int veri türünün 2 byte uzunluðunda olduðu sistemlerde bu veri türünün sayý sýnýrlarý, iºaretli int türü için 32768 - +32767, iºaretsiz int veri türü için 0 - +65535 arasýnda olacaktýr.
iºaretli ve iºaretsiz long int veri türü (iºaretli uzun tamsayý türü - iºaretsiz
uzun tamsayý türü)
Bu türün ismini genellikle long int, ya da kýsaca long türü olarak telaffuz edeceðiz.
iºaretli ve iºaretsiz long int veri türünden biriyle tanýmlanan bir nesnenin bellekte kaç byte yer kaplayacaðý
sistemden sisteme deðiºebilir. Sistemlerin çoðunda, long int veri türünden yaratýlan nesne bellekte 4 byte'lýk
bir alan kaplayacaktýr. ݺaretli long int veri türünden bir nesne -2147483648 - +2147483647 aralýðýndaki
tamsayý deðerlerini tutabilirken, iºaretsiz long int türü söz konusu olduðýundan tutulabilecek deðerler 0 +4.294.967.296 aralýðýnda olur.
GERÇEK SAYI TÜRLERÝ
C dilinde gerçek sayý deðerlerini tutabilmek için 3 ayrý veri türü tanýmlanmýºtýr. Bunlar sýrasýyla, float, double
ve long double veri türleridir. Gerçek sayý veri türlerinin hepsi iºaretlidir. Yani gerçek sayý veri türleri içinde
hem pozitif hem de negatif deðerler tutulabilir. Gerçek sayýlarýn bellekte tutulmasý sistemden sisteme
deðiºebilen özellikler içerebilir. Ancak sistemlerin çoðunda IEEE 754 sayýlý standarda uyukmaktadýr.
Sistemlerin hemen hemen hepsinde float veri türünden bir nesne tanýmlandýðý zaman bellekte 4 byte yer
kaplayacaktýr. 4 byte'lýk yani 32 bitlik alana özel bir kodlama yapýlarak gerçek sayý deðeri tutulur. IEEE 754
sayýlý standartta 4 byte'lýk gerçek sayý formatý "single precision " (tek hassasiyet) olarak isimlendirilmiºtir.
Bu standartta 32 bitlik alan 3 bölüme ayrýlmýºtýr.
1 bitlik alan (sign bit): gerçek sayýnýn iºaret bilgisini yani pzoitif mi negatif mi olduðu bilgisini tutar.
8 bitlik alan (exponential part) :
23 bitlik alan (fraction part) : sayýnýn ondalýk kýsmýný tutar.
Sistemlerin hemen hemen hepsinde double veri türünden bir nesne tanýmlandýðý zaman bellekte 8 byte yer
kaplayacaktýr. Gerçek sayýlarýn bellekte tutulmasý sistemden sisteme deðiºebilen özellikler içerebilir. Ancak
sistemlerin çoðunda IEEE 754 sayýlý standarda uyulmaktadýr.
long double veri türünden bir nesne tanýmlandýðý zaman bellekte 10 byte yer kaplayacaktýr.
C dilinin doðal veri türlerine iliºkin bilgileri aºaðýda bir tablo ºeklinde veriyoruz:
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
26
Buy RoboPDF
VERÝ TÜRLERÝ
C DÝLÝNÝN ÖNCEDEN TANIMLANMIª
(DEFAULT ) VERÝ TÜRLERÝ
TAMSAYI TÜRLERÝ
(INTEGER TYPES)
TÜR Ý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
2
long int
unsigned long int
4
4
4
SINIR DEÐERLERÝ
-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
GERÇEK SAYI TÜRLERÝ
(FLOATING TYPES)
TÜR ÝSMÝ
UZUNLUK
(byte)
float
4
double
8
long double
10
SINIR DEÐERLERÝ
en küçük pozitif deðer
en büyük pozitif deðer
-38
1.17 x 10
3.40 x 1038
(6 basamak hassasiyet)
2.22 x 10-308
1.17 x 10-38
(15 basamak hassasiyet)
(15 basamak hassasiyet)
taºýnabilir deðil
Yukarýda verilen tablo sistemlerin çoðu için geçerli de olsa ANSI C standartlarýna göre yalnýzca aºaðýdaki
özellikler garanti altýna alýnmýºtýr:
char türü 1 byte uzunluðunda olmak zorundadýr.
short veri türünün uzunluðu int türünün uzunluðuna eºit ya da int türü uzunluðundan küçük olmalýdýr. Yani
short <= int
long veri türünün uzunluðu int türüne eºit ya da int türünden büyük olmak zorundadýr. Yani
long >= int
Derleyiciler genel olarak derlemeyi yapacaklarý sistemin özelliklerine göre int türünün uzunluðunu iºlemcinin
bir kelimesi kadar alýrlar. 16 bitlik bir iºlemci için yazýlan tipik bir uygulamada
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
27
Buy RoboPDF
4 . BÖLÜM :
char türü 1 byte
int türü 2 byte (iºlemcinin bir kelimesi kadar)
short türü 2 byte (short = int)
long türü 4 byte (long > int)
alýnabilir.
Yine 32 bitlik bir iºlemci için yazýlan tipik bir uygulamada
char türü 1 byte
int türü 4 byte (iºlemcinin bir kelimesi kadar)
short türü 2 byte (short < int)
long türü 4 byte (long = int)
alýnabilir.
C dilinin en çok kullanýlan veri türleri tamsaylar için int türü iken gerçek sayýlar için double veri türüdür. Peki
hangi durumlarda hangi veri türünü kullanmak gerekir. Bu sorunun cevabý olarak hazýr bir reçete vermek pek
mümkün deðil, zira kullanacaðýmýz bir nesne için tür seçerken bir çok faktör söz konusu olabilir, ama genel
olarak ºu bilgileri verebiliriz :
Gerçek sayýlarla yapýlan iºlemler tam sayýlarla yapýlan iºlemlere göre çok daha fazla yavaºtýr. Bunun nedeni
ºüphesiz gerçek sayýlarýn özel bir ºekilde belirli bir byte alanýna kodlanmasýdýr. Tamsayýlarýn kullanýlmasýnýn
yeterli olduðu durumlarda bir gerçek sayý türünün kullanýlmasý , çalýºan programýn hýzýnýn belirli ölçüde
yavaºlatýlmasý anlamýna gelecektir. Bir tamsayý türünün yeterli olmasý durumunda gerçek sayý türünün
kullanýlmasý programýn okunabilirliðininin de azalmasýna neden olacaktýr.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
28
Buy RoboPDF
BÝLDÝRÝM VE TANIMLAMA
5 . BÖLÜM : BÝLDÝRÝM VE TANIMLAMA
Progamlama dillerinin çoðunda nesneler kullanýlmadan önceye derleyiciye tanýtýlýrlar.
Nesnelerin kullanýlmalarýndan önce, özellikleri hakkýnda derleyiciye bilgi verme iºlemlerine
bildirim (declaration) denir. Bildirim iºlemi yoluyla, derleyiciler nesnelerin hangi özelliklere
sahip olduklarýný anlarlar ve böylece bu nesneler için bellekte uygun bir yer tahsisatý
yapabilirler. Yaratýlacak nesne hakkýnda derleyiciye verilecek en önemli bilgi ºüphesiz nesneye
iliºkin tür (type) bilgisidir.
C dilinde eðer yapýlan bir bildirim iºlemi, derleyicinin bellekte bir yer ayýrmasýna neden oluyorsa
bu iºleme tanýmlama (definition) denir. Tanýmlama nesne yaratan bir bildirimdir.
Her tanýmlama iºlem ayný zamanda bir bildirim iºlemidir ama her bildirim iºlemi bir tanýmlama
olmayabilir. Baºka bir deyiºle, tanýmlama nesne yaratan bir bildirim iºlemidir.
C dilinde bir deðiºkeni bildirimini yapmadan önce kullanmak derleme iºleminde hata (error)
oluºumuna yol açar.
Bir deðiºkenin derleyiciye tanýtýlmasý deðiºkenin türünün ve isminin derleyiciye bildirilmesidir
ki, derleyici bu bilgiye dayanarak deðiºken için bellekte ne kadar yer ayýracaðýný, deðiºkenin
için ayrýlan byte'lardaki 1 ve 0 larýn nasýl yorumlanacaðý bilgisini elde eder.
C Dilinde Bildirim ݺleminin Genel Biçimi
C programlama Dili'nde bildirim iºlemi aºaðýdaki ºekilde yapýlmaktadýr :
<tür> <nesne ismi> <;>
Burada noktalý virgül karakterine sonlandýrýcý karakter diyoruz. Noktalý virgül ayýraç türünden
bir atomdur ve C'de bütün ifadeler noktalý virgül ile birbirlerinden ayrýlýrlar.
a = x + 1; b = x + 2;
ifadelerinde bulunan noktalý virgüller bunlarýn ayrý birer ifade olduklarýný gösterirler. Eðer bir
tek noktalý virgül olsaydý derleyici iki ifadeyi tek bir ifade gibi yorumlayacaktý.
a = x + 1
b = x + 2;
Yukarýdaki ifade tek bir ifade gibi yorumlanýr ve derleyici buna bir anlam veremez.
Tür belirten anahtar sözcükler, C dilinin önceden tanýmlanmýº veri türlerine iliºkin anahtar
sözcüklerdir. Bu sözcükleri bildirim sentaksýnda kullanarak, daha önce öðrenmiº olduðumuz 11
temel veri türünden hangisinden deðiºken tanýmlamak istediðimizi derleyiciye bildirmiº
oluyoruz. C dilinin önceden tanýmlanmýº veri türlerine iliºkin, bilidirim iºleminde kullanýlabilecek
anahtar sözcükler ºunlardýr :
signed, unsigned, char, short, int, long, float, double
Bu sözcüklerin hepsi anahtar sözcük olduðundan küçük harf ile yazýlmalýdýr, C dilinin büyük
harf küçük har duyarlý (case sensitive) bir dil olduðunu hatýrlayalým. C dilinin tüm anahtar
sözcükleri küçük harf ile tanýmlanmýºtýr.
Tür belirten anahtar sözcükler aºaðýdaki tabloda listelenen seçeneklerden biri olmalýdýr. Köºeli
parantez içerisindeki ifadeler kullanýlmasý zorunlu olmayan, yani seçime baðlý olan anahtar
sözcükleri göstermektedir. Ayný satýrdaki tür belirten anahtar sözcükler tamamen ayný anlamda
kullanýlabilmektedir.
1
2
char
unsigned char
[signed ] char
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
29
Buy RoboPDF
5 . BÖLÜM :
3
4
5
6
7
8
9
10
11
short
unsigned short
int
unsigned int
long
unsigned long
float
double
long double
[signed] short
short [int]
[signed] int
unsigned
[signed] long
unsigned long [int]
signed
Yukarýdaki tablodan da görüldüðü
mümkündür.
char a;
int a;
signed char a;
signed int a;
signed a;
long [int]
[signed] short [int]
[signed] long [int]
gibi, belirli türleri birden fazla ºekilde ifade etmek
long a;
long int a;
signed long a;
signed long int a;
Yukarýda ayný kolon üzerindeki bildirimlerin hepsi ayný türden nesne yaratýr.
Bildirim iºleminde nesne ismi olarak, C dilinin isimlendirme kurallarýna uygun olarak seçilen
herhangi bir isim kullanýlabilir.
C dilinde isimlendirilenler (identifiers) kavramý 6 grubu içerir. Deðiºkenler (variable) bunlardan
yalnýzca bir tanesidir. Fonksiyonlar (functions), etiketler (labels), makrolar (macros), yapý ve
birlik isimleri (structure and union tags), enum sabitleri (enum constants) isimlerini
programcýlardan alýrlar.
C Dilinin Ýsimlendirme Kurallarý
Ýsimlendirmede yalnýzca 63 karakter kullanýlabilir.
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 yukarýda belirtilen karakterlerin dýºýnda baºka bir karakterin kullanýlmasý
derleme zamanýnda hata oluºumuna yol açar. (ömeðin boºluk karakterinin kullanýlmasý Türkçe
karakterlerin kullanýlmasý, +, -, /, *, & ya da $ karakterinin kullanýlmasý gibi).
Deðiºken isimleri rakam karakteriyle baºlayamaz. Rakam karakteri dýºýnda, yukarýda geçerli
herhangi bir karakterle baºlayabilir.
C'nin anahtar sözcükleri isimlendirme amacý ile kullanýlamaz.
Ýsimler boºluk içeremeyeceði için uygulamalarda genellikle boºluk hissi vermek için alttire
(underscore) karakteri kullanýlýr.
genel_katsayi_farki, square_total, number_of_cards gibi.
Baºka bir teknik de isimlendirmede her sözcüðün ilk harfini Büyük, diðer harfleri küçük
yazmaktýr.
GenelKatsayiFarki, SquareTotal, NumberOfCards gibi.
C dilinde yapýlan isimlendirmelerde, isimlerin maksimum uzunluðu tanýmlanmamýºtýr. Bu
derleyicilere göre deðiºebilir. Ancak bir çok derleyicide 32 sayýsý kullanýlmaktadýr. Eðer verilen
isim 32 karakterden daha fazla karakter içeriyorsa, derleyici bu ismi budar, yani yalnýzca ilk 32
karakterini algýlar.
C dili büyük harf küçük harf duyarlýðý olan bir dil olduðu için (case sensitive) isimlendirmelerde
de büyük harf ve küçük harfler farklý karakterler olarak ele alýnacaktýr :
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
30
Buy RoboPDF
BÝLDÝRÝM VE TANIMLAMA
var, Var, VAr, VAR, vAR, vaR deðiºkelerinin hepsi ayrý deðiºkenler olarak ele alýnacaktýr.
Bu noktalarýn hepsi C dilinin sentaksý açýsýndan, hata oluºumunu engellemek için zorunlu
durumlarý belirtmek için anlatýlmýºtýr.
Ýsimlendirme yazýlan programlarýn okunabilirliði açýsýndan da çok önemlidir. Kullanýlan isimlerin
legal olmalarýnýn dýºýnda, anlamlý olmalarýna, kodu okuyacak kiºiye bir fikir verecek ºekilde
seçilmelerine de dikkat edilmelidir.
Bildirim iºlemi noktalý virgül ile sonlandýrýlmalýdýr.
Bildirim Örnekleri
int x;
unsigned long int var;
double MFCS;
unsigned _result;
signed short total;
Tür belirten anahtar sözcüklerin yazýlmasýndan sonra ayný türe iliºkin birden fazla nesnenin
bildirimi, isimleri arasýna virgül koyularak yapýlabilir. Bildirim deyimi yine noktalý virgül ile
sonlandýrýlmalýdýr.
unsigned char ch1, ch2, ch3, ch4;
float FL1, Fl2;
unsigned total, subtotal;
int _vergi_katsayisi, vergi_matrahi;
Farklý türlere iliºkin bildirimler virgüllerle birbirinden ayrýlamaz.
long x, int y;
/* error */
signed ve unsigned sözcükleri tür belirten anahtar sözcük(ler) olmadan yalnýz baºlarýna
kullanýlabilirler. Bu durumda int türden bir deðiºkenin bildiriminin yapýldýðý kabul edilir:
signed x, y;
ile
signed int x, y;
tamamen ayný anlamdadýr. Yine
unsigned u;
ile
unsigned int u;
tamamen ayný anlamdadýr. Ancak bu tür bir bildirimi tavsiye etmiyoruz, standartlar komitesi
ileride bu özelliðin dilin kurallarýndan kaldýrýlabileceðini bildirmiºtir. (deprecated feature).
Bildirim iºleminde, tür belirten anahtar sözcük birden fazla ise bunlarýn yazým sýrasý önemli
deðildir, ama okunabilirlik açýsýndan önce iºaret belirten anahtar sözcüðün sonra tip belirten
anahtar sözcüðün kullanýlmasý gelenek haline gelmiºtir. Örneðin :
signed long int
signed int long
long signed int
long int signed
x;
x;
x;
x;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
31
Buy RoboPDF
5 . BÖLÜM :
int long signed x;
int signed long x;
hepsi geçerli bildirimlerdir. Ama yukarýdaki bildirimde, seçimlik olan anahtar sözcükler özellikle
kullanýlmak isteniyorsa 1. yazým biçimi okunabilirlik açýsýndan tercih edilmelidir.
Bildirimlerin Kaynak Kod Ýçinde Yapýlýº Yerleri
C dilinde genel olarak 3 yerde bildirim yapýlabilir :
1. Bloklarýn içinde
2. Tüm bloklarýn dýºýnda.
3. Fonksiyon parametre deðiºkeni olarak fonksiyon parantezlerinin içerisinde
Fonksiyon parametre parantezleri içerisinde yapýlan bildirimler, baºka bir sentaks kuralýna
uyarlar, bu bildirimler fonksiyonlar konusuna gelindiðinde detaylý olarak incelenecektir.
C dilinde eðer bildirim bloklarýn içinde yapýlacaksa, bildirim iºlemi bloklarýn ilk iºlemi olmak
zorundadýr. Baºka bir deyiºle bildirimlerden önce baºka bir ifade bulunmamalý ya da
bildirimden önce bir fonksiyon çaðýrýlmamalýdýr. (Aksi halde derleme zamaný sýrasýnda hata
oluºur.)
Bildirimin mutlaka ana bloðun baºýnda yapýlmasý gibi bir zorunluluk yoktur. Eðer içiçe bloklar
varsa içteki herhangi bir bloðun baºýnda da (o bloðun ilk iºlemi olacak ºekilde) bildirim
yapýlabilir. Örnekler :
{
int var1, var2;
char ch1, ch2, ch3;
var1 = 10;
float f;
/* error */
}
Yukarýdaki örnekte var1, var2, ch1, ch2, ch3 deðiºkenlerinin tanýmlanma yerleri doðrudur.
Ancak f deðiºkeni yanlýº yerde bildirilmiºtir. Çünkü bildirim iºleminden önce baºka bir iºlem
(deyim) yer almaktadýr. Bu durum derleme aºamasýnda hata oluºumuna neden olur.
Ayný program parçasý ºu ºekilde yazýlmýº olsaydý bir hata söz konusu olmazdý :
{
int var1, var2;
char ch1, ch2, ch3;
var1 = 10;
{ float f; }
}
bu durumda artýk f deðiºkeni de kendi bloðunun baºýnda (ilk iºlem olarak) tanýmlanmýºtýr.
Ýleride de göreceðimiz gibi C dilinde tek baºýna bir noktalý virgül, bir deyim oluºturur. C
sentaksýna göre oluºan bu deyim icra edilebilir bir deyimdir. Dolayýsýyla aºaðýdaki kod
parçasýnda y deðiºkeninin tanýmlamasý derleme zamanýnda hata oluºturacaktýr.
{
int x;;
int y; /* hata! ikinci sonlandýrýcý atom icra edilebilir bir deyim olarak
ele alýnýyor. */
}
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
32
Buy RoboPDF
BÝLDÝRÝM VE TANIMLAMA
Ayný ºekilde boº bir blok da C dilinde bir deyim gibi ele alýnýr. Bu yazým tamamen noktalý
virgülün (sonlandýrýcýnýn) yalnýz kullanýlmasýna eºdeðerdir. Dolayýsýyla aºaðýdaki kod parçasý da
hatalýdýr:
{
int x;
{ }
int y;
/* ERROR ! y deðiºkeninin bildirimi doðru yerde deðil. */
}
Bir ya da birden fazla deyimin de blok içine alýnmasý C dilinde bileºik deyim (compound
statement) ismini alýr ve bileºik deyimler de icra edilebilir deyim kategorisine girerler.
Dolayýsýyla aºaðýdaki kod parçasý da hatalýdýr.
{
{int x;}
int y;
/* ERROR */
}
(C++ dilinde blok içinde bildirimi yapýlan deðiºkenlerin, bloklarýn ilk iºlemleri olacak ºekilde
bildirilmeleri zorunlu deðildir. Yani C++ da deðiºkenler bloklarýn içinde herhangi bir yerde
bildirilebilirler.)
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
33
Buy RoboPDF
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
34
Buy RoboPDF
SABÝTLER
6 . BÖLÜM : SABÝTLER
Veriler ya nesnelerin içerisinde ya da doðrudan sabit biçiminde bulunurlar. Sabitler nesne
biçiminde olmayan, programcý tarafýndan doðrudan girilen
verilerdir. Sabitlerin sayýsal
deðerleri derleme zamanýnda tam olarak bilinmektedir. Örneðin :
x = y + z;
ifadesi bize a ve b içindeki sayýlarýn toplanacaðý ve c’ye aktarýlacaðýný anlatýr. Oysa
d = x
+ 10;
ifadesinde x deðiºkeni içinde saklanan deðer ile 10 sayýsý toplanmýºtýr. Burada 10 sayýsý
herhangi bir deðiºkenin içindeki deðer deðildir, doðrudan sayý biçiminde yazýlmýºtýr. Nesnelerin
türleri olduðu gibi sabitlerin de türleri vardýr. Nesnelerin türleri daha önce gördüðümüz gibi
bildirim yapýlýrken belirlenir. Sabitlerin türlerini ise derleyici, belirli kurallar dahilinde sabitlerin
yazýlýº biçimlerinden tespit eder. Sabitlerin türlerini bilmek zorundayýz, çünkü C dilinde
sabitler, deðiºkenler ve operatörler bir araya getirilerek (kombine edilerek) ifadeler
(expressions) oluºturulur. Daha sonra detaylý göreceðimiz gibi C dilinde ifadelerin de bir türü
vardýr ve ifadelerin türleri, içerdikleri sabit ve deðiºkenlerin türlerinden elde edilir. O halde
sabit türlerini detaylý olarak inceleyelim :
Tamsayý Sabitleri (integer constants)
ݺaretli Tamsayý Sabitleri (signed int) :
Bunlar tipik olarak int türden deðiºkenlerine atanan ve tamsayý biçiminde olan sabitlerdir,
yazýlýrken herhangi bir ek almazlar. C’de int türü sýnýrlarý içinde olan her tamsayý birer tamsayý
sabit (ya da int türden sabit ) olarak ele alýnýr.
-25
30000
25789
-320
0
sayýlarýnýn hepsi iºaretli tamsayý (signed int) sabiti olarak ele alýnýrlar, çünkü int türü sayý
sýnýrlarý içinde bulunuyorlar ve sonlarýnda herhangi bir ek bulunmuyor.
int türü sistem baðýmlýdýr ve int sabitleri de sistemden sisteme deðiºebilir.
sistem
DOS, WINDOWS 3.1
UNIX WINDOWS 95
2 byte
4 byte
uzunluk
sýnýr deðerler
- 32768, + 32767
-2147483648,
+2147483647
Örneðin 425000 Dos’ta int sabiti deðildir ama UNIX’te int sabittir.
Uzun Tamsayý Sabitleri(Long integer constants)
Uzun Tamsayý Sabitleri
ݺaretli Uzun Tamsayý Sabitleri (signed long)
long türden sabitler iki türlü ifade edilirler :
1. long int türünün sayý sýnýrlarý içinde bulunan bir sayýnýn sonuna L ya da l yazarak.
Bu durumda derleyiciler ilgili sayý int sýnýrlarý içinde olsa da long sabit olarak ele alýr.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
35
Buy RoboPDF
6 . BÖLÜM :
22345l long sabittir. çünkü sonunda l eki var.
0l, -23465L, 325l long sabitlerdir.
long sabit kullanýmýnda algýlanmasý daha kolay olduðu için L soneki tercih edilmelidir. l
soneki 1 rakamýyla görünüm açýsýndan çok benzediði için karýºýklýða neden olabilir.
2. int türün sayý sýnýrlarýný aºan fakat long int türü sayý sýnýrlarý içinde kalan her tamsayý
doðrudan long int türden sabit olarak ele alýnýr. Bu durum doðal olarak, DOS gibi int ve
long türlerinin birbirinden farklý olduðu sistemlerde anlamlýdýr.
Örneðin DOS’da
325000
-33333
1278902
long türden sabitlerdir. Oysa 32 bitlik sistemlerde long türünün uzunluðuyla int türün
uzunluðu ayný (4 byte) olduðu için bu sayýlar int sabiti olarak ele alýnacaktýr. Bu
sistemlerde yukarýdaki sayýlarý long sabit olarak ele almak istersek sonlarýna l ya da L
eklememiz gerekmektedir.
Karakter Sabitleri (char)
char sabitleri tipik olarak char türden nesnelere atanan sabitlerdir. (Böyle bir zorunluluk yok.)
char türden sabitler C dilinde dört ayrý biçimde bulunabilirler.
1. Ýstenilen bir karakter tek týrnak (single quote) içerisinde kullanýlýrsa char türden sabit
olarak ele alýnýr. Örnek :
'a'
'J'
'Ç'
':'
'8'
'<'
Yukarýdaki gösterimlerin herbiri birer char türden sabitidir.
C'de tek týrnak içerisinde belirtilen char sabitleri, aslýnda o karakterin karakter setindeki
(örneðin ASCII tablosundaki) sýra numarasýný gösteren bir tamsayýdýr.
{
char ch;
ch = 'a';
...
}
Bu örnekte aslýnda ch isimli char türden deðiºkene a karakterinin ASCII tablosundaki sýra
numarasý olan 97 sayýsý aktarýlmaktadýr. Tek týrnak içindeki karakter sabitlerini görünce
aslýnda onlarýn küçük birer tamsayý olduðunu bilmeliyiz. Çünkü bellekte karakter diye
birºey yoktur herºey ikilik sistemde 1 ve 0 lardan oluºan sayýlardýr. Yukarýdaki örnekte
istersek ch deðiºkenine aºaðýdaki gibi bir atama yapabiliriz:
ch = 'a' + 3;
Bu durumda ch deðiºkenine sayýsal olarak 100 deðeri atanacaktýr. Bu sayýya da ASCII
tablosundaki 'd' karakteri karºýlýk gelir.
2. Önceden tanýmlanmýº ters bölü karakter sabitleri (escape sequences)
Yukarýda tanýmlanan yöntemde ekrana basýlamayan yani ekranda görüntü oluºturmayan
(non printable) karakterleri ifade edemeyiz. Örneðin çan karakteri (çan sesi) ya da ters
boºluk (backspace) karakteri ekrana basýlamaz. Tek týrnak içindeki ters bölü (back slash)
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
36
Buy RoboPDF
SABÝTLER
karakterinden sonra yer alan bazý karakterler çok kullanýlan ancak basýlamayan bazý
karakterlerin yerlerini tutarlar. Bunlarýn listesi aºaðýda verilmiºtir:
Önceceden Tanýmlanmýº Ters Bölü 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'
Taným
NULL karakter
çan sesi (alert)
geri boºluk (back space)
tab karakteri (tab)
aºaðý satýr (new line)
düºey tab (vertical tab)
sayfa ileri (form feed)
satýr baºý (carriage return)
çift týrnak (double quote)
ters bölü (back slash)
ASCII No
0
7
8
9
10
11
12
13
34
92
kullanýlýºlarýna bir örnek :
{
char ch;
ch = '\a';
}
3. 16'lýk (hexadecimal) sayý sisteminde tanýmlanmýº karakter sabitleri
Tek týrnak içinde tersbölü ve x karakterlerinden sonra bir hex sayý verilirse bu ASCII
tablosundaki o sayýsal deðerin gösterdiði sýra numarasýndaki karaktere iºaret eden bir
karakter sabitidir.
'\x41'
'\xff'
'\x1C'
/* 41H numaralý ASCII karakteridir.
*/
/* FFH numaralý '2' karakter sabitidir. */
/* 1C numaralý ASCII karakter sabitidir. */
Küçük "x" yerine büyük harfle "X" yazmak C'nin ilk klasik versiyonunda kabul ediliyordu
ºimdi artýk geçerli deðildir. Örnek :
{
char harf;
harf = '\x41';
}
Yukarýdaki örnekte harf isimli char türden deðiºkene 41H ASCII sýra no.lu karakter
atanmýºtýr. Bu da desimal sistemdeki 65 sayýsýna eºittir. 65 sýra nolu ASCII karakteri 'A'
karakteridir. Dolayýsýyla harf isimli deðiºkene 'A' atanmýºtýr.
4. 8'lik (octal) sayý sistemde tanýmlanmýº karakter sabitleri
Tek týrnak içinde tersbölü karakterinden sonra bir oktal sayý yazýlýrsa bu kullanýlan karakter
setindeki o sayýsal deðerin gösterdiði sýra numarasýndaki karaktere iºaret eden bir karakter
sabitidir. Tek týrnak içindeki ters bölü karakterini izleyen sayý üç basamaktan uzun
olmamalýdýr. Sekizlik sayýlarýn yazýmýnda olduðu gibi sayýnýn baºýnda sýfýr olma zorunluluðu
yoktur. Bu ºekilde yazýlabilecek en büyük karakter sabiti '\377' dir.:
'\012'
'\16'
'\123'
/* 10 numaralý ASCII karakteri, Tam sayý deðeri 10 */
/* 14 numaralý ASCII karakteri. Tam sayý deðeri 14 */
/* 83 numaralý ASCII karakteri. Tam sayý deðeri 83 */
Program içinde kullanýmýna bir örnek:
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
37
Buy RoboPDF
6 . BÖLÜM :
{
char a, b;
a = '\xbc' ;
b = '\012';
/* hex sistemde tanýmlanmýº char sabit */
/* oktal sistemde tanýmlanmýº bir char sabit */
}
7 numaralý ASCII karakteri olan çan karakterini sabit olarak 3 biçimde de yazabiliriz.
'\x7'
'\07'
'\a'
/* hex gösterimli karakter sabiti */
/* oktal gösterimli karakter sabiti */
/* önceden belirlenmiº ters bölü karakter sabiti */
Burada tercih edilecek biçim son biçim olmalýdýr.Hem taºýnabilir bir biçimdir hem de
okunabilirliði daha iyidir. Baºka karakter setlerinde çan sesi karakteri 7 sýra numaralý
karakter olmayabilir ama önceden belirlenmiº ters bölü karakter sabiti ºeklinde ifade
edersek hangi sistem olursa olsun çan sesi karakterini verecektir. Ayrýca kodu okuyan kiºi
çan sesi karakterinin 7 numaralý ASCII karakteri olduðunu bilmeyebilir ama C programcýsý
olarak '\a' nýn çan sesi karakteri olduðunu bilecektir.
Karakter sabitleri konusunu kapatmadan önce karakter setleri konusunda da biraz bilgi
verelim:
Günümüzde kullanýlan en popüler karakter seti ASCII karakter setidir. ASCII (American
Standard Code for Information Interchange) sözcüklerinin baºharflerinden oluºan bir
kýsaltmadýr. ASCII setinin orjinal versiyonunda karakterler 7 bitlik bir alanda kodlanmýºtýr. Bazý
bilgisayarlar ise 8 bit alana geniºletilmiº ASCII seti kullanýrlar 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 kullanýrlar. Unicode ismi
verilen daha geliºtirilmiº bir karakter seti vardýr ki karakterler 2 byte alanda temsil edildikleri
için bu sette 65.536 farklý karakter yer alabilmektedir. Gelecekte bir çok makinanýn bu karakter
setini destekleyecek biçimde tasarlanacaðý düºünülmektedir.
ݺaretsiz türlere iliºkin sabitler
ݺaretsiz türlere iliºkin sabitler onlarýn iºaretli biçimlerinin sonuna u ya da U getirilmesiyle elde
edilirler.
-15000
15000U
1200L
1200Lu
(signed) int sabit
(unsigned) int sabit.
(signed) long sabit
(unsigned) long sabit.
Sonek olarak kullanýlan l, L, u ve U harflerinin sýrasý önemli deðildir.
123ul
123UL
123Lu
123lu
Yukarýdaki hepsi geçerli birer uzun tamsayý (unsigned long int) sabittir.
Tamsayý sabitlerinin 16'lýk ve 8'lik sistemlerde gösterilmesi
C'de tamsayý sabitleri (char, int, long) 10'luk sistemin yanýsýra 16'lýk ve 8'lik sistemlerde de
yazýlabilirler. Bu sayý sistemleriyle yazýlmýº tamsayý sabit türleri için yukarýda verilen kurallar
aynen geçerlidir. Çünkü bir sayýyý 16'lýk ya da 8'lik sistemde yazmakla onun yalnýzca
görünümünü deðiºtirmiº oluruz. Sabit türleri gösterim biçimiyle deðil nicelikle iliºkilidir. C
dilinde ikilik sayý sisteminde sabitlerin yazýlmasý söz konusu deðildir.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
38
Buy RoboPDF
SABÝTLER
16'lýk sistemde gösterim 0Xbbb.. biçimindedir. (b karakterleri basamaklarý gösteriyor, 9'dan
büyük basamak deðerleri için A, B, C, D, E, F karakterleri ya da a, b, c, d, e, f karakterleri
kullanýlabilir.
8'lik sistemde ise 0bbb.. biçimindedir. (nadir olarak kullanýlýr). Örnekler:
0x12
0X12L
0x1C205470
0x1934ul
01234
0567L
0777U
0452Lu
sayýsý hex gösterimli bir tamsayý (int) sabit.
sayýsý hex gösterimli bir uzun tamsayý (long) sabit.
hex gösterimli bir uzun tamsayý (long) sabit. Çünkü (DOS'da) tamsayý sayý
sýnýrýný aºmaktadýr.
hex gösterimli iºaretsiz uzun tamsayý (unsigned long) sabittir.
oktal gösterimli tamsayý (int) sabit
oktal gösterimli uzun tamsayý (long) sabit
oktal gösterimli iºaretsiz tamsayý (unsigned int) sabit
oktal gösterimli (unsigned long) sabit.
Sabitler yukarýda gösterildiði gibi her üç sayý sisteminde de yazýlabilir, hatta bir ifade içinde
kullanýlan sabitler farklý sayý sistemlerinde de yazýlmýº olabilirler, bu derleme zamanýnda error
oluºturacak bir neden olmayýp tamamen legaldir.
...
int x;
x = 0x1AC2 + 345 + 01234;
Gerçek Sayý Sabitleri (floating Constants)
1. float türden sabitler
Nokta içeren ve sonuna f ya da F getirilmiº sabitler float türden sabitler olarak ele alýnýrlar.
Örneðin:
1.31F
10.F
-2.456f
float türden sabitlerdir.
Not : Klasik C'de, yani C dilinin standartlaºtýrýlmasýndan önceki dönemde float türden bir
sabit elde etmek için, sayýnýn sonuna f eki almasý yeterliydi yani nokta içermesi
gerekmiyordu ama standartlarda yapýlan deðiºiklikle artýk float sabitlerin sonuna ek gelse
de mutlaka nokta içermeleri gerekiyor. Yani derleyiciler 3f ºeklinde bir yazýmý derleme
zamanýnda bir hata (error) mesajýyla bildiriyorlar.
2. double türden sabitler
Sonuna f ya da F eki almamýº nokta içeren sabitler ile float duyarlýðýný aºmýº sabitler
double sabitler olarak deðerlendirilirler. Örneðin :
-24.5
double türden sabittir.
3. long double türden sabitler
long double türden sabitler noktalý ya da üstel biçimdeki sayýlarýn sonuna l ya da L
getirilerek elde edilirler :
1.34L
10.2L
long double türden sabitlerdir.
Gerçek Sayý Sabitlerinin Üstel Biçimde Gösterilmesi
Gerçek sayý sabitleri üstel biçimde de ifade edilebilirler, bunun için sayýnýn sonuna e ya da E eki
getirilerek bir tamsayý yazýlýr. Bu, sayýnýn 10x gibi bir çarpanla çarpýldýðýný gösterir.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
39
Buy RoboPDF
6 . BÖLÜM :
2.3e+04f
1.74e-6F
8.e+9f
burada e 10'un kuveti anlamýna gelmektedir:
1.34E-2f ile 0.0134
-1.2E+2F ile 120.f
ayný sabitlerdir.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
40
Buy RoboPDF
FONKSÝYONLAR
7 . BÖLÜM : FONKSÝYONLAR
C'de alt programlara fonksiyon denir. Fonksiyon sözcüðü burada matematiksel anlamýyla deðil
diðer programlama dillerinde kullanýlan, "alt program", "prosedür", "subroutine" sözcüklerinin
karºýlýðý olarak kullanýlmaktadýr.
Fonksiyonlar C dilinin temel yapý taºlarýdýr. Çalýºtýrýlabilen bir C programý en az bir C
fonksiyonundan oluºur. Bir C programýnýn oluºturulmasýnda fonksiyon sayýsýnda bir kýsýtlama
yoktur.
Fonksiyonlarýn onlarý çaðýran fonksiyonlardan aldýklarý girdileri ve yine onlarý çaðýran
fonksiyonlara gönderdikleri çýktýlarý vardýr. Fonksiyonlarýn girdilerine aktüel parametreler
(actual parameters) ya da argumanlar (arguments) diyoruz. Fonksiyonlarýn çýktýlarýna geri
dönüº deðeri (return value) diyoruz.
Bir fonksiyon iki farklý amaçla kullanýlabilir :
1. Fonksiyon, icrasý süresince belli amaçlarý gerçekleºtirir. (Belli iºlemleri yapar)
2. Fonksiyon icrasý sonunda üreteceði bir deðeri kendisini çaðýran fonksiyona gönderebilir.
Fonksiyonlarýn Tanýmlanmasý ve Çaðýrýlmasý
Bir fonksiyonun ne iº yapacaðýnýn ve bu iºi nasýl yapacaðýnýn C dilinin sentaks kurallarýna uygun
olarak anlatýlmasýna o fonksiyonun tanýmlanmasý (definition) denir. Fonksiyon tanýmlamalarý
aºaðýda inceleneceði gibi birtakým sentaks kurallarýna tabidir.
Bir fonksiyonun çaðýrýlmasý ise o fonksiyonun yapacaðý iºi icraya davet edilmesi anlamýna gelir.
Fonksiyon çaðýrma ifadesi karºýlýðýnda derleyici, programýn akýºýný ilgili fonksiyonun kodunun
bulunduðu bölgeye aktaracak ºekilde bir kod üretir. Programýn akýºý fonksiyonun kodu içinde
akýp bu kodu bitirdiðinde, yani fonksiyon icra edildiðinde, programýn akýºý yine fonksiyonun
çaðýrýldýðý noktaya geri dönecektir. Fonksiyon çaðýrmaya iliºkin sentaks da yine aºaðýda
açýklanacaktýr.
Fonksiyonlarýn Geri Dönüº Deðerleri (return values)
Bir fonksiyonun yürütülmesi sonunda onu çaðýran fonksiyona dönüºünde gönderdiði deðere,
fonksiyonun geri dönüº deðeri (return value) denmektedir. Her fonksiyon bir geri dönüº deðeri
üretmek zorunda deðildir. Fonksiyonlarýn geri dönüº deðerleri farklý amaçlar için kullanýlabilir;
1. Bazý fonksiyonlar tek bir deðer elde etmek amacýyla tasarlanmýºlardýr. Elde ettikleri deðeri
de kendilerini çaðýran fonksiyonlara geri dönüº deðeri olarak iletirler. Örneðin:
y = pow(2, 3);
pow fonksiyonu standart bir C fonksiyonudur. Birinci parametresiyle belirtilen sayýnýn ikinci
parametresiyle belirtilen kuvvetini hesaplayarak, hesapladýðý sayýyý geri dönüº deðeri olarak
kendisini çaðýran fonksiyona iletir. Yukarýdaki örnekte 2 sayýsýnýn 3. kuvveti bu fonksiyon
yardýmýyla hesaplanarak bulunan deðer y deðiºkenine atanmýºtýr.
2. Bazý fonksiyonlarýn geri dönüº deðerleri fonksiyonun yürütülmesi sýrasýnda yapýlan
iºlemlerin baºarýsý hakkýnda bilgi verir. Yani bu tür fonksiyonlarýn geri dönüº deðerleri test
amacýyla kullanýlmaktadýr. Geri dönüº deðerleri yapýlmasý istenen iºlemin baºarýlý olup
olmamasý durumunu açýklar. Örneðin :
p = malloc(200);
ifadesiyle bellekte 200 byte uzunluðunda bir blok tahsis etmek isteyen programcý bu
iºlemin baºarýlý bir biçimde yerine getirilip getirilmediðini de test etmek zorundadýr. Hemen
arkasýndan p deðiºkeninin aldýðý deðeri kontrol edecek ve iºlemin baºarýsý hakkýnda bir
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
41
Buy RoboPDF
7 . BÖLÜM :
karara varacaktýr. Dolayýsýyla malloc fonksiyonunun geri dönüº deðeri, fonksiyonun
yapmasý gereken iºin baºarýlý bir ºekilde sonuçlanýp sonuçlanmadýðýný göstermektedir.
3. Bazý fonksiyonlar kendilerine gönderilen argumanlarý belirli bir kritere göre test ederler.
Ürettikleri geri dönüº deðerleri ise test sonucunu belirtir. Örneðin:
if (isalpha(ch)) {
...
}
Burada isalpha fonksiyonu arguman olarak gönderilen karakterin bir harf karakteri olup
olmadýðýný test eder. Eðer harf karakteriyse, isalpha fonksiyonu 0 dýºý bir deðere geri
dönecek, eðer harf karakteri deðilse 0 deðerine geri dönecektir. Çaðýran fonksiyonda da
geri dönüº deðerine göre farklý iºlemler yapýlabilecektir.
4. Bazý fonksiyonlar hem belli bir amacý gerçekleºtirirler hem de buna ek olarak amaçlarýný
tamamlayan bir geri dönüº deðeri üretirler. Örneðin :
x =
printf("Merhaba Dünya\n");
Burada printf fonksiyonu ekrana Merhaba Dünya yazýsýný yazmak için kullanýlmýºtýr. Ancak
ekrana yazdýðý karakter sayýsýný da geri dönüº deðeri olarak vermektedir.
Bir yazý içersinde bulunan belirli bir karakteri silecek bir fonksiyon tasarladýðýmýzý
düºünelim. Fonksiyon iºini bitirdikten sonra yazýdan kaç karakter silmiº olduðunu geri
dönüº deðeri ile çaðýrýldýðý yere bildirilebilir.
5. Bazen geri dönüº deðerlerine ihtiyaç duyulmaz. Örneðin yalnýzca ekraný silme amacýyla
tasarlanmýº olan bir fonksiyonun geri dönüº deðerine sahip olmasý gereksizdir.
clrscr();
clrscr fonksiyonu yalnýzca ekraný siler, böyle bir fonksiyonun geri dönüº deðerine ihtiyacý
yoktur.
Fonksiyonlarýn geri dönüº deðerlerinin de türleri söz konusudur. Fonksiyonlarýn geri dönüº
deðerleri herhangi bir türden olabilir. Geri dönüº deðerlerinin türleri fonksiyonlarýn
tanýmlanmasý sýrasýnda belirtilir.
Fonksiyonlarýn Tanýmlanmasý
Kendi yazdýðýmýz fonksiyonlar için tanýmlama (definition) terimini kullanýyoruz. C'de fonksiyon
tanýmlama iºleminin genel biçimi ºöyledir:
[Geri dönüº deðerinin türü] <fonksiyon ismi> ([parametreler])
{
...
...
}
Yukarýdaki gösterimde açýsal parantez içinde belirtilen ifadeler zorunlu olarak bulunmasý
gerekenleri köºeli parantez içinde belirtilen ifadeler ise bulunmasý zorunlu olmayan, isteðe
baðlý (optional) ifadeleri göstermektedir. Tanýmlanan fonksiyonlar en az bir blok içerirler. Bu
bloða fonksiyonun ana bloðu denir. Ana blok içinde istenildiði kadar içiçe blok yaratýlabilir.
Aºaðýdaki fonksiyon tanýmlamasýndan fonk1 fonksiyonunun parametre almadýðýný ve geri dönüº
deðerinin de double türden olduðunu anlýyoruz.
double fonk1()
{
...
...
Fonksiyonun ana bloðu
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
42
Buy RoboPDF
FONKSÝYONLAR
}
...
void Anahtar Sözcüðü
Bir fonksiyonun parametre deðiºkeni ya da geri dönüº deðeri olmak zorunda deðildir. Bir
fonksiyonun parametre deðiºkeni olmadýðý iki ºekilde belirtilebilir:
1. Fonksiyon parametre parantezinin içi boº býrakýlýr, yani buraya hiçbirºey yazýlmaz.
2. Fonksiyon parametre parantezinin içine void anahtar sözcüðü yazýlýr.
fonk()
{
...
}
fonk(void)
{
...
}
Yukarýdaki tanýmlamalar C'de ayný anlama gelmiyor. Fonksiyon prototipleri konusunu
öðrenirken bu iki tanýmlama arasýndaki farký da öðrenmiº olacaðýz. ªimdilik bu iki
tanýmlamanýn ayný anlama geldiðini ve fonksiyonun parametre almadýðýný belirttiklerini
varsayacaðýz.
Geri dönüº deðerine ihtiyaç duyulmadýðý durumlarda da geri dönüº deðerinin türü yerine void
anahtar sözcüðü yerleºtirilir. Örneðin:
void sample(void)
{
...
}
Yukarýda tanýmlanan sample fonksiyonu parametre almamakta ve bir geri dönüº deðeri de
üretmemektedir.
Fonksiyon tanýmlarken geri dönüº deðeri yazýlmayabilir. Bu durum geri dönüº türünün olmadýðý
anlamýna gelmez. Eðer geri dönüº deðeri yazýlmazsa, C derleyicileri tanýmlanan fonksiyonun int
türden bir geri dönüº deðerine sahip olduðunu varsayarlar. Örneðin :
sample2()
{
...
}
Tanýmlanan sample2 fonksiyonunun parametresi yoktur ama int türden bir geri dönüº deðeri
vardýr.
C dilinde fonksiyon içinde fonksiyon tanýmlanamaz!
Örneðin aºaðýdaki durum error oluºturur, çünkü sample2 fonksiyonu sample1 fonksiyonunun
içinde tanýmlanmýºtýr:
double sample1()
{
...
int sample2()
{
...
}
...
}
/* error */
tanýmlamanýn aºaðýdaki ºekilde yapýlmasý gerekirdi :
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
43
Buy RoboPDF
7 . BÖLÜM :
double sample1()
{
...
}
int sample2()
{
...
}
Fonksiyonlarýn Çaðýrýlmasý (function calls)
C dilinde fonksiyon çaðýrma operatörü olarak () kullanýlmaktadýr. Bir fonksiyon çaðýrýldýðý
zaman programýn akýºý fonksiyonu icra etmek üzere bellekte fonksiyonun kodunun bulunduðu
bölgeye atlar, fonksiyonun icra edilme iºlemi bittikten sonra da akýº tekrar çaðýran fonksiyonun
kalýnan yerinden devam eder.
Bir fonksiyonun geri dönüº deðeri varsa, fonksiyon çaðýrma ifadesi geri dönüº deðerini üretir.
Geri dönüº deðeri bir deðiºkene atanabileceði gibi doðrudan aritmetik iºlemlerde de
kullanýlabilir. Örneðin:
sonuc = hesapla();
Burada hesapla fonksiyonunun çaðýrýlma
deðiºkenine atanmaktadýr. Bir baºka deyiºle
ilgili fonksiyonun ürettiði (eðer üretiyorsa)
hesapla() fonksiyonu çaðýrýlacak daha sonra
deðeri sonuc deðiºkenine atanacaktýr.
ifadesiyle üretilen geri dönüº deðeri sonuc
bir fonksiyon çaðýrma ifadesinin ürettiði deðer,
geri dönüº deðeridir. Yukarýdaki örnekte önce
fonksiyonun icra edilmesiyle oluºan geri dönüº
Fonksiyonlarýn geri dönüº deðerleri nesne deðildir yani sol taraf deðeri (L value) deðildir. Yani
C dilinde aºaðýdaki gibi bir atama her zaman hata verecektir:
hesapla() = 5;
/* hata
(L value required) */
Fonksiyonlarýn geri dönüº deðerleri sað taraf deðeri (R value) dir.
sonuc = hesapla1() + hesapla2() + x + 10;
gibi bir ifade geçerlidir. çaðýrýlmýº olan hesapla1 ve hesapla2 fonksiyonlarý icra edilerek üretilen
geri dönüº deðerleri ile x deðiºkeni içindeki deðer ve 10 sabiti toplanacaktýr. Ýfadeden elde
edilen deðer sonuç deðiºkenine atanacaktýr.
Fonksiyonlar ancak tanýmlanmýº fonskiyonlarýn içerisinden çaðýrýlabilirler. Bloklarýn dýºýndan
fonksiyon çaðýrýlamaz.
Çaðýran fonksiyon ile çaðýrýlan fonksiyonun her ikisi de ayný amaç kod içerisinde bulunmak
zorunda deðildir. Çaðýran fonksiyon ile çaðýrýlan fonksiyon farklý amaç kodlar içerisinde de
bulunabilir. Çünkü derleme iºlemi sýrasýnda bir fonksiyonun çaðýrýldýðýný gören derleyici, amaç
kod içerisine (yani .obj içine) çaðýrýlan fonksiyonun adýný ve çaðýrýlýº biçimini yazmaktadýr.
Çaðýran fonksiyon ile çaðýrýlan fonksiyon arasýnda baðlantý kurma iºlemi, baðlama aºamasýnda,
baðlayýcý program (linker) tarafýndan yapýlýr.
Bu nedenle tanýmlanan bir fonksiyon içerisinde, var olmayan bir fonksiyon çaðýrýlsa bile
derleme aºamasýnda bir hata oluºmaz. Hata baðlama aºamasýnda oluºur. Çünkü baðlayýcý
çaðýrýlan fonksiyonu bulamayacaktýr.
Bütün C programlarý çalýºmaya main fonksiyonundan baºlar. Programýn baºladýðý nokta olma
dýºýnda main fonksiyonunun diðer fonksiyonlardan baºka hiçbir farký yoktur. main fonksiyonun
icrasý bitince program da sonlanýr. Bir C programýnýn çalýºabilmesi için mutlaka bir main
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
44
Buy RoboPDF
FONKSÝYONLAR
fonksiyonuna sahip olmasý gerekir. Eðer main fonksiyonu yoksa hata baðlama (linking)
aºamasýnda baðlayýcý program tarafýndan bildirilecektir.
Standart C Fonksiyonlarý
Standard C fonksiyonlarý, C dilinin standarlaºtýrýlmasýndan sonra, her derleyicide bulunmasý
zorunlu hale getirilmiº fonksiyonlardýr. Yani derleyicileri yazanlar mutlaka standard C
fonksiyonlarýný kendi derleyicilerinde tanýmlamak zorundadýrlar. Bu durum C dilinin
taºýnabilirliðini (portability) artýran ana faktörlerden biridir.
Bir fonksiyonun derleyiciyi yazanlar tarafýndan tanýmlanmýº ve derleyici paketine eklenmiº
olmasý, o fonksiyonun standart C fonksiyonu olduðu anlamýna gelmez. Derleyiciyi yazanlar
programcýnýn iºini kolaylaºtýrmak için çok çeºitli fonksiyonlarý yazarak derleyici paketlerine
eklerler. Ama bu tür fonksiyonlarýn kullanýlmasý durumunda, oluºturulan kaynak kodun baºka
bir derleyicide derlenebilmesi yönünde bir garanti yoktur, yani artýk kaynak kodun taºýnabilirliði
azalýr. Örneðin printf fonksiyonu standart bir C fonksiyonudur. Yani printf fonksiyonu her
derleyici paketinde ayný isimle bulunmak zorundadýr.
Standart C fonksiyonlarý özel kütüphanelerin içerisinde bulunurlar. Baºlýk dosyalarý içinde, yani
uzantýsý .h biçiminde olan dosyalarýn içinde standart C fonksiyonlarýnýn prototipleri
bulunmaktadýr. Fonksiyon prototipleri konusu ileride detaylý olarak incelenecektir.
Kütüphaneler (libraries) derlenmiº dosyalardan oluºur. DOS'da kütüphane dosyalarýnýn uzantýsý
.lib, UNIX'de ise .a (archive) biçimindedir. WINDOWS altýnda uzantýsý .dll biçiminde olan
dinamik kütüphaneler de bulunmaktadýr.
Derleyicileri yazanlar tarafýndan kaynak kodu yazýlmýº standart C fonksiyonlarý önce derlenerek
.obj haline getirilirler ve daha sonra ayný gruptaki diðer fonksiyonlarýn .obj halleriyle birlikte
kütüphane dosyalarýnýn içine yerleºtirilirler. Standart C fonksiyonlarý baðlama aºamasýnda,
baðlayýcý (linker) tarafýndan çalýºabilir (.exe) kod içerisine yazýlýrlar. Entegre çalýºan
derleyicilerde baðlayýcýlar amaç kod içerisinde bulamadýklarý fonksiyonlarý, yerleri önceden
belirlenmiº kütüphaneler içinde ararlar. Oysa komut satýrlý uyarlamalarýnda (command line
version) baðlayýcýlarýn hangi kütüphanelere bakacaðý komut satýrýnda belirtilir.
Standart fonksiyonlarýný kullanmak programlarýn taºýnabilirliðini artýrdýðý gibi proje geliºtirme
süresini de kýsaltýr. Bu yüzden iyi bir C programcýsýnýn C dilinin standart fonksiyonlarýný çok iyi
tanýmasý ve bu fonksiyonlarý yetkin bir ºekilde kullanabilmesi gerekmektedir.
Fonksiyonlarýn Geri Dönüº Deðerlerinin Oluºturulmasý
C dilinde fonksiyonlarýn geri dönüº deðerleri return anahtar sözcüðü ile oluºturulur. return
anahtar sözcüðünün bir baºka iºlevi de içinde bulunduðu fonksiyonu sonlandýrmasýdýr.
#include <stdio.h>
int sample(void)
{
int x = 10; int y = 20;
return x * y;
}
int main()
{
int c;
c = sample();
printf("c = %d\n", c);
return 0;
}
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
45
Buy RoboPDF
7 . BÖLÜM :
Yukarýdaki örnekteki sample fonksiyonunda return anahtar sözcüðünün yanýnda yer alan x * y
ifadesi sample fonksiyonunu sonlandýrmakta ve sample fonksiyonunun geri dönüº deðerini
oluºturmaktadýr. Fonksiyonun geri dönüº deðeri, main fonksiyonu içinde c deðiºkenine atanmýº
ve daha sonra standart C fonksiyonu olan printf ile c fonksiyonunun deðeri ekrana
yazdýrýlmýºtýr. fonksiyonun geri dönüº deðerini baºka bir deðiºkene atamadan aºaðýdaki ifade
ile de doðrudan ekrana yazdýrabilirdik :
printf("%d\n", sample());
Ayný örnekte main fonksiyonu içinde de bir return ifadesinin yer aldýðý görülmektedir. main de
bir fonksiyondur ve main fonksiyonunun da bir geri dönüº deðeri olabilir. main fonksiyonun
geri dönüº deðeri programýn icrasý bittikten sonra iºletim sistemine bildirilmektedir. main
fonksiyonunun baºýna bir geri dönüº deðer türü yazýlmazsa derleyiciler main fonksiyonunun
geri dönüº deðerinin int türden olduðunu varsayarlar. Özellikle yeni derleyiciler,
tanýmlamalarýnda bir geri dönüº deðeri üretecekleri belirtilen fonksiyonlarýnýn, return anahtar
sözcüðüyle geri dönüº deðeri üretmemelerini bir uyarý (warning) mesajý ile bildirirler. Borland
derleyicilerinde bu uyarý mesajý genellikle "warning : function should return a value..."
ºeklindedir. Bu uyarý mesajýný kesmek için iki yol vardýr:
1. main fonksiyonu da yukarýdaki örnekte olduðu gibi int türden bir geri dönüº deðeri üretir.
Geleneksel olarak bu deðer 0 ise programýn problemsiz bir ºekilde sonlandýrýldýðý anlamýna
gelir.
2. main fonksiyonunun baºýna void anahtar sözcüðü yazýlarak bu fonksiyonun bir geri dönüº
deðeri üretmeyeceði derleyiciye bildirilir. Bu durumda derleyici geri dönüº deðeri
beklemediði için bir uyarý mesajý göndermez.
return anahtar sözcüðünün kullanýlmasý zorunlu deðildir. Bir fonksiyon içinde return anahtar
sözcüðü kullanýlmamýºsa fonksiyonun icrasý, fonksiyonun ana bloðunun sonuna gelindiðinde
otomatik olarak biter. Tabi bu tür bir fonksiyon anlamlý bir ºekilde bir geri dönüº deðeri
üretemeyecektir. Bir geri dönüº deðerine sahip olacak ºekilde tanýmlanmýº fakat return ile geri
dönüº deðeri oluºturulmamýº fonksiyonlar rastgele bir deðer döndürürler.
return anahtar sözcüðünden sonra parantez kullanýlabilir ama parantez kullanýmý zorunlu
deðildir. Okunabilirlik açýsýndan özellikle uzun return ifadelerinde parantez kullanýmý tavsiye
edilmektedir.
return (a * b - c * d);
return 5;
/* return ifadesinin deðiºken içermesi bir zorunluluk deðildir. Bir fonksiyon
sabit bir deðerle de geri dönebilir. */
return sample();
Bu örnekte return anahtar sözcüðünden sonra bir fonksiyon çaðýrma ifadesi yer almaktadýr.
Bu durumda önce çaðýrýlan fonksiyon icra edilir, ve geri dönüº deðeri elde edilir, daha sonra
elde edilen geri dönüº deðeri tanýmlanmasý yapýlan fonksiyonun da geri dönüº deðeri
yapýlmaktadýr.
Geri dönüº deðeri olmayan fonksiyonlarda return anahtar
olmaksýzýn tek baºýna da kullanýlabilir :
sözcüðü yanýnda bir ifade
return;
Bu durumda return içinde yer aldýðý fonksiyonu geri dönüº deðerini oluºturmadan sonlandýrýr.
C dilinde fonksiyonlar yalnýzca bir geri dönüº deðeri üretebilirler. Bu da fonksiyonlarýn
kendilerini çaðýran fonksiyonlara ancak bir tane deðeri geri gönderebilmeleri anlamýna
gelmektedir. Ancak, fonksiyonlarýn birden fazla deðeri ya da bilgiyi kendilerini çaðýran
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
46
Buy RoboPDF
FONKSÝYONLAR
fonksiyonlara iletmeleri gerekiyorsa, C dilinde bunu saðlayacak baºka mekanizmalar vardýr ve
bu mekanizmalar ileride detaylý olarak incelenecektir.
Fonksiyonlarýn ürettiði geri dönüº deðerlerinin kullanýlmasý yönünde bir zorunluluk yoktur.
Örneðin fonk() fonksiyonu int türden bir deðeri geri dönen bir fonksiyon olsun:
a = fonk();
yukarýdaki ifadese fonk fonksiyonunun geri dönüº deðeri a deðiºkenine atanmaktadýr.
Dolayýsýyla biz bu fonksiyonu bir kez çaðýrmamýza karºýn artýk geri dönüº deðerini a
deðiºkeninede tuttuðumuz için, bu geri dönüº deðerine fonksiyonu tekrar çaðýrmadan
istediðimiz zaman ulaºabiliriz. Ancak:
fonk();
ºeklinde bir fonksiyon çaðýrma ifadesinde artýk geri dönüº deðeri bir deðiºkende
saklanmamakatdýr. Bu duruma geri dönüº deðerinin kullanýlmamasý denir. (discarded return
value).
Örneðin standart bir C fonksiyonu olan printf fonksiyonun da bir geri dönüº deðeri vardýr (printf
fonksiyonu ekrana bastýrýlan toplam karakter sayýsýna geri döner) ama bu geri dönüº deðeri
nadiren kullanýlýr.
Fonksiyon Parametre Deðiºkenlerinin Tanýmlanmasý
Bir fonksiyonun parametreleri ya da parametre deðiºkenleri fonksiyonlarýn kendilerini çaðýran
fonksiyonlardan aldýklarý girdileri tutan deðiºkenleridir. Bir fonksiyonun parametre sayýsý ve bu
parametrelerin türleri gibi bilgiler, fonksiyonlarýn tanýmlanmasý sýarsýnda derleyicilere
bildirilirler.
C dilinde fonksiyonlarýn tanýmlanmasýnda kullanýlan 2 temel biçim vardýr. Bu biçimler
birbirlerinden fonksiyon parametrelerinin derleyicilere tanýtýlma ºekli ile ayrýlýrlar.
Bu
biçimlerden birincisi eski biçim (old style) ikincisi ise yeni biçim (new style) olarak adlandýrýlýr.
Artýk eski biçim hemen hemen hiç kullanýlmamaktadýr, ama C standartlarýna göre halen
geçerliliðini korumaktadýr. Kullanýlmasý tavsiye edilen kesinlikle yeni biçimdir ancak eski
kodlarýn ya da eski kaynak kitaplarýn incelenmesi durumunda bunlarýn anlaºýlabilmesi için eski
biçimin de öðrenilmesi gerekmektedir.
Eski Biçim (old style)
Bu biçimde fonksiyonun parametre deðiºkenlerinin yalnýzca ismi fonksiyon parantezleri içinde
yazýlýr. (Eðer parametre deðiºkenleri birden fazla ise aralarýna virgül koyulur. Daha sonra alt
satýra geçilerek bu deðiºkenlerin bildirimi yapýlýr. Bu bildirimler daha önce öðrendiðimiz, C
dilinin bildirim kurallarýna uygun olarak yapýlýr. Örnek :
double alan(x, y)
int x, y;
{
return x * y;
}
Yukarýda tanýmlanan alan fonksiyonunun iki parametre deðiºkeni vardýr ve bu parametre
deðiºkenlerinin isimleri x ve y'dir. Her iki parametre deðiºkeni de int türdendir.
int sample (a, b, c)
int a;
double b;
long c;
{
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
47
Buy RoboPDF
7 . BÖLÜM :
}
...
Bu örnekte ise sample fonksiyonu üç parametre almaktadýr. Parametre deðiºkenlerinin isimleri
a, b ve c'dir. Ýsmi a olan parametre deðiºkeni int türden, b olaný double türden ve ismi c olaný
ise long türdendir.
Eski biçimin dezavantajý gereksiz yere uzun oluºudur. Çünkü fonksiyon parantezelerinin içinde
parametre deðiºkenlerinin isimi yer almakta sonra tekrar bu isimler alt satýrlarda yeniden
kullanýlarak bildirim yapýlmaktadýr.
Yeni Biçim (new style)
Yeni biçim eski biçime göre hem daha kýsadýr hem de okunabilmesi eski biçime göre çok daha
kolaydýr.
Yeni biçimde fonksiyon parametre deðiºkenlerinin bildirimi fonksiyon parantezelerinin içinde
yalnýzca bir kez yapýlmaktadýr. Bu biçimde fonksiyonun parantezlerinin içine parametre
deðiºkenin türü ve yanýna da ismi yazýlýr. Eðer birden fazla fonksiyon parametre deðiºkeni
varsa bunlar virgüllerle ayrýlýr ancak her defasýnda tür bilgisi yeniden yazýlýr . Örnek :
int sample (int x, int y)
{
...
}
int fonk(double x, int y)
{
...
}
Bu biçimde dikkat edilmesi gereken önemli nokta, fonksiyon parametre deðiºkenleri ayný
türden olsalar bile her defasýnda tür bilgisinin tekrar yazýlmasý zorunluluðudur. Örneðin :
int sample (double x, y)
{
...
}
/* error */
bildirimi hatalýdýr. Doðru tanýmlamanýn aºaðýdaki º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
fonksiyonlarýn biri tam olarak standarttýr ama diðer ikisi sistemlerin hemen hemen hepsinde
bulunmasýna karºýn tam olarak standart deðildir.
getchar Fonksiyonu
int getchar(void);
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
48
Buy RoboPDF
FONKSÝYONLAR
getchar standart bir C fonksiyonudur. Geri dönüº deðeri klavyeden alýnan karakterin ASCII
tablosundaki sýra numarasýný gösteren int türden bir sayýdýr. getchar fonskiyonu klavyeden
karakter almak için enter tuºuna ihtiyaç duyar.
Aºaðýda yazýlan programda önce klavyeden bir karakter alýnmýº daha sonra alýnan karakter ve
karakterin sayýsal karºýlýklarý ekrana yazdýrýlmýºtýr. (getchar fonksiyonunun geri dönüº deðeri
klavyede basýlan tuºa iliºkin karakterin sistemde kullanýlan karakter seti tablosundaki sýra
numarasýdýr.)
#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 çoðunda stdio.h dosyasýnda bir makro olarak tanýmlanmýºtýr. Makrolar
konusunu daha ileride inceleyeceðiz.
getch Fonksiyonu
int getch(void);
getchar fonksiyonu gibi bu fonksiyonda klavyede basýlan tuºun kullanýlan karakter setindeki
sýra numarasýyla geri döner. getchar fonksiyonundan iki farký vardýr.
1. Basýlan tuº ekranda görünmez.
2. Enter tuºuna ihtiyaç duymaz.
Yukarýda verilen programda getchar yerine getch yazarak programý çalýºtýrýrsanýz farký daha iyi
görebilirsiniz.
Tam olarak standardize edilmemiºtir ama neredeyse bütün sistemlerde bulunur. getch
fonksiyonu özellikle tuº bekleme ya da onaylama amacýyla kullanýlmaktadýr:
....
printf("devam için herhangi bir tuºa basýnýz...\n");
getch();
Burada basýlacak tuºun programcý açýsýndan bir önemi olmadýðý için fonksiyonun geri dönüº
deðeri kullanýlmamýºtýr.
getche Fonksiyonu
int getche(void);
getche Ýngilizce get char echo sözcüklerinden gelmektedir. getche fonksiyonu da basýlan tuºun
karakter setindeki sýra numarasýyla geri döner ve enter tuºuna gereksinim duymaz. Ama
basýlan tuºa iliºkin karakter ekranda görünür.
getchar
getch
getche
enter tuºuna ihtiyaç duyar
enter tuºuna ihtiyaç duymaz
enter tuºuna ihtiyaç duymaz
alýnan karakter ekranda görünür.
alýnan karakter ekranda görünmez
alýnan karakter ekranda görünür.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
49
Buy RoboPDF
7 . BÖLÜM :
Ekrana Bir Karakterin Görüntüsünü Yazan C Fonksiyonlarý
C dilinde ekrana karakter yazamakta iki fonksiyonun kullanýldýðý görülür :
putchar Fonksiyonu
int putchar(int ch);
putchar standart bir C fonksiyonudur. Bütün sistemlerde bulunmasý zorunludur. Parametresi
olan karakteri ekranda imlecin bulunduðu yere yazar. Örneðin:
#include <stdio.h>
main()
{
char ch;
}
ch = getchar();
putchar (ch);
return 0;
Burada putchar fonksiyonunun yaptýðý iºi printf fonksiyonuna da yaptýrabilirdik;
printf("%c", ch);
putchar(ch) ile tamamen ayný iºleve sahiptir.
putchar fonksiyonu ile '\n' karakterini yazdýrdýðýmýzda printf fonksiyonunda olduðu gibi imleç
sonraki satýrýn baºýna geçer. putchar fonksiyonu ekrana yazýlan karakterin ASCII karºýlýðý ile
geri dönmektedir.
putchar fonksiyonu derleyicilerin çoðunda stdio.h dosyasý içinde bir
tanýmlanmýºtýr. Makrolar konusunu ileriki derslerde detaylý olarak öðreneceðiz.
makro
olarak
putch Fonksiyonu
int putch(int ch);
putch standart bir C fonksiyonu deðildir. Dolayýsýyla sistemlerin hepsinde bulunmayabilir. Bu
fonksiyonun putchar fonksiyonundan tek farký '\n' karakterinin yazdýrýlmasý sýrasýnda ortaya
çýkar. putch, '\n" karakterine karºýlýk yalnýzca LF(line feed) (ASCII 10) karakterini yazmaktadýr.
Bu durum imlecin bulunduðu kolonu deðiºtirmeksizin aºaðý satýra geçmesine yol açar.
printf Fonksiyonu
Deðiºkenlerin içerisindeki deðerler aslýnda bellekte ikilik sistemde tutulmaktadýr. Bir deðiºkenin
içerisindeki deðerin ekrana, kaçlýk sistemde ve nasýl yazdýrýlacaðý programcýnýn isteðine
baðlýdýr. Deðiºkenlerin içerisindeki deðerlerin ekrana yazdýrýlmasýnda printf fonksiyonu
kullanýlýr. printf standart bir C fonksiyonudur.
printf aslýnda çok ayrýntýlý özelliklere sahip bir fonksiyondur. Burada yalnýzca temel özellikleri
görsel bir biçimde açýklanacaktýr. printf iki týrnak içerisindeki karakterleri ekrana yazar. Ancak
iki týrnak içinde gördüðü % karakterlerini ekrana yazmaz. printf fonksiyonu % karakterlerini
yanýndaki karakter ile birlikte format karakteri olarak yorumlar. Format karakterleri iki
týrnaktan sonra yazýlan parametrelerle birebir eºleºtirilir. Örnek:
int x, y;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
50
Buy RoboPDF
FONKSÝYONLAR
x = 125;
y = 200;
printf("x = %d\ny = %d\n", x, y);
printf fonksiyonunun yukarýdaki ºekilde çaðýrýlmasýyla x ve y deðiºkeni içindeki deðerler ekrana
onluk sistemde yazdýrýlacaktýr.
Format karakterleri yerine eºlenen deðiºkenlerin içerisindeki deðerler ekrana yazýlýr. Format
karakterleri sayýlarýn ekrana nasýl yazýlacaðýný belirtmekte kullanýlýr.
format
karakteri
Anlamý
%d
%ld
%x
%X
%lx
%u
%o
%f
%lf
%e
%c
%s
%lf
int türünü desimal sistemde yazar.
long türünü desimal sistemde yazar
unsigned int türünü hexadecimal sistemde yazar.
unsigned int türünü hexadecimal sistemde yazar.(semboller büyük harfle)
unsigned long türünü hexadecimal sistemde yazar.
unsigned int türünü decimal sistemde yazar.
unsigned int türünü oktal sistemde yazar.
float ve double türlerini desimal sistemde yazar.
double türünü desimal sistemde yazar.
gerçek sayýlarý üstel biçimde yazar.
char veya int türünü karakter görüntüsü olarak yazdýrýr.
string olarak yazdýrýr.
long double türünü desimal sistemde yazdýrýr.
Yukarýdaki tabloda görüldüðü gibi double türü hem %f format karakteri hem de %lf format
karakteri ile yazdýrýlabilmektedir. Ama %lf (okunabiliriliði artýrdýðý için) daha çok tercih
edilmektedir.
Yukarýdaki tabloya göre unsigned int türünden bir sayýyý aºaðýdaki ºekillerde yazdýrabiliriz :
unsigned int u;
printf("%u", u);
printf("%o, u);
printf("%x, u);
/* u sayýsýný 10'luk sistemde yazar */
/* u sayýsýný 8'lik sistemde yazar */
/* u sayýsýný 16'lýk sistemde yazar */
short bir sayýyý yazarken d o u ya da x karakterlerinden önce h karakterini kullanýyoruz :
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'lýk sistemde yazar */
long bir sayýyý yazarken d o u ya da x karakterlerinden önce l karakterini kullanýyoruz :
long int lo;
printf("%ld", lo);
/* 10'luk sistemde yazar */
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
51
Buy RoboPDF
7 . BÖLÜM :
unsigned long int unlo;
printf("%lu", unlo);
printf("%lo", unlo);
printf("%lx", unlo);
/* 10'luk sistemde yazar */
/* 8'lik sistemde yazar */
/* 16'lýk sistemde yazar */
Yukarýdaki bilgilerde unsigned bir tamsayýyý printf fonksiyonuyla 8'lik ya da 16'lýk sistemde
yazdýrabileceðimizi gördük. Peki signed bir tamsayýyý 8'lik ya da 16'lýk sistemde yazdýramaz
mýyýz? Yazdýrýrsak ne olur? Sözkonusu signed tamsayý pozitif olduðu sürece bir sorun olmaz.
Sayýnýn iºaret biri 0 olduðu için sayýnýn nicel büyüklüðünü etkilemez. Yani doðru sayý ekrana
yazar, ama sayý negatifse iºaret biti 1 demektir. Bu durumda ekrana yazýlacak sayýnýn iºaret
biti de nicel büyüklüðün bir parçasý olarak deðerlendirilerek yazýlýr. Yani yazýlan deðer doðru
olmayacaktýr.
% karakterinin yanýnda önceden belirlenmiº bir format karakteri yoksa , % karakterinin
yanýndaki karakter ekrana yazýlýr.
%% (%) karakterini yaz anlamýna gelir.
scanf Fonksiyonu
scanf fonksiyonu klavyeden her türlü bilginin giriºine olanak tanýyan standart bir C
fonksiyonudur. scanf fonksiyonu da printf fonksiyonu gibi aslýnda çok detaylý, geniº kullaným
özellikleri olan bir fonksiyondur. Ancak biz bu noktada scanf fonksiyonunu yüzeysel bir ºekilde
tanýyacaðýz.
scanf fonksiyonunun da birinci parametresi bir stringdir. Ancak bu string klavyeden alýnacak
bilgilere iliºkin format karakterlerini içerir. Bu format karakterleri önceden belirlenmiºtir ve %
karakterinin yanýnda yer alýrlar. scanf fonksiyonunun kullandýðý format karakterlerinin printf
fonksiyonunda kullanýlanlar ile ayný olduðunu söyleyebiliriz. Yalnýzca gerçek sayýlara iliºkin
format karakterlerinde önemli bir farklýlýk vardýr. printf fonksiyonu %f formatý ile hem float
hem de double türden verileri ekrana yazabilirken scanf fonksiyonu %f format karakterini
yalnýzca float türden veriler için kullanýr. double tür için scanf fonksiyonunun kullandýðý format
karakterleri %lf ºeklindedir. scanf fonksiyonunun format kýsmýnda format karakterlerinden
baºka bir ºey olmamalýdýr. printf fonksiyonu çift týrnak içindeki format karakterleri dýºýndaki
karakterleri ekrana yazýyordu, ancak scanf fonksiyonu format karakterleri dýºýnda string içine
yazýlan karakterleri ekrana basmaz, bu karakterler tamamen baºka anlama gelecektir. Bu
nedenle fonksiyonun nasýl çalýºtýðýný öðrenmeden bu bölgeye format karakterlerinden baºka bir
ºey koymayýnýz. Buraya konulacak bir boºluk bile farklý anlama gelmektedir.
int x, y;
scanf(“%d%d”, &x, &y);
Yukarýdaki örnekte x ve y sayýlarý için desimal sistemde klavyeden giriº yapýlmaktadýr. Giriº
arasýna istenildiði kadar boºluk karakteri konulabilir. Yani ilk sayýyý girdikten sonra ikinci sayýyý
SPACE, TAB ya da ENTER tuºuna bastýktan sonra girebilirsiniz. Örneðin:
5
60
biçiminde bir giriº geçerli olacaðý gibi;
5
60
biçiminde bir giriº de geçerlidir. scanf fonksiyonuna gönderilecek diðer argumanlar & operatörü
ile kullanýlmaktadýr. & bir gösterici operatörüdür. Bu operatörü göstericiler konusunda
öðreneceðiz.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
52
Buy RoboPDF
FONKSÝYONLAR
scanf fonksiyonunun yalnýzca giriº için kullanýlýr, ekrana yazmak için printf fonksiyonunu
kullanmamýz gerekir :
int number;
printf(“bir sayi giriniz : “);
scanf(“%d”, &number);
C++ dilinde bir fonksiyon tanýmlanmasýnda fonksiyonun geri dönüº deðerinin türü olarak void
anahtar sözcüðü yazýlmamýºsa, fonksiyon return anahtar sözcüðü kullanýlarak mutlaka bir geri
dönüº deðeri üretmelidir. Fonksiyonun geri dönüº deðeri üretmemesi durumunda derleme
zamanýnda hata oluºacaktýr. Yani C dilinde olduðu gibi rasgele bir deðer üretilmesi söz konusu
deðildir. Yine C++ dilinde geri dönüº deðeri üretecek bir fonksiyonun tanýmlanmasý içinde
return anahtar sözcüðü yalýn olarak kullanýlamaz. return anahtar sözcüðünün yanýnda
mutlaka bir ifade yer almalýdýr.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
53
Buy RoboPDF
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
Buy RoboPDF
NESNELERÝN FAALÝYET ALANLARI VE ÖMÜRLERÝ
8 . BÖLÜM : NESNELERÝN FAALÝYET ALANLARI VE
ÖMÜRLERÝ
Daha önce C dilinde nesnelerin 3 ayrý özelliðini görmüºtük. Bunlar nesnelerin isimleri, deðerleri
ve türleriydi. Nesnelerin C dili açýsýndan çok önem taºýyan iki özellikleri daha söz konusudur.
Bunlar tanýnabilirlik alanlarý (scope) ve ömürleridir (storage duration). Bu dersimizde bu iki
kavramý detaylý olarak inceleyeceðiz.
Tanýnabilirlik Alaný (scope / visibility)
Tanýnabilirlik alaný bir nesnenin ömrünü sürdürdüðü ve tanýnabildiði program aralýðýdýr. Burada
program aralýðý demekle kaynak kodu kastediyoruz. Dolayýsýyla tanýnabilirlik alaný doðrudan
kaynak kod ile ilgili bir kavramdýr, dolayýsýyla derleme zamanýna iliºkindir. C dilinde derleyici,
bildirimleri yapýlan deðiºkenlere kaynak kodun ancak belirli bölümlerinde ulaºýlabilir. Yani bir
deðiºkeni tanýmlýyor olmamýz o deðiºkene kodun istediðimiz
bir yerinde ulaºabilmemizi
saðlamaz. Tanýnabilirlik alanlarýný 2 ayrý grupta toplayabiliriz :
Blok tanýnabilirlik alaný. (Block scope): Bir deðiºkenin tanýmlandýktan sonra, derleyici
tarafýndan, yalnýzca belirli bir blok içinde tanýnabilmesidir.
Dosya tanýnabilirlik alaný (File scope) : Bir deðiºkenin tanýmlandýktan sonra tüm kaynak dosya
içinde, yani tanýmlanan tüm fonksiyonlarýn hepsinin içerisinde tanýnabilmesidir.
Deðiºkenleri de tanýnabilirlik alanlarýna göre ikiye ayýrabiliriz :
Yerel deðiºkenler (local variables)
Global deðiºkenler (global variables)
C dili için çok önemli olan bu deðiºken tiplerini ºimdi detaylý olarak inceleyeceðiz :
Yerel Deðiºkenler (local variables)
Bloklarýn içlerinde tanýmlanan deðiºkenlere yerel deðiºkenler denir. Hatýrlanacaðý gibi C dilinde
bloklarýn içlerinde tanýmlanan deðiºkenlerin tanýmlama iºlemleri blok içinde ilk iºlem olarak
yapýlmalýydý. (C++ dilinde böyle bir zorunluluk yoktur) Yerel deðiºkenler blok içlerinde
tanýmlanan deðiºkenlerdir, iç içe bloklarýn söz konusu olmasý durumunda hangi blok içerisinde
tanýmlanýrlarsa tanýmlansýnlar bunlarý yerel deðiºken olarak adlandýracaðýz. Yani yerel deðiºken
olmalarý için en dýº blok içinde tanýmlanmalarý gerekmiyor.
Yerel deðiºkenlerin tanýnabilirlik alaný blok tanýnabilirlik alanýdýr. Yani yerel deðiºkenlere
yalnýzca tanýmlandýklarý blok içinde ulaºýlabilir. Tanýmlandýklarý bloðun daha dýºýnda bir blok
içinde bu deðiºkenlere ulaºamayýz. Örnek :
main ()
{
float x;
...
...
{
int y;
...
...
{
int z;
...
...
}
}
}
x deðiºkeninin tanýnabilirlik alaný
y deðiºkeninin tanýnabilirlik alaný
z deðiºkeninin tanýnabilirlik
alaný
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
55
Buy RoboPDF
8 . BÖLÜM :
Yukarýdaki örnekte tanýmlanan deðiºkenlerden hepsi yerel deðiºkenlerdir. Çünkü x y z
deðiºkenleri bloklarýn içlerinde tanýmlanmýºlardýr. Bu deðiºkenlere yalnýzca tanýmlanmýº
olduklarý blok içinde ulaºabiliriz. Tanýmlandýklarý blok dýºýnda bunlara ulaºmaya çalýºmak
derleme aºamasýnda error ile neticelenecektir.
Dikkat etmemiz gereken bir nokta da ºudur : Yukarýdaki örnekte bu deðiºkenlerin hepsi yerel
deðiºkenler olduklarý için blok tanýnabilirlik alaný kuralýna uyarlar, ancak bu tanýnabilirlik
alanlarýnýn tamamen ayný olmasýný gerektirmez. Yukarýdaki ºekilden de görüldüðü gibi x
deðiºkeni en geniº tanýnabilirlik alanýna sahipken y deðiºkeni daha küçük ve z deðiºkeni de en
küçük tanýnabilirlik alanýna sahiptir.
Yukarýdaki örneði geniºletelim :
main ()
{
float x = 2.5;
printf(“x = %f\n”, x); /* LEGAL BU ALANDA x’E ULAªILABÝLÝR */
printf(“y = %d\n”, y); /* ERROR BU ALANDA y’YE ULAªILAMAZ. */
printf(“z = %ld\n”, z); /* ERROR BU ALANDA z’YE ULAªILAMAZ. */
{
int y = 1;
printf(“x = %f\n”, x);
printf(“y = %d\n”, y);
printf(“z = %ld\n”, z);
...
...
{
}
}
}
/* LEGAL BU ALANDA x’E ULAªILABÝLÝR */
/* LEGAL BU ALANDA y’E ULAªILABÝLÝR */
/* ERROR BU ALANDA z’YE ULAªILAMAZ. */
long z = 5;
printf(“x = %f\n”, x);
printf(“y = %d\n”, y);
printf(“z = %ld\n”, z);
/* LEGAL BU ALANDA x’E ULAªILABÝLÝR */
/* LEGAL BU ALANDA x’E ULAªILABÝLÝR */
/* LEGAL BU ALANDA x’E ULAªILABÝLÝR */
C dilinde ayný isimli birden fazla deðiºken tanýmlanabilmektedir. Genel kural ºudur: iki
deðiºkenin scoplarý (tanýnabilirlik alanlarý ayný ise) ayný isimi taºýyamazlar, ayný isim altýnda
tanýmlanmalarý derleme zamanýnda hata oluºturur. Ýki deðiºkenin scoplarýnýn ayný olup
olmadýklarý nasýl tespit edilecek? Standartlar bu durumu ºöyle açýklamaktadýr : Ýki deðiºkenin
scoplarý ayný kapanan küme parantezinde sonlanýyorsa, bu deðiºkenlerin scoplarý ayný
demektir.
{
}
float a;
int b;
double a;
{
int c;
...
}
/* error */
Yukarýdaki program parçasýnýn derlenmesi derleme aºamasýnda error ile neticelenir. Çünkü her
iki a deðiºkeninin de tanýnabilirlik alaný (scoplarý) aynýdýr. (scoplarý ayný küme paranteziyle
sonlanmaktadýr.)
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
56
Buy RoboPDF
NESNELERÝN FAALÝYET ALANLARI VE ÖMÜRLERÝ
Bu durum error oluºturmasaydý, yukarýdaki örnekte derleyici hangi a deðiºkeninin yazdýrýlmak
istendiðini nasýl anlayacaktý. Zira bu durum error ile engellenmeseydi printf fonksiyonunun
çaðýrýldýðý yerde her iki a deðiºkeni de tanýnabilir olacaktý.
C dilinde farklý tanýnabilirlik alanlarýna sahip birden fazla ayný isimli deðiºken tanýmlanabilir.
Çünkü derleyiciler için artýk bu deðiºkenlerin ayný isimli olmasý önemli deðildir. 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);
Yukarýdaki program parçasýnda bir hata bulunmamaktadýr. Çünkü her üç x deðiºkeninin de
tanýnabilirlik alanlarý birbirlerinden farklýdýr. Peki yukarýdaki örnekte içerideki bloklarda x ismini
kullandýðýmýzda derleyici hangi x deðiºkenini kast ettiðimizi nasýl anlayacak? Belirli bir kaynak
kod noktasýnda, ayný isimli birden fazla deðiºkenin faaliyet alaný (scope) içindeysek, deðiºken
ismini kullandýðýmýzda derleyici hangi deðiºkene ulaºacaktýr? Ayný isimli deðiºkenlere ulaºma
konusundaki kural ºudur : C dilinde daha dar faaliyet alanýna sahip deðiºken diðer ayný isimli
deðiºkenleri maskeler.
Konunun daha iyi anlaºýlmasý için bir kaç örnek daha verelim :
{
}
{
}
int a;
char ch;
long b;
double a, f; /* hata ayný tanýnabilirlik alanýnda ve ayný blok seviyesinde ayný isimli iki
deðiºken tanýmlanmýº */
int var1;
char var2;
{
int var1;
char var2;
}
Yukarýdaki kodda herhangi bir hata bulunmamaktadýr. var1 ve var2 deðiºkenlerinin ismi ikinci
kez içteki blokta tanýmlama iºleminde kullanýlmýºtýr ama artýk bu tanýnabilirlik alanýnda farklýlýk
yaratan ayrý bir bloktur, dolayýsýyla bir hata söz konusu deðildir.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
57
Buy RoboPDF
8 . BÖLÜM :
void sample1(void)
{
int k;
...
}
void sample2(void)
{
int k;
...
}
void sample3(void)
{
int k;
...
}
Yukarýdaki kodda da bir hata söz konusu deðildir. Zira her üç fonksiyonunda da k isimli bir
deðiºken tanýmlanmýº olsa da bunlarýn tanýnabilirlik alanlarý tamamen birbirinden farklýdýr.
Global Deðiºkenler (global variables)
C dilinde tüm bloklarýn dýºýnda da deðiºkenlerin tanýmlanabileceðini söylemiºtik. ݺte bütün
bloklarýn dýºýnda tanýmlanan deðiºkenler global deðiºkenler olarak isimlendirilirler.
Bütün bloklarýn dýºý kavramýný daha iyi anlamak için bir örnek verelim :
#include <stdio.h>
/* bu bölge tüm bloklarýn dýºý burada global bir deðiºken tanýmlanabilir. */
int sample1()
{
...
}
/* bu bölge tüm bloklarýn dýºý burada global bir deðiºken tanýmlanabilir. */
int sample2()
{
...
}
/* bu bölge tüm bloklarýn dýºý burada global bir deðiºken tanýmlanabilir. */
int sample 3()
{
...
}
/* bu bölge tüm bloklarýn dýºý burada global bir deðiºken tanýmlanabilir. */
main()
{
...
}
/* bu bölge tüm bloklarýn dýºý burada global bir deðiºken tanýmlanabilir. */
Yorum satýrlarýnýn bulunduðu yerler global deðiºkenlerin tanýmlanabileceði yerleri
göstermektedir. Bu bölgeler hiçbir fonksiyon içinde deðidir. Global deðiºkenler dosya
tanýnabilirlik alaný kuralýna uyarlar. Yani global deðiºkenler programýn her yerinde ve bütün
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
58
Buy RoboPDF
NESNELERÝN FAALÝYET ALANLARI VE ÖMÜRLERÝ
fonksiyonlarýn içinde tanýnabilirler. Burada bir noktayý gözden kaçýrmamak gerekir, bir deðiºken
yerel de olsa global de olsa tanýmlamasý yapýlmadan önce bu deðiºkene ulaºýlamaz. Derleme
iºleminin bir yönü vardýr ve bu yön kaynak kod içerisinde yukarýdan aºaðýya doðrudur. Bunu ºu
ºekilde de ifade edebiliriz : Global deðiºkenler tanýmlandýklarý noktadan sonra kaynak kod
içerisinde her yerde tanýnabilirler.
#include <stdio.h>
int y;
/* y bir global deðiºken tanýmlandýktan sonra her yerde tanýnabilir */
void sample(void)
{
y = 10;
}
/*baºka bir fonksiyondan da y global deðiºkenine ulaºýlabilir */
void main()
{
y = 20;
}
printf(“y = %d\n”, y);
sample();
printf(“y = %d\n”, y);
/* y = 20
/* y = 10
*/
*/
Yukarýdaki örnekte y deðiºkeni tüm bloklarýn dýºýnda tanýmlandýðý için (ya da hiçbir fonksiyonun
içinde tanýmlanmadýðý için) global deðiºkendir. y deðiºkeninin tanýnabilirlik alaný dosya
tanýnabilirlik alanýdýr. yani y deðiºkeni tanýmlandýktan sonra tüm fonksiyonlarýn içinde
tanýnabilir. Yukarýdaki programýn çalýºmasý main fonksiyonundan baºlayacaktýr. y global
deðiºkenine önce 20 deðeri atanmakta ve daha sonra bu deðer printf fonksiyonuyla ekrana
yazdýrýlmaktadýr. Daha sonra sample fonksiyonu çaðýrýlmýºtýr. sample fonksiyonu çaðýrýlýnca
kodun akýºý sample fonksiyonuna geçer. sample fonksiyonu içinde de y global deðiºkeni
tanýnabilir. sample fonksiyonunda global y deðiºkenine 10 deðeri atanmakta ve daha sonra bu
deðer yine printf fonksiyonuyla ekrana yazdýrýlmaktadýr.
Peki bir global deðiºkenle ayný isimli yerel bir deðiºken olabilir mi? Kesinlikle olabilir! Ýki
deðiºkenin tanýnabilirlik alanlarý ayný olmadýðý için bu durum bir hataya neden olmaz. Ayný
isimli hem global hem de yerel bir deðiºkene ulaºýlabilecek bir noktada, ulaºýlan yerel deðiºken
olacaktýr, çünkü daha önce de söylediðimiz gibi ayný tanýnabilirlik alanýnda birden fazla ayný
isimli deðiºken olmasý durumunda o alan içinde en dar tanýnabilirlik alanýna sahip olanýna
eriºilebilir. Aºaðýdaki kodu çok dikkatli inceleyelim :
int g= 20;
/* g global bir deðiºken */
void sample(void)
{
g = 100;
printf(“global g = %d\n”, g);
}
/* global g deðiºkenine atama yapýlýyor. */
/* global g yazdýrýlýyor. */
int main()
{
int g;
}
/* g yerel deðiºken */
g = 200;
printf(“yerel g = %d\n”, g);
sample();
printf(“yerel g = %d\n”, g);
return 0;
/* yerel olan g deðiºkenine atama yapýlýyor */
/* yerel g yazdýrýlýyor. */
/* yerel g yazdýrýlýyor. */
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
59
Buy RoboPDF
8 . BÖLÜM :
Fonksiyonlarýn kendileri de bütün bloklarýn baºlarýnda tanýmlandýklarýna göre global
nesnelerdir. Gerçekten de fonksiyonlar kaynak kodun heryerinden çaðýrýlabilirler. Ayný
tanýnabilirlik alanýna iliºkin ayný isimli birden fazla deðiºken olamayacaaðýna göre , ayný isme
sahip birden fazla fonksiyon da olamaz. (C++ dilinde ayný isimli fakat farklý parametrik yapýya
sahip fonksiyonlar tanýmlamak mümkündür.)
Programcýlarýn çoðu global deðiºkenleri mümkün olduðu kadar az kullanmak ister. Çünkü
global deðiºkenleri kullanan fonksiyonlar
baºka projelerde kullanýlamazlar. Kullanýldýklarý
projelerde de ayný global deðiºkenlerin tanýmlanmýº olmasý gerekecektir. Dolayýsýyla global
deðiºkenlere dayanýlarak yazýlan fonksiyonlarýn yeniden kullanýlabilirliði azalmaktadýr.
Parametre Deðiºkenleri (formal parameters)
Parametre deðiºkenleri, fonksiyon parametreleri olarak kullanýlan deðiºkenlerdir. Parametre
deðiºkenleri de blok tanýnabilirlik alaný kuralýna uyarlar. Yani parametresi olduklarý fonksiyonun
her yerinde tanýnabilirler. Fonksiyon parametre deðiºkeninin scope'u fonksiyonun ana bloðunun
kapanmasýyla sonlanacaktýr. Yani fonksiyon parametre deðiºkeninin tanýnabilirlik alaný
fonksiyonun ana bloðudur.
function(int a, double b)
{
/ *a ve b bu fonksiyonun heryerinde tanýnýr. */
}
Baºka bir örnek :
sample (int a, int b)
{
int a;
/* hata ayný tanýnýrlýk alaný içinde ve ayný seviyede ayný isimli deðiºken */
...
{
int b;
/* hata deðil tanýnabilirlik alanlarý farklý */
...
}
}
Bu örnekte fonksiyonun ana bloðunun baºýnda tanýmlanmýº olan a, “ayný tanýnabilirlik alanýnda
ayný blok seviyesinde ayný isimli birden fazla deðiºken olamaz “ kuralýna göre geçersizdir. Biri
parametre deðiºkeni biri yerel deðiºken olmasýna karºýn, her iki a deðiºkeni ayný tanýnabilirlik
alanýna sahiptir.
Nesnelerin Ömürleri (storage duration / lifespan)
Ömür, nesnelerin faaliyet gösterdiði zaman aralýðýný anlatmak için kullanýlan bir kavramdýr. Bir
kaynak kod içinde tanýmlanmýº nesnelerin hepsi program çalýºmaya baºladýðýnda ayný zamanda
yaratýlmazlar. Ömürleri bakýmýndan nesneleri iki gruba ayýrabiliriz :
1. Statik ömürlü nesneler (static objects)
2. Dinamik ömürlü nesneler (dynamic / automatic objects)
Statik Ömürlü Nesneler (static duration – static storage class)
Statik ömürlü nesneler, programýn çalýºmaya baºlamasýyla yaratýlýrlar, programýn çalýºmasý
bitene kadar varlýklarýný sürdürürler, yani bellekte yer kaplarlar. Statik nesneler genellikle
amaç kod (.obj) içerisine yazýlýrlar.
C dilinde statik ömürlü 3 nesne grubu vardýr :
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
60
Buy RoboPDF
NESNELERÝN FAALÝYET ALANLARI VE ÖMÜRLERÝ
global deðiºkenler
stringler(iki týrnak içerisndeki ifadeler)
statik yerel deðiºkenler
stringler ve statik yerel deðiºkenleri daha sonra inceleyeceðiz.
statik ömürlü nesneler olan global deðiºkenlerin ömürleri konusunda ºunlarý söyleyebiliriz :
Global deðiºkenler programýn çalýºmasý süresince yaºayan, yani programýn çalýºmasý süresince
bellekte yer iºgal eden deðiºkenlerdir.
Dinamik Ömürlü Nesneler
Dinamik ömürlü nesneler programýn çalýºmasýnýn belli bir zamanýnda yaratýlan ve belli süre
faaliyet gösterdikten sonra yok olan (ömürlerini tamamlayan) nesnelerdir. Bu tür nesnelerin
ömürleri programýn toplam çalýºma süresinden kýsadýr.
C dilinde dinamik ömürlü üç nense grubu vardýr :
yerel deðiºkenler
parametre deðiºkenleri
dinamik bellek fonksiyonlarý ile tahsisat yapýlarak yaratýlmýº nesneler
dinamik bellek fonskiyonlarý ile yaratýlmýº nesneleri daha sonra inceleyeceðiz.
Yerel deðiºkenler ve parametre deðiºkenleri dinamik ömürlü nesnelerdir. Tanýmlandýklarý
bloðun çalýºmasý baºladýðýnda yaratýlýrlar, bloðun çalýºmasý bitince yok olurlar (ömürleri sona
erer.) Tanýnabilirlik alanlarý kendi bloklarýnýn uzunluðu kadar olan yerel deðiºkenlerin ömürleri,
program akýºýºýnýn bu bloða gelmesiyle baºlar ve bloðun çalýºma süresi bitince de sona erer .
Örnek :
{
}
double x; /* programýn akýºý bu noktaya geldiðinde bellekte x için bir yer
blok içinde a yaºamaya devam ediyor.*/
...
/* programýn akýºý bloðun sonuna geldiðinde a deðiºkeninin de
ömrü sona eriyor */
ayrýlýyor. ve
Fonksiyonlarýn parametre deðiºkenleri de benzer biçimde fonksiyon çaðýrýldýðýnda yaratýlýrlar,
fonksiyon icrasý boyunca yaºarlar, fonksiyonun icrasý bitince yok olurlar.
Statik deðiºkenlerle dinamik deðiºkenler arasýnda ilk deðer verme(initialization) açýsýndan da
fark bulunmaktadýr. Statik olan global deðiºkenlere de yerel deðiºkenlerde olduðu gibi ilk deðer
verilebilir.
Ýlk deðer verilmemiº ya da bir atama yapýlmamýº bir yerel deðiºkenin içinde rasgele bir deðer
bulunur. Bu deðer o an bellekte o deðiºken için ayrýlmýº yerde bulunan
rasgele bir
sayýdýr.(garbage value). Oysa ilk deðer verilmemiº, ya da bir atama yapýlmamýº global
deðiºkenler içinde her zaman 0 deðeri vardýr. Yani bu deðiºkenler 0 deðeriyle baºlatýlýrlar.
Aºaðýdaki kýsa programý derleyerek çalýºtýrýnýz :
#include <stdio.h>
int globx;
int main()
{
int localy;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
61
Buy RoboPDF
8 . BÖLÜM :
printf("globx = %d\n", globx);
printf("localy = %d\n", localy);
}
return 0;
Yerel deðiºkenler ile global deðiºkenler arasýndaki baºka bir fark da, global deðiºkenlere ancak
sabit ifadeleriyle ilk deðer verilebilmesidir. Global deðiºkenlere ilk deðer verme iºleminde
kullanýlan ifadede (initializer), deðiºkenler ya da fonksiyon çaðýrma ifadeleri kullanýlamazlar,
ifade yalnýzca sabitlerden oluºmak zorundadýr. (C++ dilinde böyle bir zorunluluk
bulunmamaktadýr.)
Ancak yerel deðiºkenlere ilk deðer verilme iºleminde böyle bir kýstlama bulunmamaktadýr.
Örnek :
#include <stdio.h>
int x = 5;
int y = x + 5;
int z = funk();
/* legal */
/* error! ilk deðer verme iºleminde sabit ifadesi kullanýlmamýº */
/* error! ilk deðer verme iºleminde funksiyon çaðýrma ifadesi var */
int main()
{
int a = b;
int k = b - 2;
/* legal, k yerel deðiºken olduðu için ilk deðer verme ifadesi deðiºken
içerebilir */
int l = funk() /* legal, k yerel deðiºken olduðu için ilk deðer verme ifadesinde fonksiyon
çaðýrma i
fadesi bulunabilir. */
...
}
int funk()
{
...
}
Argumanlarýn Parametre Deðiºkenlerine Kopyalanmasý
C dilinde bir fonksiyonun parametre deðiºkenlerinin tanýmlandýklarý fonksiyon içinde her yerde
tanýnabildiklerini söylemiºtik. Peki bir fonksiyonun parametre deðiºkenleri ne iºe yararlar?
Bir fonksiyonun parametre deðiºkenleri, o fonksiyonun çaðýrýlma ifadesiyle kendisine
gönderilen argumanlarý tutacak olan yerel deðiºkenlerdir. Örnek :
fonk(int a)
{
.....
}
main()
{
int x;
....
fonk (x);
}
Yukarýdaki örnekte fonk fonksiyonu x argumaný ile çaðýrýldýðýnda, programýn akýºý fonk
fonksiyonunun kodunun bulunduðu yere sýçrar, fonk fonksiyonundaki a isimli parametre
deðiºkeni için bellekte bir yer ayrýlýr ve a parametre deðiºkenine x deðiºkeninin deðeri atanýr.
Yani
a = x;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
62
Buy RoboPDF
NESNELERÝN FAALÝYET ALANLARI VE ÖMÜRLERÝ
iºleminin otomatik olarak yapýldýðýný söyleyebiliriz.
Baºka 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 çaðýrýldýðýnda programýn akýºý bu fonksiyona geçmeden önce, x ve y
deðiºkenlerinin içinde bulunan deðerler add fonksiyonunun parametre deðiºkenleri olan a ve
b'ye kopyalanýrlar.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
63
Buy RoboPDF
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
Buy RoboPDF
9 . BÖLÜM :
9 . BÖLÜM : OPERATÖRLER
Operatörler nesneler veya sabitler üzerinde önceden tanýmlanmýº birtakým iºlemleri yapan
atomlardýr. Operatörler mikroiºlemcinin bir iºlem yapmasýna neden olurlar ve bu iºlem sonunda
da bir deðer üretilmesini saðlarlar. Programlama dillerinde tanýmlanmýº olan her bir operatör
en az bir makine komutuna karºýlýk gelmektedir.
Benzer iºlemleri yapmalarýna karºýlýk programlama dillerinde operatör atomlarý birbirlerinden
farklýlýk gösterebilir.
C programlama dilinde her ifade en az bir operatör içerir. (Sabitler, nesneler ve operatörlerin
kombinezonlarýna ifade denir.)
c=a*b/2+3
++x * y-a >= b
/* 4 operatör vardýr ifadedeki sýrasýyla =, *, /, + */
/* 3 operaör vardýr, ifadedeki sýrasýyla ++, *, -- */
/* 1 operatör vardýr. >= */
Her programlama dilinde operatörlerin birbirlerine göre önceliði söz konusudur. (Eðer öncelik
kavramý söz konusu olmasaydý, operatörlerin neden olacaðý iºlemlerin sonuçlarý makinadan
makinaya, derleyiciden derleyiciye farklý olurdu.)
C' de toplam 45 operatör vardýr, ve bu operatörler 15 ayrý öncelik seviyesinde yer alýr. (bakýnýz
operatör öncelik tablosu) . Bir öncelik seviyesinde eðer birden fazla operatör varsa bu
operatörlerin soldan saða mý saðdan sola mý öncelikle dikkate alýnacaðý da tanýmlanmalýdýr.
Buna öncelik yönü diyebiliriz. (associativity)
Bir sembol, birden fazla operatör olarak kullanýlýlabilmektedir. Örneðin * operatörü hem
çarpma hem de içerik alma operatörü (göstericilerle ilgili bir operatör) olarak kullanýlýr. Yine bir
C dilinde &(ampersand) hem bitsel ve hem de göstericilere iliºkin adres operatörü olarak
kullanýlmaktadýr. Operatör öncelik listesinde gördüðümüz operatörlerin çoðunu bu ders
tanýyacaðýz ama bir kýsmý ileriki derslerimizde yer alacak. (örneðin gösterici operatörleri)
Operatör Terminolojisi
Hem operatörler konusunun daha iyi anlaºýlmasý hem de ortak bir dil oluºturmak amacýyla
operatörler hakkýnda kullanabileceðimiz terimleri inceleyelim.
Operand
Operatörlerin deðer üzerinde iºlem yaptýklarý nesne veya sabitlere denir. C'de operatörleri
aldýklarý operand sayýsýna göre 3 gruba ayýrabiliriz.
1. Tek Operand Alan Operatörler (unary operators)
Örneðin ++ ve -- operatörleri unary operatörlerdir. (C dilinde unary operatörler
operatöröncelik tablosunun 2. seviyesinde bulunurlar.)
2. Ýki Operand Alan Operatörler. (binary operators)
Aritmetik iºlem operatörü olan + ve / operatörlerini örnek olarak verebiliriz.
3. Üç Operand Alan Operatör (ternary operator)
Çoðul kullanmýyoruz çünkü C'de 3 opererand olan tek bir operatör vardýr. (koºul operatörü
- conditional operator)
Operatörleri operandýnýn ya operandlarýnýn neresinde bulunduklarýna göre de gruplayabiliriz:
1. Sonek Konumundaki Operatörler (postfix operators)
Bu tip operatörler operandlarýnýn arkasýna getirilirler. Örneðin sonek ++ operatörü (x++)
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
65
Buy RoboPDF
9 . BÖLÜM :
2. Önek Konumundaki Operatörler (prefix operators)
Bu tip operatörler operandlarýnýn önüne getirilirler.
Örneðin önek ++ operatörü (++x)
C Dilinin Operatör Öncelik Tablosu
Seviye
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Operatör
()
[]
.
->
+
++
-~
!
*
&
sizeof
(tür)
*
/
%
+
<<
>>
<
>
<=
>=
==
!=
&
^
|
&&
||
?:
=
+=
-=
*=
/=
%=
<<=
>>=
&=
|=
^=
,
Taným
öncelik kazandýrma ve fonksiyon çaðýrma
index operatörü (subscript)
yapý elemanýna ulaºým (structure access)
yapý elemanýna gösterici ile ulaºým
iºaret operatörü (unary)
iºaret operatörü (unary)
1 artýrma (increment)
1 eksiltme (decrement)
bitsel deðil (bitwise not)
mantýksal deðil (logical not)
içerik operatörü (indirection)
adres operatörü (address of)
sizeof operatörü
tür dönüºtürme (type cast operator)
çarpma (multiplication)
bölme (division)
modulus (bölümden kalan)
toplama (addition)
çýkarma (suntraction)
bitsel sola kaydýrma (bitwise shift left)
bitsel saga kaydýrma (bitwise shift right)
küçüktür (less than)
büyüktür (greater than)
küçük eºittir (less than or equal)
büyük eºittir (greater than or equal)
eºittir (equal)
eºit deðildir (not equal to)
bitsel VE (bitwise AND)
bitsel EXOR (bitwise EXOR)
bitsel VEYA (bitwise OR)
mantýksal VE (logical AND)
mantýksal VEYA (logical OR)
koºul operatörü (conditional operator)
atama (assignement)
iºlemli atama (assignment addition)
iºlemli atama (assignment subtraction)
iºlemli atama (assignment multiplication)
iºlemli atama (assignment division)
iºlemli atama (assignment modulus)
iºlemli atama (assignment shift left)
iºlemli atama (assignment shift right)
iºlemli atama (assignment bitwise AND)
iºlemli atama (assignment bitwise OR)
iºlemli atama (assignment bitwise EXOR)
virgül operatörü (comma)
Öncelik Yönü
(associativity)
soldan saða
saðdan sola
soldan saða
soldan saða
soldan saða
soldan saða
soldan saða
soldan saða
soldan saða
soldan saða
soldan saða
soldan saða
saðdan sola
saðdan sola
3. Araek Konumundaki Operatörler (infix operators)
Bu tip operatörler operandlarýnýn aralarýna getirilirler.
Örneðin aritmetiksel toplama operatörü (x + y)
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
66
Buy RoboPDF
9 . BÖLÜM :
Son olarak operatörleri yaptýklarý iºlere göre sýnýflayalým :
1.
2.
3.
4.
5.
6.
Aritmetik operatörler (arithmetic operators)
Ýliºkisel operatörler (relational operators)
Mantýksal operatörler (logical operators)
Gösterici operatörleri (pointer operators)
Bitsel iºlem yapan operatörler (bitwise operators)
Özel amaçlý operatörler (special purpose operators)
Ýlk 3 grup programlama dillerinin hepsinde vardýr. Bitsel iºlem yapan operatörler ve gösterici
operatörleri yüksek seviyeli programla dillerinde genellikle bulunmazlar. Programlama
dillerinden çoðu, kendi
uygulama alanlarýnda kolaylýk saðlayacak birtakým özel amaçlý
operatörlere de sahip olabilir.
Operatörlerin Deðer Üretmeleri
Operatörlerin en önemli özellikleri bir deðer üretmeleridir. Operatörlerin ana iºlevi bir deðer
üretmeleridir. Programcý, bir ifade içinde operatörlerin ürettiði deðeri kullanýr ya da kullanmaz.
(discard edebiliriz.) Operatörlerin ürettiði deðeri nasýl kullanabiliriz:
Üretilen deðeri baºka bir deðiºkene aktararak kullanabiliriz.
x = y + z;
Yukarýdaki örnekte y + z ifadesinin deðer, yani + operatörünün ürettiði deðer x deðiºkenine
aktarýlmaktadýr.
Üretilen deðeri baºka bir fonksiyona arguman olarak gönderebiliriz.
func(y + z);
Yukarýdaki örnekte func fonksiyonuna arguman olarak y + z ifadesinin deðeri gönderilmektedir.
(Yani + operatörünün ürettiði deðer)
Üretilen deðeri return anahtar
belirlenmesinde kullanabiliriz.
sözcüðü
ile
fonksiyonlarýn
geri
dönüº
deðerlerinin
int sample(void)
{
...
return (y + z)
}
yukarýda sample fonksiyonunun geri dönüº deðeri y + z ifadesinin deðeridir. (Yani +
operatörünün ürettiði deðer)
Operatörlerin elde ettiði deðerin hiç kullanýlmamasý C sentaksý açýsýndan bir hataya neden
olmaz. Ancak böyle durumlarda derleyiciler bir uyarý mesajý vererek programcýyý uyarýrlar.
Örneðin :
int x = 20;
int y = 10;
...
x + y;
Yukarýdaki ifadede + operatörü bir deðer üretir. (+ operatörünün ürettiði deðer operandlarýnýn
toplamý deðeri, yani 20 deðeridir.) Ancak bu deðer hiçbir ºekilde kullanýlmamýºtýr. Derleyici
böyle bir iºlemin büyük ihtimalle yanlýºlýkla yapýldýðýný düºünecek ve bir uyarý mesajý
verecektir. Borland derleyicilerinde verilen uyarý mesajý ºu ºekildedir :
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
67
Buy RoboPDF
9 . BÖLÜM :
warning : "code has no effect!"
Daha önce belirttiðimiz gibi C dilinde ifadelerin türleri ve deðerleri söz konusudur. Bir ifadenin
deðerini derleyici ºu ºekilde tespit eder : Ýfade içindeki operatörler öncelik sýralarýna göre deðer
üretirler, ve ürettikleri deðerler, ifade içindeki önceliði daha az olan operatörlere operand
olarak aktarýlýr. Bu iºlemin sonunda tek bir deðer elde edilir ki bu da ifadenin deðeridir.
int x = 10;
int y = 3;
printf("%d\n", x % y / 2 + 7 && !x || y);
Yukarýdaki kod parçasýnda printf fonksiyonu çaðýrýmýyla x % y / 2 + 7 && !x || y ifadesinin
deðeri yazdýrýlmaktadýr. Yazdýrýlacak deðer nedir? ifade içindeki operatörler sýrayla deðer
üretecek ve üretilen deðerler öncelik sýrasýna göre, deðer üretecek operatörlere operand
olacaktýr. En son kalan deðer ise ifadenin deðeri, yani ekrana yazdýrýlan deðer olacaktýr.
Operatörlerin Yan Etkileri (side effect of operators)
C dilinde operatörlerin ana iºlevleri, bir deðer üretmeleridir. Ancak bazý operatörler operandý
olan nesnelerin deðerlerini deðiºtirirler. Yani bu nesnelerin bellekteki yerlerine yeni bir deðer
yazýlmasýna neden olurlar. Bir operatörün kendilerine operand olan nesnenin deðerlerini
deðiºtirmesine operatörün yan etkisi diyeceðiz. Yan etki, bellekte yapýlan eðer deðiºikliði olarak
tanýmlanmaktadýr. Örneðin atama operatörünün, ++ ve -- operatörlerinin yan etkileri söz
konusudur.
Operatörler Üzerindeki Kýsýtlamalar
Programlama dilinin tasarýmýnda, bazý operatörlerin kullanýlmalarýyla ilgili birtakým kýsýtlamalar
söz konusu olabilir. Örneðin ++ operatörünün kullanýmýnda, operandýn nesne gösteren bir ifade
olmasý gibi bir kýsýtlama söz konusudur. Eðer operand olan ifade bir nesne göstermiyorsa, yani
sol taraf deðeri deðilse, derleme zamanýnda hata oluºacaktýr.
Kýsýtlama operatörün operand ya da operandlarýnýn türleriyle de ilgili olabilir. Örneðin %
operatörünün operandlarýnýn tamsayý türlerinden birine ait olmasý gerekmektedir. %
operatörünün operandlarý gerçek sayý türlerinden birine ait olamaz. Operandýn gerçek sayý
türlerinden birinden olmasý durumunda derleme zamanýnda hata oluºacaktýr.
Operatörlerin Detaylý Olarak Ýncelenmesi
Aritmetik Operatörler
Aritmetik operatörler dört iºlemlerle ilgili iºlem yapan operatörlerdir.
+ ve - Operatörleri. (toplama ve çýkarma operatörleri)
Ýki operand alan araek operatörlerdir. (binary infix) Diðer bütün programlama dillerinde
olduklarý gibi operandlarýnýn toplamýný ve farkýný almak için kullanýrlar. Yani ürettikleri deðer,
operandlarýnýn toplamý ya da farký deðerleridir. Operandlarý üzerinde herhangi bir kýsýtlama
yoktur. Öncelik tablosundan da görüleceði gibi genel öncelik tablosunun 4. sýrasýnda yer alýrlar
ve öncelik yönleri soldan saðadýr (left associative). Yan etkileri yoktur, yani operandlarýnýn
bellekte sahip olduklarý deðerleri deðiºtirmezler.
Toplama ve çýkarma operatörleri olan + ve – operatörlerini tek operand alan + ve –
operatörleriyle karýºtýrmamak gerekir.
ݺaret Operatörü Olan – ve + Operatörleri
Bu operatörler unary prefix (tek operand alan önek konumundaki) operatörlerdir. - operatörü
operandý olan ifadenin deðerinin ters iºaretlisini üretir. Unary prefix – operatörünün ürettiði bir
nesne deðil bir deðerdir. Aºaðýdaki ifade matematiksel olarak doðru olmasýna karºýn C dili
açýsýndan hatalýdýr, derleme zamanýnda hata (error) oluºumuna neden olur:
int x;
-x = 5;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
68
Buy RoboPDF
9 . BÖLÜM :
x bir nesne olmasýna karºý –x ifadesi bir nesne deðil, x nesnesinin deðerinin ters iºaretlisi olan
deðerdir. Dolayýsýyla bir sol taraf deðeri deðildir ve bu ifadeye bir atama yapýlamaz.
+ operatörü yalnýzca sentaks açýsýndan C diline ilave edilmiº bir operatördür. Unary prefix bir
operand olarak derleyici tarafýndan ele alýnýr. Operandý olan ifade üzerinde herhangi bir etkisi
olmaz.
Unary prefix olan – ve + operatörleri operatör öncelik tablosunun 2. seviyesinde bulunurlar ve
öncelik yönleri saðdan sola doðrudur. Aºaðýdaki ifadeyi ele alalým :
int x = 5;
int y = -2;
-x - -y;
Yukarýdaki ifadede 3 operatör bulunmaktadýr. Sýrasýyla unary prefix – operatörü, binary infix
çýkarma operatörü ve yine unary prefix - operatörü. Ýfadenin deðerinin hesaplanmasýnda
operatör önceliklerine göre hareket edilecektir. unary prefix olan – operatörü 2. öncelik
seviyesinde olduðu için binary infix olan çýkarma operatörüne göre daha yüksek önceliklidir, ve
kendi içinde öncelik yönü saðdan soladýr. Önce –y ifadesi deðer üretir. Üretilen deðer 2
olacaktýr. daha sonra –x ifadesi deðer üretir. Üretilen deðer –5 olacaktýr. üretilen bu deðerler
çýkarma operatörüne operand olurlar ve ana ifadenin deðeri –5 – 2 yani –7 deðeri olarak
hesaplanýr.
* ve / Operatörleri
Ýki operand alan araek operatörlerdir. (binary infix) * operatörü operandlarý çarpmak / ise
operandlarý bölmek amacýyla kullanýlýr. Yani üretilen deðer operandlarýnýn çarpým ya da bölüm
deðerleridir. Operandlarý herhangi bir türden olabilir. Öncelik tablosunda görülebileceði gibi,
genel öncelik tablosunun 3. sýrasýnda bulunurlar. Öncelik yönleri soldan saðadýr. Her iki
operatörün de bir yan etkisi yoktur.
/ operatörünün kullanýmýnda dikkatli olmak gerekir. Eðer her iki operand da tamsayý
türlerindense operatörün bulunduðu ifadenin türü de ayný tamsayý türünden olacaktýr. (Bu
konuya ileride detaylý deðineceðiz.)
C programlama dilinde * sembolü ayný zamanda bir gösterici operatörü olarak da kullanýlýr.
Ama ayný sembol kullanýlmasýna karºýn bu iki operatör hiçbir zaman birbirine karýºmaz çünkü
aritmetik çarpma operatörü olarak kullanýldýðýnda binary infix durumundadýr, ama gösterici
operatörü olarak kullanýldýðýnda unary prefix dir.
% (modulus) Operatörü
Ýki operand alan araek bir operaötördür. (binary infix) Operatörlerin her ikisinin de türü de
tamsayý türlerinden (char, short, int, long) biri olmak zorundadýr. (Deðilse bu durum derleme
zamanýnda error ile neticelenir.) Ürettiði deðer sol tarafýndaki operandýn sað tarafýndaki
operanda bölümünden kalanýdýr. Operatörün yan etkisi yoktur. Örneðin:
c = 15 % 4;
/* burada c'ye 3 deðeri atanacaktýr */
int c = 13 - 3 * 4 + 8 / 3 - 5 % 2;
Burada c'ye 2 deðeri atanacaktýr. Çünkü iºlem ºu ºekilde yapýlmaktadýr:
c = 13 - (3 * 4) + (8 / 3) - (5 % 2)
c = 13 - 12 + 2 - 1;
c = 2;
Artýrma ++ ve Eksiltme -- Operatörleri (increment and decrement operators)
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
69
Buy RoboPDF
9 . BÖLÜM :
Artýrma (++) ve eksiltme (--) operatörleri C dilinde en çok kullanýlan operatörlerdendir. Tek
operand alýrlar. Önek ya da sonek durumunda bulunabilirler. ++ operatörü operandý olan
deðiºkenin içeriðini 1 artýrmak –- operatörü de operandý olan deðiºkenin içeriðini 1 eksiltmek
için kullanýlýr. Dolayýsýyla yan etkileri söz konusudur. Operandlarý olan nesnenin bellekteki
deðerini deðiºtirirler. Bu iki operatör de diðer aritmetik operatörlerden daha yüksek önceliðe
sahiptir. Operatör öncelik tablosunun 2. seviyesinde bulunurlar ve öncelik yönleri saðdan
soladýr. (right associative)
Yalýn olarak kullanýldýklarýnda (baºka hiçbir operatör olmaksýzýn) önek ya da sonek durumlarý
arasýnda hiçbir fark yoktur. ++ bir artýr ve –- bir eksilt anlamýna gelir.
++c ve c++ ifadeleri tamamen birbirine denk olup c = c + 1 anlamýna gelirler.
--c ve c— ifadeleri tamamen birbirine denk olup c = c – 1 anlamýna gelirler.
Diðer operatörlerle birlikte kullanýldýklarýnda (örneðin atama operatörleriyle) önek ve sonek
biçimleri arasýnda farklýlýk vardýr :
Önek durumunda kullanýldýðýnda operatörün ürettiði deðer artýrma/eksiltme yapýldýktan sonraki
deðerdir. Yani operandýn artýrýlmýº ya da azaltýlmýº deðeridir. Sonek durumunda ise operatörün
ürettiði deðer artýrma / eksiltme yapýlmadan önceki deðerdir. Yani operandý olan nesnenin
artýrýlmamýº ya da azaltýlmamýº deðeridir. Operandýn deðeri ifadenin tümü deðerlendirildikten
sonra artýrýlacak ya da eksiltilecektir.
x = 10;
y = ++x;
Bu durumda:
++x  11
ve y = 11 deðeri atanýr..
x = 10;
y = x++;
y = 10;
++x  11
Aºaðýdaki 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;
Yukarýdaki birinci printf ifadesi ekrana 11 11 yazdýrýrken ikinci printf ifadesi 11 10 yazdýrýr.
Bir örnek :
x = 10;
y = 5;
z = x++ % 4 * --y;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
70
Buy RoboPDF
9 . BÖLÜM :
--y 4
10 % 4  2
2*48
z=8
x++ 11
Bir örnek daha:
c = 20;
d = 10;
a = b = d + c--;
ݺlem sýrasý:
10 + 20  30
b = 30
a = 30
c--  19
Ýfadenin sonunda deðiºkenler:
a = 30, b = 30, c = 19, d = 10 deðerlerini alýrlar.
Fonksiyon çaðýrma ifadelerinde bir deðiºken postfix ++ ya da – operatörü ile kullanýlmýºsa, ilk
önce fonksiyon artýrýlmamýº veya eksiltilmemiº deðiºken ile çaðýrýlýr, fonksiyonun çalýºmasý
bitince deðiºken 1 artýtýlýr 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 -- Operatörleriyle Ýlgili ªüpheli Kodlar (undefined behaviours)
++ ve – operatörlerinin bilinçsiz bazý kullanýmlarý derleyiciler arasýnda yorum farklýlýðýna yol
açarak taºýnabilirliði bozarlar. Böyle kodlardan sakýnmak gerekir.
3 tane + (+++) ya da 3 tane – (---) karakteri boºluk olmaksýzýn yan yana getirilmemelidir.
x = a+++b; /* ºüpheli kod
*/
Burada derleyiciler x = a++ + b;iºlemlerini yapabileceði gibi x = a+ ++b; iºlemlerini de
yapabilirler.
Bir ifadede bir deðiºken ++ ya da – operatörleriyle kullanýlmýºsa, o deðiºken o ifadede
bir kez daha yer almamalýdýr. Örneðin aºaðýdaki ifadelerin hepsi ºüpheli kodlardýr :
int x = 20, y;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
71
Buy RoboPDF
9 . BÖLÜM :
y = ++x + ++x;
y = ++x + x
a = ++a;
/* ºüpheli kod */
/* ºüpheli kod */
/* ºüpheli kod */
Bir fonksiyon çaðýrýlýrken parametrelerden birinde bir deðiºken ++ ya da – ile kullanýlmýºsa
budeðiºken diðer parametrelerde gözükmemelidir.
Argumanlarým patrametre deðiºkenlerine kopyalanma sýrasý standart bir biçimde
belirlenmemiºtir. Bu kopyalama iºlemi bazý sistemlerde soldan saða bazý sistemlerde ise
saðdan soladýr. örnek :
int a = 10;
fonk (a, a++);
/* ºüpheli kod fonk fonksyinuna 10, 10 deðerleri mi 11, 10 deðerleri mi
önderiliyor? */
void fonk(x, y)
{
...
}
Karºýlaºtýrma Operatörleri (iliºkisel operatörler)
C programlama dilinde toplam 6 tane karºýlaºtýrma operatörü vardýr:
<
>
<=
>=
==
!=
küçüktür (less than)
büyüktür (greater than)
küçük eºit (less than or equal)
büyük eºit (greater than or equal)
eºittir. (equal)
eºit deðildir. (not equal)
Bu operatörlerin hepsi iki operand alan araek operatörlerdir. (binary infix)
Operatör öncelik tablosuna bakýldýðýnda, karºýlaºtýrma operatörlerinin aritmetik operatörlerden
daha sonra geldiði yani daha düºük öncelikli olduklarý görülür. Karºýlaºtýrma operatörleri kendi
aralarýnda iki öncelik grubu biçiminde bulunurlar.
Karºýlaºtýrma operatörleri bir önerme oluºtururlar ve sonuç ya doðru ya da yanlýº olur.
Karºýlaºtýrma operatörlerinden elde edilen deðer , önerme doðru ise 1 önerme yanlýº ise 0
deðeridir ve int türdendir. Bu operatörlerin ürettiði deðerler de týpký aritmetik operatörlerin
ürettiði deðerler gibi kullanýlabilirler. örnekler :
#include <stdio.h>
int main()
{
int x = 5;
...
y = (x > 5) + 1;
printf("%d\n", y);
funk(y >= x);
}
return 0;
Yukarýdaki örnekte ekrana 1 deðeri yazdýrýlacaktýr. Daha sonra da funk fonksiyonu 0 deðeriyle
çaðýrýlacaktýr.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
72
Buy RoboPDF
9 . BÖLÜM :
Bazý programlama dillerinde x = (a < b) + 1; gibi bir iºlem hata ile sonuçlanýr. Çünkü örneðin
Pascal dilinde a < b ifadesinden elde edilen deðer True ya da False dir. (yani BOOL ya da
BOOLEAN türündendir.) Ama C doðal bir dil olduðu için karºýlaºtýrma operatörlerinin ürettikleri
deðeri Boolean türü ile kýsýtlamamýºtýr. C’de mantýksal veri türü yerine int türü kullanýlýr.
Mantýksal bir veri türünün tamsayý türüyle ayný olmasý C’ye esneklik ve doðallýk kazandýrmýºtýr.
Baºka bir örnek :
x = y == z;
Yukarýdaki deyim C dili için son derece doðal ve okunabilir bir deyimdir. Bu deyimin icrasýyla x
deðiºkenine ya 1 ya da 0 deðeri atanacaktýr.
Karºýlaºtýrma operatörünün kullanýlmasýnda bazý durumlara dikkat etmemiz gerekmektedir.
Örneðin
int x = 12;
5>x>9
Yukarýdaki ifade matematiksel açýdan doðru deðildir. Çünkü 12 deðeri 5 ve 9 deðerlerinin
arasýnda deðildir. Ancak ifade C açýsýndan doðru olarak deðerlendirilir. Çünkü ayný seviyede
olan iki operatöre (> ve >) iliºkin öncelik yönü soldan saðadýr. Önce soldaki > operatörü deðer
üretecek ve ürettiði deðer olan 0 saðdaki > operatörüne operand olacaktýr. Bu durumda 0 > 9
ifadesi elde edilecek ve bu ifadeden de 0 yani yanlýº deðeri elde edilecektir.
Mantýksal Operatörler (logical operators)
Bu operatörler operandlarý üzerinde mantýksal iºlem yaparlar. Operandlarýný Doðru (true) ya da
Yanlýº(false) olarak yorumladýktan sonra iºleme sokarlar. C’de dilinde öncelikleri farklý seviyede
olan (tabloya bakýnýz) üç mantýksal operatör vardýr:
! deðil operatörü (not)
&& Ve operatörü (and)
|| veya operatörü (or)
Tablodan da görüleceði gibi
&& ya da || operatörlerin ayný ifade içinde birden fazla
kullanýlmasý durumunda öncelik yönü soldan saðadýr, 2. seviyede bulunan ! operatörü için ise
öncelik yönü saðdan soladýr.
C’de mantýksal veri türü yoktur. Mantýksal veri türü olmadýðý için bunun yerine int türü
kullanýlýr ve mantýksal doðru olarak 1 mantýksal yanlýº olarak da 0 deðeri kullanýlýr.
C dilinde herhangi bir ifade mantýksal operatörlerin operandý olabilir. Bu durumda söz konusu
ifade mantýksal olarak yorumlanýr. Bunun için ifadenin sayýsal deðeri hesaplanýr. Hesaplanan
sayýsal deðer 0 dýºý bir deðer ise doðru (1), 0 ise yanlýº (0) olarak yorumlanýr. Örneðin:
25 Doðru (Çünkü 0 dýºý bir deðer)
-12 Doðru (Çünkü 0 dýºý bir deðer)
0 Yanlýº (Çünkü 0)
int x = 5;
x * x – 25
Ýfadesi mantýksal bir operatörün operandý olduðu zaman yanlýº olarak yorumlanacaktýr. Çünkü
sayýsal deðeri 0’a eºittir.
! Operatörü
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
73
Buy RoboPDF
9 . BÖLÜM :
Deðil operatörü tek operand alýr ve her zaman önek durumundadýr. (unary prefix) ! operatörü
operandýnýn mantýksal deðerini deðiºtirir. Yani Doðru deðerini yanlýº deðerini, yanlýº deðerini de
Doðru deðerine dönüºtürür:
x
Doðru (0 dýºý deðer)
Yanlýº (0)
!x
Yanlýº (0)
Doðru (1)
Örnekler :
a = !25;
b = 10 * 3 < 7 + !2
/* a deðiºkenine 0 deðeri atanýr */
ݺlem sýrasý:
!2 = 0
10 * 3 = 30
7+0=7
30 < 7 = 0
b = 0 (atama operatörü en düºük öncelikli operatördür)
y = 5;
x = !++y < 5 != 8;
ݺlem sýrasý:
++y  6
!6  0
/* ++ ve ! operatörleri ayný öncelik seviyesindedir ve öncelik yönü saðdan soladýr. */
0<51
1 != 8  1
x=1
&& (ve / and) Operatörü
Bu operatör iliºkisel operatörlerin hepsinden düºük, || (veya / or) operatöründen yüksek
önceliklidir. Operandlarýnýn ikisi de Doðru ise Doðru (1), operandlardan bir tanersi yanlýº ise
yanlýº (0) deðerini üretir.
x
yanlýº
yanlýº
Doðru
Doðru
x
3
7
1
x
y
yanlýº
Doðru
yanlýº
Doðru
x&&y
yanlýº
yanlýº
yanlýº
Doðru
= 3 < 5 && 7;
<51
1
&& 1  1
=1
&& operatörünün önce sol tarafýndaki iºlemler öncelik sýrasýna göre tam olarak yapýlýr. Eðer bu
iºlemlerde elde edilen sayýsal deðer 0 ise && operatörünün sað tarafýndaki iºlemler hiç
yapýlmadan Yanlýº (0) sayýsal deðeri üretilir. Örneðin :
x = 20;
b = !x == 4 && sqrt(24);
!20  0
0 == 4  0
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
74
Buy RoboPDF
9 . BÖLÜM :
Sol taraf 0 deðeri alacaðýndan operatörün sað tarafý hiç icra edilmeyecek dolayýsýyla da sqrt
fonksiyonu çaðýrýlmayacaktýr. Dolayýsýyla b deðiºkenine 0 deðeri atanacaktýr.
Uygulamalarda mantýksal operatörler çoðunlukla iliºkisel (karºýlaºtýrma) operatörleriyle birlikte
kullanýlýrlar :
scanf(“%d”, &x);
y = x >= 5 && x <= 25;
Bu durumda y deðiºkenine ya 1 ya da 0 deðeri atanacaktýr. Eðer x 5’den büyük ya da eºit ve
25’den küçük ya da eºit ise y deðiºkenine 1 deðeri bunun dýºýndaki durumlarda y deðiºkenine 0
deðeri atanacaktýr.
ch = ‘c’
z = ch >= ‘a’ && ch <= ‘z’
Yukarýdaki örnekte ch deðiºkeninin küçük harf olup olmamasý durumuna göre z deðiºkenine 1
ya da 0 atanacaktýr.
|| (veya / and) Operatörü
Önceliði en düºük olan mantýksal operatördür. Ýki operandýndan biri Doðru ise Doðru deðerini
üretir. Ýki operandý da yanlýº ise yanlýº deðerini üretir.
x
yanlýº
yanlýº
Doðru
Doðru
y
yanlýº
Doðru
yanlýº
Doðru
a = 3 || 5
x = 0 || -12
sayi = 0 || !5
x||y
yanlýº
Doðru
Doðru
Doðru
/* a = 1 */
/* x = 1 */
/* sayi = 0 */
|| operatörünün önce sol tarafýndaki iºlemler öncelik sýrasýna göre tam olarak yapýlýr. Eðer bu
iºlemlerden elde edilen sayýsal deðer 1 ise sað tarafýndaki iºlemler yapýlmaz. Örnekler:
a = 20;
b = 10;
y = a + b >= 20 || a – b <= 10;
a + b  30
30 >= 20  1
Artýk sað taraftaki iºlemlerin yapýlmasýna gerek kalmadan y deðiºkenine 1 deðeri atanýr.
Aºaðýdaki ifadede ch deðiºkeninin içinde bulunan karakterin (Türkçe karakterler de dahil olmak
üzere) küçük harf olup olmadýðý bulunur:
ch = ‘ç’;
a = ch >= ‘a’ && ch <= ‘z’ || ch == ‘ý’ || ch == ‘ü’ || ch == ‘ð’ || ch == ‘ç’ || ch ==’ö’ || ch
== ‘º’;
Son olarak ºunu da ilave edelim, mantýksal operatörler bir deðer üretebilmek için operandlarýný
önce 1 ya da 0 (yani DOÐRU ya da YANLIª) olarak yorumlarlar, ama yan etkileri yoktur. Yani
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
75
Buy RoboPDF
9 . BÖLÜM :
operandlarýnýn nesne olmasý durumunda bu neslerin bellekteki deðerlerini 1 ya da 0 olarak
deðiºtirmezler.
Özel Amaçlý Operatörler
Bu bölümde özel amaçlý operatörlerden atama, iºlemli atama, öncelik ve virgül operatörlerini
inceleyeceðiz.
Atama Operatörü (assignment operator)
Atama operatörü C dilinde öncelik tablosunun en alttan ikinci seviyesinde bulunur ve yalnýzca
virgül operatöründen daha yüksek önceliklidir. Her operatör bir deðer üretir ve atama
operatörü de yaptýðý atama iºleminin yanýsýra bir deðer üretir. Atama operatörünün ürettiði
deðer sað taraf deðerinin kendisidir. Örneðin:
if (a = 20) {
...
}
Burada sýrasýyla ºunlar olur :
1. 20 sayýsý x deðiºkenine atanýr.
2. Bu iºlemden 20 sayýsý üretilir.
3. 20 sýfýr dýºý bir sayý olduðu için if deyimi doðru olarak deðerlendirilir.
Atama operatörünün ürettiði deðer nesne deðildir. dolayýsýyla;
(b = c) = a;
/* ifadesi C’de geçerli bir deyim deðildir. */
b = c atamasýndan elde edilen deðer c nesnesinin kendisi deðil c nesnesinin sayýsal deðeridir.
Operatör tablosundan da göreceðimiz gibi atama operatörü kendi arasýnda saðdan sola
önceliklidir. (right associative) Bu yüzden :
var1 = var2 = var3 = 0; deyimi C’de geçerlidir. Bu deyimde önce var3 deðiºkenine 0 deðeri
atanacak ve üretilen 0 deðeri var2 deðiºkenine atanacak ve yine üretilen 0 deðeri son olarak
var1 deðiºkenine atanacaktýr.
ݺlemli Atama Operatörleri
Bir iºlemin operandý ile iºlem sonucunda üretilen deðerin atanacaðý nesne ayný ise iºlemli
atama operatörleri kullanýlýr.
<nesne1> = <nesne1> iºlem <operand2> ile
<nesne1> iºlem= <operand2> ayný anlamdadýr.
ݺlemli atama operatörleri atama operatörüyle saðdan sola eºit öncelike sahiptir. (operatör
öncelik tablosuna bakýnýz)
ݺlemli atama operatörleri hem okunabilirlik hem da daha kýsa yazým için tercih edilirler.
Aºaðýdaki ifadeler eºdeðerdir:
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 yazýlabilir.
var1 = 3;
var2 = 5;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
76
Buy RoboPDF
9 . BÖLÜM :
var1 += var2 *= 3; ifadesinde var2 = var2 * 3 iºlemiyle önce var2 deðiºkenine 15 deðeri
atanacak ve iºlem sonucunda 15 deðeri üretilecek var1 = var1 + 15 iºlemiyle var1 deðiºkenine
18 deðeri atanacaktýr.
Özellikle += ve -= operatörlerinin yanlýº yazýlmasý, tespit edilmesi zor hatalara neden olabilir.
x += 5;
ifadesi x degiºkeninin eski deðerini 5 artýrýyorken bu deyim yanlýºlýkla aºaðýdaki gibi yazýldýðý
takdirde
x =+ 5;
x deðiºkenine 5 deðeri atanacaktýr. Çünku burada iki ayrý operatör söz konusudur. (atama
operatörü olan = ve iºaret operatörü olan +)
yukarýdaki örneklerden de görüldüðü gibi atama grubu operatörlerinin yan etkileri vardýr. Yan
etkileri operatörün sol operandýnýn bellekteki deðerinin deðiºtirilmesi (operatörün sað
tarafýndaki operandý olan ifadenin deðerinin sol tarafýndaki nesneye aktarýlmasý) ºeklinde
kendini gösterir.
Virgül (,) Operatörü
Ýki ayrý ifadeyi tek bir ifade olarak birleºtiren virgül operatörü C’nin en düºük öncelikli
operatörüdür.
ifade1;
ifade2;
ile
ifade1, ifade2;
ayný iºleve sahiptir.
Virgül operatörünün önce sol tarafýndaki ifade sonra sað tarafýndaki ifade tam olarak yapýlýr. Bu
operatörün ürettiði deðer sað tarafýndaki ifadenin ürettiði deðerdir. Virgülün sol tarafýndaki
ifadenin ürettiði deðerin virgül operatörünün ürettiði deðere bir etkisi yoktur. Örneðin :
x = (y *= 5, z = 100);
ifadesinde x deðiºkenine 100 deðeri atanacaktýr.
Aºaðýdaki örnekte if deðeri yanlýº olarak deðerlendirilecektir :
if (a =10, b = 0) {
...
}
Virgül operatörleri ile birden fazla ifade tek bir ifade olarak birleºtirilebilir. Örneðin :
if (x == 20) {
a1 = 20;
a2 = 30;
a3 = 40;
}
yerine
if (x == 20)
a1 = 20, a2 = 30, a3 = 40;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
77
Buy RoboPDF
9 . BÖLÜM :
yazýlabilir.
Öncelik Operatörü ( )
Öncelik operatörü bir ifadenin önceliðini yükseltmek amacýyla kullanýlmaktadýr.
x = (y + z) * t;
Öncelik operatörünü C nin en yüksek öncelikli operatörler grubundadýr. Öncelik operatörü de
kendi arasýnda soldan saða öncelik kuralýna uyar. Örneðin:
a = (x + 2) / ((y + 3) * (z + 2) – 1);
ifadesinde iºlem sýrasý ºöyledir :
i1
i2
i3
i4
i5
i6
i7
:
:
:
:
:
:
:
x+2
y+3
z+2
i2 * i3
i4 – 1
i1 / i5
a = i6
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
78
Buy RoboPDF
if DEYÝMÝ
10 . BÖLÜM : if DEYÝMÝ
C dilinde program akýºýný kontrol etmeye yönelik en önemli deyim if deyimidir. if deyiminin
genel biçimi aºaðýda verilmiºtir:
if (ifade)
deyim1;
else
deyim2;
deyim1 ve deyim2 yalýn deyim (simple statement) olabileceði gibi, bileºik bir deyim (compound
statement) ya da baºka bir kontrol deyimi de (control statement) olabilir.
if parantezi içindeki ifadeye kontrol ifadesi (control expression) denir.
if deyiminin icrasý aºaðýdaki gibi yapýlýr:
Derleyici önce kontrol ifadesinin sayýsal deðerini hesaplar. Hesapladýðý sayýsal deðeri mantýksal
doðru ya da yanlýº olarak yorumlar. Ýfadenin hesaplanan deðeri 0 ise yanlýº, 0 dýºýnda bir deðer
ise doðru olarak yorumlanýr. (Örneðin kontrol ifadesinin hesaplanan deðerinin –5 olduðunu
düºünelim, bu durumda kontrol ifadesi doðru olarak deðerlendirilecektir). Eðer ifadenin sonucu
doðru ise else anahtar sözcüðüne kadar olan kýsým, eðer ifadenin sonucu yanlýº ise else
anahtar sözcüðünden sonraki kýsým icra edilir. Örnek :
{
}
int var = 3;
if (var * 5 < 50)
deyim1;
else
deyim2;
deyim3;
1. adým : if parantezi içindeki ifadenin sayýsal deðeri hesaplanacak :
15 < 50
sonuç 1 (doðru)
2. adým : deyim1 icra edilecek.
3. adým : daha sonra else kýsmý atlanarak deyim3 icra edilecek.
if parantezi içerisindeki ifadeler karmaºýk yapýda da olabilir :
...
char ch = ‘Q’;
if (ch >= ‘a’ && ch <= ‘z’)
printf(“%c\n”, ch);
else
printf(“küçük harf deðil\n”);
ch = ‘A’;
Yukarýdaki if deyimi ile ch karakterinin küçük harf olup olmadýðý test edilmektedir. ch
karakterinin küçük harf olmasý durumunda bu karakter ekrana basýlacak, aksi durumda ekrana
“küçük harf deðil” mesajý yazýlacaktýr. Her iki durumdada programýn akýºý
ch = ‘A’;
atama deyimiyle devam edecektir.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
79
Buy RoboPDF
10 . BÖLÜM :
if deyiminin doðru ve / veya yanlýº kýsmý birden fazla deyimden oluºuyorsa bloklama
yapýlmalýdýr :
if (b * b – 4 * a * c < 0) {
deyim1;
deyim2;
deyim3;
}
else {
deyim4;
deyim5;
deyim6;
}
Yukarýdaki örnekte kontrol ifadesinin doðru olmasý durumunda, deyim1, deyim2, deyim3 icra
edilecektir. Kontrol ifadesinin yanlýº olmasý durumunda ise deyim4, deyim5, deyim6 icra
edilecektir.
Bir if deyiminin else kýsmý olmayabilir:
if (result < 0) {
clrscr();
printf(“sonuç 0’dan küçük\n”);
}
++x;
...
Bir if deyimi yalnýzca else kýsmýna sahip olamaz. Bu durumda if deyiminin doðru kýsmýna boº
deyim ya boº bileºik deyim yerleºtirilmelidir.
if (ifade)
;
else
deyim1;
ya da
if (ifade)
{}
else
deyim1;
Ama daha iyi teknik koºul ifadesini deðiºtirmektir:
if (!ifade)
deyim1;
if parantezindeki ifade deðiºken içermek zorunda deðildir, sabit ifadesi de olabilir:
if (10)
deyim1
...
if (-1)
deyim2
Yukarýdaki kontrol ifadelerinin deðeri her zaman doðru olacaktýr. (0 dýºý deðer)
if ( 0)
deyim1;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
80
Buy RoboPDF
if DEYÝMÝ
Yukarýdaki kontrol ifadesi ise her zaman yanlýº olacaðýndan if deyiminin doðru kýsmý hiçbir
zaman icra edilmeyecektir.
if (x) {
deyim1;
deyim2;
....
}
Bu if deyiminde ise x deðiºkeninin deðerinin 0 dýºý bir deðer olup olmamasýna göre deyim1 ve
deyim2 icra edilecektir.
Yukarýdaki yapýyla aºaðýdaki yapý eºdeðerdir:
if (x != 0) {
deyim1;
deyim2;
....
}
Aºaðýdaki örneði inceleyelim :
if (!x) {
deyim1;
deyim2;
....
}
Bu if deyiminde ise ancak x deðiºkeninin deðerinin 0 olmasý durumunda deyim1 ve deyim2
icra edilecektir.
Yine yukarýdaki yapýyla aºaðýdaki yapý eºdeðerdir:
if (x == 0) {
deyim1;
deyim2;
....
}
if ((ch = getchar()) == ‘h’)
deyim1;
else
deyim2;
Bu if deyiminin kontrol ifadesinde ise klavyeden bir deðer alýnmakta alýnan deðer ch
deðiºkenine atanmakta ve daha sonra da ch deðiºkeni deðerinin ‘h’ karakteri olup olmadýðý test
edilmektedir. Eðer klavyeden alýnan deðer 'h' ise deyim1 deðil ise deyim2 yapýlacaktýr.
kontrol ifadesi içindeki parantezler atama iºlemine öncelik kazandýrmak amacýyla
kullanýlmaktadýr. Parantez kullanýlmasaydý eºitlik karºýlaºtýrma operatörünün (==) önceliði
atama operatöründen daha yüksek olduðu için önce karºýlaºtýrma iºlemi yapýlacak daha sonra
üretilen 0 ya da 1 deðeri ch deðiºkenine atanacaktý.
Yukarýdaki örnekte de görüldüðü gibi bir if deyiminin koºul ifadesi içinde atama operatörünün
bir deðer üretmesi fikrinden sýklýkla faydalanýlýr.
Fonksiyonlarýn geri dönüº deðerleri de sýklýkla if deyiminin kontrol ifadesi olarak kullanýlýr.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
81
Buy RoboPDF
10 . BÖLÜM :
if (isupper(ch) != 0)
deyim1;
else
deyim2;
isupper parametresinin büyük harf olup olmadýðýný kontrol eden bir standart C fonksiyonudur.
Yukarýdaki if deyiminde ch karakterinin büyük harf olup olmamasýna göre deyim1 ya da
deyim2 icra edilecektir.
Yukarýdaki koºul ifadesi yerine C programcýlarý genellikle aºaðýdaki ifadeyi tercih ederler :
if (isupper(ch))
deyim1;
else
deyim2;
if deyiminin doðru ya da yanlýº kýsmý baºka bir if deyimi de olabilir :
if (ifade1)
if (ifade2) {
deyim1;
deyim2;
deyim3;
}
deyim4;
Bu örnekte ikinci if deyimi birinci if deyiminin doðru kýsmýný oluºturmaktadýr. Birinci ve ikinci if
deyimlerinin yanlýº kýsýmlarý yoktur.
Ýç içe if deyimlerinde son if anahtar sözcüðünden sonra gelen else anahtar sözcüðü en içteki if
deyimine ait olacaktýr:
if (ifade1)
if (ifade2)
deyim1;
else
deyim2;
Yukarýdaki örnekte yazým tarzý olarak else kýsmýnýn birinci if deyimine ait olmasý gerektiði gibi
bir görüntü verilmiº olsa da else kýsmý ikinci if deyimine aittir. else anahtar sözcüðü bu gibi
durumlarda kendisine yakýn olan if deyimine ait olacaktýr. (dangling else) Eðer else anahtar
sözcüðünün birinci if deyimine ait olmasý isteniyorsa, birinci if deyiminin doðru kýsmý blok içine
alýnmalýdýr.
if (ifade1) {
if (ifade2)
deyim1;
}
else
deyim2;
Yukarýdaki örnekte else kýsmý birinci if deyimine aittir.
if (ifade1) {
if (ifade2)
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
82
Buy RoboPDF
if DEYÝMÝ
deyim1;
else {
deyim2;
deyim3;
}
deyim4;
}
else
deyim5;
Birinci if deyiminin doðru kýsmý birden fazla deyimden oluºtuðu için (bu deyimlerden birisi de
yine baºka bir if deyimidir) bloklama yapýlmýºtýr. deyim5 birinci if deyiminin yanlýº kýsmýný
oluºturmaktadýr.
Ayrýk karºýlaºtýrma ve else if merdivenleri :
Aºaðýdaki 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(“Aralýk\n”);
Yukarýdaki örnekte verilen yapýda olduðu gibi, eðer bir karºýlaºtýrmanýn doðru olarak
yorumlanmasý durumunda yapýlan diðer karºýlaºtýrmalarýn doðru olmasý söz konusu deðilse bu
tür karºýlaºtýrmalara ayrýk karºýlaºtýrma denir. Ayrýk karºýlaºtýrmalarda ayrý ayrý if deyimlerinin
kullanýlmasý kötü tekniktir. Yukarýdaki örnekte m deðiºkeninin deðerinin 1 olduðunu düºünelim.
Bu durumda ekrana Ocak yazdýrýlacak fakat daha sonra yer alan if deyimleriyle m deðiºkeninin
sýrasýyla 2, 3, .... 12’ye eºit olup olmadýðý test edilecektir. Ama x deðiºkeni 1 deðerine sahip
olduðundan bütün diðer if deyimleri içindeki kontrol ifadelerinin yanlýº olarak deðerlendirileceði
bellidir.
Ayrýk karºýlaºtýrmalarda else if merdivenleri uygulamalarý çok kullanýlýr :
if (ifade1)
deyim1;
else
if (ifade2)
deyim2;
else
if (ifade3)
deyim3;
else
if (ifade4)
deyim4;
else
deyim5;
Bu yapýda artýk herhangi bir if deyimi içerisindeki bir kontrol ifadesi doðru olarak
deðerlendirilirse programýn akýºý hiçbir zaman baºka bir if deyimine gelmeyecektir. Bu yapýya
else if merdiveni (cascaded if / else if ladder) denir. else if merdivenlerinin yukarýdaki
biçimde yazýlýºý özellikle uzun else if merdivenlerinde okunabilirliði bozduðu için aºaðýdaki
yazým tarzý okunabilirlik açýsýndan tercih edilmelidir.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
83
Buy RoboPDF
10 . BÖLÜM :
if (ifade1)
deyim1;
else if (ifade2)
deyim2;
else if (ifade3)
deyim3;
else if (ifade4)
deyim4;
else deyim5;
if Deyiminin Kullanýlmasýna Ýliºkin Sýk Yapýlan Hatalar
if parantezinin sonuna yanlýºlýkla ; yerleºtirilmesi:
...
if (x > 5);
printf("doðru!\n");
...
Yukarýdaki örnekte x > 5 ifadesi doðru da yanlýº da olsa printf fonksiyonu çaðýrýlacaktýr. Zira
printf çaðýrýmý if deyiminin dýºýndadýr. if deyiminin doðru kýsmýný bir boº deyim (Null
statement) oluºturmaktadýr. Ayný nedenden dolayý aºaðýdaki kod derleme zamanýnda error
oluºumuna neden olacaktýr :
...
if (x > 5);
printf("doðru!\n");
else
printf("yanlýº\n");
...
if anahtar sözcüðü olmayan bir else anahtar sözcüðü:
Tabi ki bir if deyiminin doðru ya da yanlýº kýsmýný bir ; (boº deyim - null statement)
oluºturabilir. Bu durumda okunabilirlik açýsýndan bu boº deyim bir tab içeriden yazýlmalýdýr:
...
if (funk())
;
else
x = 5;
if parantezi içerisinde karºýlaºtýrma operatörü (==) yerine yanlýºlýkla atama operatörünün (=)
kullanýlmasý
...
if (x == 5)
printf("eºit\n");
...
Yukarýdaki if deyiminde x deðiºkeninin deðeri eðer 5'e eºitse printf fonksiyonu çaðýrýlacaktýr.
Operatörler konusunda da deðindiðimiz gibi karºýlatýrma operatörünün yan etkisi yoktur, yani
yukarýdaki if parantezi içerisinde x deðiºkeninin deðeri yalnýzca 5 sabiti ile karºýlaºtýrýlmakta,
deðiºkenin deðeri deðiºtirilmemektedir. Oysa karºýlaºtýrma operatörünün yerine yanlýºlýkla
atama operatörü kullanýlýrsa:
...
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
84
Buy RoboPDF
if DEYÝMÝ
if (x = 5)
printf("eºit\n");
...
Atama operatörü atama operatörünün sað tarafýndaki ifadenin deðerini üreteceðinden if
parantezi içindeki ifadenin deðeri 5 olarak hesaplanacak ve 5 de 0 dýºý bir deðer olduðundan
printf fonksiyonu x deðiºkeninin deðeri ne olursa olsun, çaðýrýlacaktýr. Tabi, atama operatörü
yan etkisi olan bir operatör olduðundan x deðiºkeni de if deyiminin icrasý sýrasýnda 5 deðerini
alacaktýr.
C derleyicilerinin çoðu if parantezi içindeki ifade yalýn bir atma ifadesi ise, durumu ºüpheyle
karºýlayarak, bir uyarý mesajý verirler. Örneðin Borland derleyicilerinde tipik bir uyarý mesajý
aºaðýdaki gibidir :
warning : possibly incorrect assignment! (muhtemelen yanlýº atama!)
Oysa if parantezi içerisinde atama operatörü bilinçli olarak da kullanýlabilir. Bilinçli kullanýmda,
uyarý mesajýnýn kaldýrýlmasý için ifade aºaðýdaki gibi düzenlenebilir :
...
if ((x = funk()) != 0)
m = 20;
...
Yukarýdaki örnekte atama operatörünün ürettiði deðer açýk olarak bir karºýlaºtýrma operatörüne
operand yapýldýðý için derleyiciler bu durumda bir uyarý mesajý vermezler.
if deyiminin doðru ya da yanlýº kýsmýnýn birden fazla basit deyimden oluºmasý durumunda if
deyiminin doðru ya da yanlýº kýsmý bileºik deyim haline getirilmelidir.
...
if ( x == 10)
m = 12;
k = 15;
...
Yukarýdaki if deyiminde sadece
m = 12;
deyimi if deyiminin doðru kýsmýný oluºturmaktadýr.
k = 15;
deyimi if deyimi dýºýndadýr. Bu durum, genellikle programcýnýn if deyiminin doðru ya da yanlýº
kýsmýný önce basit bir deyimle oluºturmasýndan sonra, doðru ya da yanlýº kýsma ikinci bir basit
deyimi eklerken, bloklama yapmayý unutmasý yüzünden oluºur!
Kodun yazýlýº biçiminden de if deyiminin doðru kýsmýnýn yanlýºlýkla bloklanmadýðý anlaºýlýyor! :
Doðrusu aºaðýdaki gibi olmalýydý :
...
if ( x == 10) {
m = 12;
k = 15;
}
...
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
85
Buy RoboPDF
10 . BÖLÜM :
Aºaðýdaki if deyimi ise yine if anahtar sözcüðü ile eºlenmeyen bir else anahtar sözcüðü
kullanýldýðý için derleme zamanýnda error oluºumuna neden olacaktýr :
...
if ( x == 10)
m = 12;
k = 15;
else
y = 20;
...
Bu tür yanlýºlýklardan sakýnmak için bazý C programcýlarý if deyiminin doðru ya da yanlýº kýsmý
basit deyimden oluºsa da, bu basit deyimi bileºik deyim olarak yazarlar :
if ( x > 10) {
y = 12;
}
else {
k = 5;
}
Yukarýdaki örnekte if deyiminin doðru ya da yanlýº kýsmýna baºka bir basit deyimin ilave
edilmesi durumunda bir yanlýºlýk ya da error oluºmayacaktýr. Ancak biz yukarýdaki gibi bir kodu
stil açýsýndan beðenmiyoruz. Gereksiz bloklamadan kaçýnmalýyýz.
Bazen de if deyiminin yanlýº kýsmý unutulur :
...
if (x == 10)
printf("x 10'a eºit!\n"")
printf("x 10'a eºit deðil!\n);
...
if parantezi içerisindeki ifadenin yanlýº olmasý durumunda bir yanlýºlýk söz konusu deðil ama
ifade doðru ise ekrana ne yazýlacak?
x 10'a eºit!
x 10'a eºit deðil!
Tehlikeli bir bug da if parantezi içerisindeki ifadenin bir fonksiyon çaðýrma ifadesi olmasý
durumunda yanlýºlýkla fonksiyon çaðýrma operatörünün unutulmasýdýr!
...
if (funk())
m = 12;
...
yerine
...
if (funk)
m = 12;
...
yazýlýrsa, if deyiminin her zaman doðru kýsmý icra edilir. Zira C dilinde bir fonksiyon ismi, o
fonksiyonun kodunun bellekteki yerine eºdeðer bir adres bilgisi olarak ele alýnýr. (Göstericiler
konusunda göreceðiz.) Bu adres bilgisi de her zaman 0 dýºý bir deðer olacaðýndan, koºul ifadesi
her zaman doðru olarak deðerlendirilecektir.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
86
Buy RoboPDF
if DEYÝMÝ
if Deyiminin Kullanýldýðý Örnek Uygulamalar
islower Fonksiyonu
islower standart bir C fonksiyonudur. Parametresi olan karakter, küçük harf karakterlerinden
biri ise Doðru (sýfýr dýºý bir deðer), deðilse Yanlýº (sýfýr) deðerine geri döner. Bu fonksiyonu
aºaðýdaki º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(“küçük harf\n”);
else
printf(“küçük harf deðil\n”);
Yukarýda yazýlan _islower fonksiyonunda önce parametre deðiºkeninin küçük harf olup olmadýðý
test edilmektedir. Parametre deðiºkeni eðer küçük harf ise if deyiminin Doðru kýsmý
yapýlacaktýr. Doðru kýsmýnýn yapýlmasý ile fonksiyon ch’nýn kendi deðerine geri dönecektir. (Bu
da 0 dýºý bir deðerdir. Pekala 1 gibi sabit bir deðer ile de geri dönebilirdik ama ch parametre
deðiºkeninin deðeri ile geri dönmemiz fonksiyonun kullanýlmasýnda bazý avantajlar
getirebilecektir. Fonksiyonun yazýmýnda dikkat edilmesi gereken bir nokta da ºudur : if
deyiminin Yanlýº kýsmý yoktur. (Yani else anahtar sözcüðü kullanýlmamýºtýr. Test
fonksiyonlarýnda bu durum çok sýk görülür. Çünkü if deyiminin Doðru kýsmýnda return anahtar
sözcüðü ile fonksiyon yalnýzca bir geri dönüº deðeri üretmekle kalmamakta ayný zamanda
sonlanmaktadýr. Bu durumda else anahtar sözcüðüne gerek kalmaz. (Çünkü Doðru kýsmýnýn
yapýlmasýndan sonra Yanlýº kýsmýnýn da yapýlmasý mümkün deðildir.) Bu tür durumlarda else
anahtar sözcüðünün kullanýlmasý kötü teknik olarak deðerlendirilir.
isalpha Fonksiyonu
isalpha fonksiyonu da standart bir C fonksiyonudur. Parametresi olan karakter , eðer alfabetik
karakterse (yani büyük ya da küçük harf ise) Doðru (sýfýr dýºý bir deðere), alfabetik bir karakter
deðilse Yanlýº (sýfýr deðerine) geri döner.
#include <stdio.h>
int isalpha (char ch)
{
if (ch >= ‘a’ && ch <= ‘z’ || ch >= ‘A’ && ch <= ‘Z’)
return ch:
return 0;
}
main()
{
char ch;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
87
Buy RoboPDF
10 . BÖLÜM :
ch = getchar();
if (isalpha(ch))
printf(“alfabetik karakter\n”);
else
printf(“alfabetik karakter deðil\n”);
tolower Fonksiyonu
tolower standart bir C fonksiyonudur. Parametresi olan karakter, eðer büyük harf ise, onun
küçük harf karºýlýðýyla geri döner. tolower küçük harf olmayan karakterlere hiç dokunmaz,
onlarý deðiºtirmeden geri dönüº deðeri 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, eðer bir rakam karakteri ise 0
dýºý bir deðer ile, rakam karakteri deðilse 0 deðeri ile geri döner.
int _digit (char ch)
{
if (ch >= ‘0’ && ch <= ‘9’)
return ch:
return 0;
}
yukarýdaki örneklerde görüldüðü gibi, fonksiyonlarýn parametreleri ve geri dönüº deðerleri char
türden olsa bile, int biçiminde gösterilir.
Karakter Test Fonksiyonlarý
Karakter test fonksiyonlarý karakterler hakkýnda bilgi edinmemizi saðlayan fonksiyonlardýr. Bu
fonksiyonlarýn hepsi ctype.h baºlýk dosyasý içinde makro olarak bulunurlar. Bu nedenle karakter
test fonksiyonlarý kullanýlmadan önce kaynak koda mutlaka ctype.h dosyasý dahil edilmelidir.
Karakter test fonksiyonlarý ASCII karakter setinin ilk yarýsý için geçerlidir, yani türkçe
karakterler için kullanýlmasý durumunda geri dönüº deðerleri güvenilir deðildir.
C dilinindeki standart karakter test fonksiyonlarý:
fonksiyon
isalpha
isupper
islower
isdigit
isxdigit
isalnum
geri dönüº deðeri
alfabetik karakterse Doðru deðilse Yanlýº
Büyük harf ise Doðru deðilse Yanlýº
Küçük harf ise Doðru deðilse yanlýº
sayýsal bir karakterse Doðru deðilse Yanlýº
hex sayýlarý gösteren bir karakterse Doðru deðilse Yanlýº
alfabetik ya da nümerik bir karakterse Doðru deðilse Yanlýº
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
88
Buy RoboPDF
if DEYÝMÝ
isspace
Boºluk karakterlerinden biriyse(space, carriage return, new line,
vertical tab, form feed) Doðru deðilse Yanlýº
Noktalama karakterlerinden biriyse (kontrol karakterleri, alfanümerik
karakterler ve boºluk karakterlerinin dýºýndaki karakterler) Doðru
deðilse Yanlýº
Ekranda görülebilen (print edilebilen) bir karakterse (space karakteri
dahil) Doðru, deðilse Yanlýº.
Ekranda görülebilen bir karakterse (space dahil deðil) Doðru deðilse
yanlýº
Kontrol karakteri ya da silme karakteri ise (Ýlk 32 karakter ya da 127
numaralý karakter) Doðru deðilse Yanlýº
ASCII tablosunun standart kýsmý olan ilk 128 karakterden biriyse
Doðru deðilse Yanlýº
ispunct
isprint
isgraph
iscntrl
isascii
Uygulamalar
Kendisine gönderilen 0 ie 15 arasýndaki bir sayýnýn hexadesimal sembol karºýlýðý karakter ile
geri dönen get_hex_char fonksiyonunun yazýlmasý :
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 arasýnda bir sayý giriniz : ");
scanf("%d", &number);
printf("hexadesimal digit karºýlýðý = %c\n", get_hex_char(number));
return 0;
Kendisine gönderilen hex digit olan bir karakterin desimal sistemdeki deðerine geri dönen
get_hex_value(char digit) fonksiyonunun yazýlmasý.
#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()
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
89
Buy RoboPDF
10 . BÖLÜM :
{
}
char hex;
printf("hex digit gösteren bir karakter giriniz: ");
hex = getchar();
printf("girmiº oldugunuz hex basamaðýn desimal deðeri %d\n", get_hex_value(hex));
return 0;
Kendisine göderilen karakter küçük harf ise büyük harfe dönüºtüren, büyük harf ise küçük
harfe dönüºtüren, eðer harf karakteri deðilse karakterin kendisiyle geri dönen 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
tanýmlayabilirdik :
standart
C
fonksiyonlarýný
kullanarak
aºaðýdaki
ºekilde
de
int change_case(int ch)
{
if (isupper(ch))
return tolower(ch);
return toupper(ch);
}
Ýkinci dereceden bir denklemin çözüm kümesini bulan bir program :
#include <stdio.h>
#include <math.h>
main()
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
90
Buy RoboPDF
if DEYÝMÝ
{
double a, b, c;
double delta, kokdelta;
printf("denklemin katsayýlarýný giriniz : ");
scanf("%lf%lf%lf", &a, &b, &c);
}
delta = b * b - 4 * a * c;
if (delta < 0) {
printf("denkleminizin gerçek kökü yok!\n");
return 0;
}
if (delta == 0) {
printf("denkleminizin tek gerçek kökü var\n");
printf("kok = %lf\n", -b / (2 * a));
return 0;
}
kokdelta = sqrt(delta);
printf("denkleminizin 2 gerçek kökü var : ");
printf("kök 1 = %lf\n", (-b + kokdelta) / (2 * a));
printf("kök 1 = %lf\n", (-b - kokdelta) / (2 * a));
return 0;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
91
Buy RoboPDF
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
Buy RoboPDF
FONKSÝYON PROTOTÝPLERÝ
11 . BÖLÜM : FONKSÝYON PROTOTÝPLERÝ
C programlama dilinde, bir fonksiyonun çaðýrýlmasý durumunda derleyiciler fonksiyonun geri
dönüº deðerinin türünü bilmek zorundadýr. C derleyicileri fonksiyonlarýn geri dönüº deðerlerini
CPU yazmaçlarýndan (registers) alýrlar ve aslýnda geri dönüº deðeri türü, deðerin hangi
yazmaçtan alýnacaðýný gösterir.
Eðer çaðýrýlan fonksiyonun tanýmlamasý, fonksiyon çaðýrma ifadesinden daha önce yer alýyorsa,
derleyici derleme iºlemi sýrasýnda fonksiyon çaðýrma ifadesine gelmeden önce, çaðýrýlan
fonksiyonun geri dönüº deðeri türü hakkýnda zaten bilgi sahibi olacaktýr. Çünkü derleme iºlemi
yukarýdan aºaðý doðru yapýlýr.
# 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;
Yukarýdaki örnekte calculate fonksiyonu kendisini çaðýran main fonksiyonundan daha önce
tanýmlanmýºtýr. Dolayýsýyla çaðýrma ifadesine gelmeden önce derleyici, calculate fonksiyonunun
geri dönüº deðeri türünü zaten bilecektir.
Eðer çaðýrýlan fonksiyonun tanýmlamasý çaðýran fonksiyondan daha sonra yapýlmýºsa, derleyici
fonskiyon çaðýrma ifadesine geldiðinde, söz konusu fonksiyonun geri dönüº deðerinin türünü
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);
}
Yukarýda calculate fonksiyonu main içinde çaðýrýlmýºtýr. Fakat calculate fonksiyonunun
tanýmlamasý kaynak kod içinde main’den daha sonra yer almaktadýr. Derleme akýºý içerisinde
calculate fonksiyonuna iliºkin çaðýrma ifadesine gelindiðinde, derleyici bu fonksiyonun geri
dönüº deðerini bilmemektedir.
C derleyicileri derleme iºlemi sýrasýnda bir fonksiyon çaðýrma ifadesi gördüklerinde, eðer
fonksiyonun geri dönüº deðeri türü hakkýnda henüz sahibi deðillerse, söz konusu geri dönüº
deðerinin int türden olduðunu kabul ederler.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
93
Buy RoboPDF
11 . BÖLÜM :
Yukarýdaki örnekte derleyici calculate fonksiyonunun geri dönüº deðerinin int türden olduðunu
varsayacak ve buna göre kod üretecektir. Daha sonra derleme akýºý fonksiyonun tanýmlama
kýsmýna geldiðinde ise artýk iº iºten geçmiº olacaktýr. Hedef kod oluºumunu 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'
Çaðýrýlan fonksiyonu çaðýran fonksiyonun üstünde tanýmlamak her zaman mümkün deðildir.
Büyük bir programda yüzlerce fonksiyon tanýmlanabilir ve tanýmlanan her fonksiyonun birbirini
çaðýrmasý söz konusu olabilir. Bu durumda çaðýrýlacak fonksiyonu çaðýran fonksiyonun üzerinde
tanýmlanmasý çok zor olacaktýr. Kaldý ki, C dilinde iki fonksiyon birbirini de çaðýrabilir. Bu tür bir
fonksiyon tasarýmýnda artýk çaðýrýlan fonksiyonun daha önce tanýmlanmasý mümkün
olamayacaktýr :
double func1(void)
{
...
func2();
...
}
double func2(void)
{
...
func1();
...
}
Ayrýca standart C fonksiyonlarý da ancak baðlama aºamasýna gelindiðinde baðlayýcý (linker)
tarafýndan kütüphanelerden alýnarak çalýºabilen kod (.exe) içine yerleºtirilirler. ݺte bu gibi
durumlarda derleyiciye çaðýrýlan fonksiyonun geri dönüº tür bilgisi fonksiyon prototipleriyle
verilir. Çaðýrýlana kadar tanýmlamasý yapýlmamýº fonksiyonlar hakkýnda derleyicilerin
bilgilendirilmesi iºlemi fonksiyon prototip bildirimleri ile yapýlýr.
Fonksiyon Prototip Bildirimlerinin Genel Biçimi
[geri dönüº deðeri türü] <fonksiyon ismi> ([tür1], [tür2].....);
Örneðin calculate fonksiyonu için prototip aºaðýdaki biçimde yazýlabilir:
float calculate(float, float);
Derleyici böyle bir prototip bildiriminden calculate fonksiyonunun geri dönüº deðerinin türünün
float olduðunu anlayacaktýr.
Birkaç örnek daha verelim:
int multiply (int, int);
double pow (double, double);
void clrscr(void);
Týpký fonksiyon tanýmlamalarýnda olduðu gibi, fonksiyon prototip bildirimlerinde de,
fonksiyonun geri dönüº deðeri belirtilmemiºse, derleyici bildirimin int türden bir geri dönüº
deðeri için yapýldýðýný anlayacaktýr.
func(double);
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
94
Buy RoboPDF
FONKSÝYON PROTOTÝPLERÝ
Yukarýdaki prototip bildirimi örneðinde, derleyici func fonksiyonunun geri dönüº deðerinin int
türden olduðu bilgisini alýr, fonksiyonun geri dönüº deðerinin olmadýðý bilgisini deðil. Eðer
tanýmlanacak fonksiyon geri dönüº deðeri üretmeyecekse, void anahtar sözcüðü
kullanýlmalýdýr:
void func(double);
Fonksiyon protipleri yalnýzca derleyiciyi bildirme amacýyla kullanýlýr bir bildirimdir (declaration)
bir tanýmlama (definition) iºlemi deðildir, dolayýsýyla yapýlan bildirim sonucunda bellekte bir yer
ayrýlmaz.
Fonksiyon prototip bildirimlerinde parametre deðiºkenlerinin türlerinden sonra parametre
isimleri de yazýlabilir. Prototiplerdeki parametre isimlerinin faaliyet alanlarý yalnýzca parametre
parantezi ile sýnýrlýdýr. Buraya yazýlan parametre deðiºkenleri isimleri yalnýzca okunabilirlik
açýsýndan faydalýdýr. Buradaki deðiºken isimlerinin fonksiyonun gerçek tanýmlamasýnda
kullanýlacak formal parametre deðiºkenlerinin isimleriyle ayný olmasý zorunlulugu yoktur.
Yukarýdaki prototiplerini parametre isimleriyle tekrar yazalým.
float calculate(float a, float b);
int multiply(int number1, int number2);
double pow(double base, double exp);
Fonksiyon prototip bildirimlerinde parametre deðiºkenlerine isim verilmesi, bildirimleri okuyan
kiºilerin fonksiyonlarýn tanýmlarýný görmeden, deðiºkenler için kullanýlan isimleri sayesinde,
fonksiyonlarýn yaptýðý iº konusunda daha fazla bilgi sahibi olmalarýna yardýmcý olur.
Ayný türden geri dönüº deðerine sahip fonksiyonlarýn bildirimi virgüllerle ayrýlarak yazýlabilir,
ama bu genel olarak pek tercih edilen bir durum deðildir :
double func1(int), func2(int, int), func3(float);
Yukarýdaki bildirimde func1, func2 ve func3 fonksiyonlarýnýn hepsi double türden geri dönüº
deðerine sahip fonksiyonlardýr.
Fonksiyon prototip bildirimleri deðiºken tanýmlamalarýyla da birleºtirilebilir. Bu da tercih edilen
bir durum deðildir.
long func1(int), long func2(void), x, y;
Yukarýdaki deyim ile func1 ve func2 fonksiyonlarýnýn prototip bildirimi yapýlmýºken, x ve y
deðiºkenleri tanýmlanmýºtýr.
(C++ dilinde eðer çaðrýlan fonksiyon çaðýran fonksiyondan daha önce tanýmlanmamýºsa,
fonksiyonun geri dönüº deðeri int türden kabul edilmez. Bu durumda fonksiyon prototip
bildiriminin yapýlmasý zorunludur. Prototip bildiriminin yapýlmamasý durumunda derleme
zamanýnda hata (error) oluºacaktýr.)
Fonksiyon Prototiplerinin Bildirim Yerleri
Fonksiyon prototiplerinin bildirimi programýn herhangi bir yerinde yapýlabilir. Prototipler
bildirimleri global düzeyde yapýlmýºsa (yani tüm bloklarýn dýºýnda yapýlmýºsa) bildirildikleri
yerden dosya sonuna kadar olan alan içinde geçerliliklerini sürdürürler. Önemli olan nokta söz
konusu fonksiyon çaðýrýlmadan bildiriminin yapýmýº olmasýdýr.
Ancak uygulamalarda çok az raslanmasýna karºýlýk, fonksiyon prototipleri yerel düzeyde de
yapýlabilir. Bu durumda prototip bildirimi ile , yalnýzca bildirimin yapýlmýº olduðu bloða bilgi
verilmiº olur. Baºka bir deyiºle prototip bildirimi de, deðiºken tanýmlamalarý gibi faaliyet alaný
kuralýna uyar.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
95
Buy RoboPDF
11 . BÖLÜM :
Geleneksel olarak fonksiyon prototip bildirimleri programýn en yukarýsýnda ya da programcýnýn
tanýmladýðý baºlýk dosyalarýnýn birinin içinde yapýlýr. Baºlýk dosyalarý (header files) ileride
detaylý olarak ele alýnacaktýr.
Standart C Fonksiyonlarýnýn Prototipleri
Standart C fonksiyonlarýnýn prototipleri standart baºlýk dosyalarý içine yerleºtirilmiºtir.
Programcý, uygulamalarda standart bir C fonksiyonunun prototipini kendi yazmaz, bu prototip
bildiriminin
bulunduðu baºlýk dosyasýný #include öniºlemci komutuyla (ileride detaylý
göreceðiz) koda dahil eder.
Standart C fonksiyonlarýnýn prototip bildirimlerinin yapýlmamasý durumda hata ortaya çýkmaz.
Eðer geri dönüº deðeri türü int deðilse ve geri dönüº deðeri kullanýlýrsa, programda yanlýºlýk
söz konusu olacaktýr.
Derleme zamanýnda hata oluºumu söz konusu deðildir, çünkü derleyici fonksiyonun geri dönüº
deðerinin türünü int türden kabul edecek fakat daha sonra kaynak kod içinde fonksiyonun
tanýmlamasýný göremediðinden hata oluºmayacaktýr. Ancak programýn çalýºma zamaný
sýrasýnda fonksiyonun geri dönüº deðeri int türden bir deðer olarak alýnacaðýndan yanlýºlýk söz
konusu olacak ve program doðru çalýºmayacaktýr.
Standart C fonksiyonlarýnýn prototipleri sonu .h uzantýlý olan (header) baºlýk dosyalar içindedir.
Öniºlemci komutuyla ilgili baºlýk dosyasýnýn kaynak koda ilave edilmesiyle, aslýnda standart C
fonksiyonunun da prototip bildirimi yapýlmýº olmaktadýr. Zira öniºlemci modülünün çýktýsý olan
kaynak program artýk derleyiciye verildiðinde, ekleme yapýlmýº bu dosyada fonksiyonun
prototip bildirimi de bulunmaktadýr. ªüphesiz, baºlýk dosyayý kaynak koda ilave etmek yerine
standart C fonksiyonunun prototipini kendimiz de kaynak koda yazabiliriz, bu durumda da bir
yanlýºlýk söz konusu olmayacaktýr. Örnek :
Standart bir C fonksiyonu olan pow fonksiyonunun
ekleyebiliriz:
prototipini iki ºekilde kaynak koda
1. Fonksiyon prototipinin bulunduðu baºlýk dosyasýný kaynak koda bir öniºlemci komutuyla
dahil ederek.
#include <math.h>
2. Fonksiyonun prototipini kendimiz yazarak.
double pow(double taban, double us);
Ancak tercih edilecek yöntem baºlýk dosyasýný kaynak koda dahil etmek olmalýdýr. Çünkü:
1. Programcý tarafýndan fonksiyonun prototipi yanlýº yazýlabilir.
2. Baºlýk dosyalarýnýn kaynak koda dahil edilmesinin nedeni yalnýzca fonksiyon prototip
bildirimi deðildir. Baºlýk dosyalarýnda daha baºka bilgiler de vardýr. (Makrolar, sembolik
sabitler, tür tanýmlamalarý, yapý bildirimleri vs.)
Fonksiyon Prototip Bildirimi Ýle Arguman-Parametre Uyumu Kontrolü
Fonksiyon prototiplerinin ana amacý yukarýda da belirtildiði gibi, derleyiciye fonksiyonun geri
dönüº deðeri türü hakkýnda bilgi vermektir. Ancak fonksiyon prototip bildirimlerinde fonksiyon
parametrelerinin türleri belirtilmiºse, derleyici prototip bildirimindeki parametre deðiºkeni
sayýsýný fonksiyon çaðýrma ifadesindeki fonksiyona gönderilen arguman sayýsý ile karºýlaºtýrýr.
Örneðin:
float calculate(float, float);
biçiminde bir prototip yazýldýðýnda eðer calculate fonskiyonu eksik ya da fazla parametre ile
çaðýrýlýrsa derleme hatasý oluºacaktýr.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
96
Buy RoboPDF
FONKSÝYON PROTOTÝPLERÝ
x = calculate(5.8);
y = calculate(4.6, 7.9, 8.0)
/* hata eksik parametre ile çaðýrýlmýº */
/* hata fazla parametre ile çaðýrýlmýº */
Fonksiyon prototip bildiriminde parantezin içi boº býrakýlýrsa (buraya hiçbir parametre tür bilgisi
yazýlmazsa) bu durumun özel bir anlamý vardýr. Bu durumda derleyiciden parametre kontrolu
yapmasý istenmemiº olur. (Derleyici artýk fonksiyon çaðýrma ifadesindeki arguman sayýsýyla
fonksiyonun formal parametrelerinin sayýsýnýn eºitliðini kontrol etmez.) Parametre kontrolu
yapýlmasýnýn istenmemesi uygulamalarda sýk görülen bir durum deðildir. Parametre
deðiºkenlerinin sayýsý ile fonksiyona gönderilen arguman sayýsýnýn uyumu kontrolü, C diline
standartlaºýrma çalýºmalarý sýrasýnda eklenmiºtir. Klasik C diye adlandýrdýðýmýz, C dilinin
standartlaºtýrýlmasýndan önceki dönemde böyle bir kontrol söz konusu deðildi ve prototip
bildirimlerinde fonksiyon parantezlerinin içi boº býrakýlýrdý. Geriye doðru uyumun korunmasý ve
eskiden yazýlmýº kaynak kodlarýn da desteklenmesi amacýyla, fonksiyon prototip bildirimlerinde
fonksiyon parantezlerinin içinin boº býrakýlmasý durumu halen geçerli bir iºlem olarak
býrakýlmýºtýr.
float calculate(); /* derleyiciden parametre kontrolü yapmamasý isteniyor */
Yukarýdaki bildirimden calculate fonksiyonunun parametre almadýðý anlamý çýkmaz. Yukarýdaki
bildirimden sonra eðer calculate fonksiyonu aºaðýdaki ifadelerle çaðýrýlýrsa derleme zamaný
hatasý oluºmayacaktýr:
x = calculate (5.8);
y = calculate (4.6, 7.9, 8.0)
/* derleme zamanýnda hata oluºmaz */
/* derleme zamanýnda hata oluºmaz */
Eðer fonksiyonun gerçekten parametre deðiºkeni yoksa, ve derleyicinin fonksiyonun çaðýrýlmasý
durumunda arguman parametre deðiºkeni kontrolu yapmasý isteniyorsa, prototip bildiriminde
fonksiyon parantezi içerisine void anahtar sözcüðü yazýlmalýdýr.
float sample(void);
Burada sample fonksiyonunun parametre almadýðý bildirilmiºtir. Eðer fonksiyon
x = sample(20);
/* derleme hatasý */
Ýfadesiyle çaðýrýlýrsa derleme hatasý oluºur.
(C++ dilinde fonksiyon prototip bildiriminde, fonksiyon parametre parantezinin içinin boº
býrakýlmasý, fonksiyonun parametre deðiºkeni olmadýðýný göstermektedir. Baºka bir deyiºle,
prototip bildirimi sýrasýnda parantezlerin içini boº býrakmak, derleyiciden arguman sayýsý
kontrolu yapmasýný istememek anlamýna gelmez. C++'da arguman sayýsý ile parametre
deðiºlenlerinin sayýsýnýn uyumu daima derleyici tarafýndan kontrol edilir. Dolayýsýyla derleyici,
prototip bildiriminde, parametre parantezi içine bir ºey yazýlmadýðýný gördükten sonra,
fonksiyonun tanýmlanma ifadesinde parametre deðiºken(ler)inin varlýðýný görürse, bu durumu
bir error mesajý ile bildirir.)
Fonksiyon prototip bildiriminin yapýlmýº olmasý o fonksiyonun tanýmlamasýný ya da çaðýrýlmasýný
zorunlu kýlmaz.
Prototip bildirimi yapýlan bir fonksiyonu tanýmlamamak hata oluºturmaz.
Bir fonksiyonun prototip bildirimi birden fazla yapýlabilir.. Bu durumda hata oluºturmaz. Ama
yapýlan bildirimler birbirleriyle çeliºmemelidir.
Kaynak dosya içinde ayný fonksiyona iliºkin prototip bildirimlerinin farklý yerlerde ve aºaðýdaki
biçimlerde yapýldýðýný düºünelim :
int sample (int, int);
sample (int, int);
int sample(int x, int y);
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
97
Buy RoboPDF
11 . BÖLÜM :
sample(int number1, int number2);
Yukarýdaki bildirimlerinin hiçbirinde bir çeliºki söz konusu deðildir. Fonksiyon parametre
deðiºkenlerinin isimleri için daha sonraki bildirimlerde farklý isimler kullanýlmasý bir çeliºki
yaratmayacaktýr. Çünkü bu isimlerin faaliyet alaný (name scope) yalnýzca bildirimin yapýldýðý
parantezin içidir. Ancak aºaðýdaki farklý bildirimler derleme zamanýnda error oluºturacaktýr :
double func(int x, double y);
double func(int x, float y);
/* error! bildirimler arasýnda çeliºki var */
long sample(double x);
sample (double x);
/*
error!
bildirimler
arasýnda
çeliºki
var.
*/
Fonksiyon prototiplerinde parametre deðiºkenlerinin türlerinin de belirtilmesi, argumanlarýn
parametre deðiºkenlerime aktarýlmasýnda tür dönüºümüne olanak saðlamaktadýr. Bu durum tür
dönüºümleri konusunda ele alýnacaktýr.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
98
Buy RoboPDF
KOªUL OPERATÖRÜ
12 . BÖLÜM : KOªUL OPERATÖRÜ
Koºul operatörü (conditional operator) C dilinin 3 operand alan tek operatörüdür. (ternary
operator) Koºul operatörünün 3 operandý, ifade tanýmýna uygun herhangi bir ifade olabilir.
Koºul operatörünün genel sentaksý aºaðýdaki gibidir:
ifade1 ? ifade2 : ifade3
Koºul operatörü yukarýdaki biçimden de görüldüðü gibi birbirinden ayrýlmýº iki atomdan
oluºmaktadýr. ? ve : atomlarý operatörün 3 operandýný birbirinden ayýrýr.
Derleyici bir koºul operatörü ile karºýlaºtýðýný ? atomundan anlar ve ? atomunun solundaki
ifadenin (ifade1) sayýsal deðerini hesaplar. Eðer ifade1’in deðeri 0 dýºý bir sayýsal deðerse, bu
durum koºul operatörü tarafýndan doðru olarak deðerlendirilir, ve bu durumda yalnýzca
ifade2’nin sayýsal deðeri hesaplanýr.
Eðer ifade1’in deðeri 0 ise bu durum koºul operatörü tarafýndan yanlýº olarak deðerlendirilir ve
bu durumda yalnýzca ifade3’ün sayýsal deðeri hesaplanýr.
Diðer operatörlerde olduðu gibi koºul operatörü de bir deðer üretir. Koºul operatörünün ürettiði
deðer ifade1 doðru ise (0 dýºý bir deðer ise) ifade2’nin deðeri, ifade1 yanlýº ise ifade3’ün
deðeridir. Örnek:
m = x > 3 ? y + 5 : y – 5;
Burada önce x > 3 ifadesinin sayýsal deðeri hesaplanacaktýr. Bu ifade 0 dýºý bir deðerse (yani
doðru ise) koºul operatörü y + 5 deðerini üretecektir. x > 3 ifadesinin deðeri 0 ise (yani yanlýº
ise) koºul operatörü y – 5 deðerini üretecektir. Bu durumda m deðiºkenine x > 3 ifadesinin
doðru ya da yanlýº olmasýna göre y + 5 ya da y – 5 deðeri atanacaktýr.
Ayný iºlem if deyimi ile de yapýlabilir :
if (x > 3)
m = y + 5;
else
m = y – 5;
Koºul operatörü Operatör Öncelik Tablosunun 13. öncelik seviyesindedir. Bu seviye atama
operatörünün hemen üstüdür. Aºaðýdaki ifadeyi ele alalým:
x>3?y+5:y–5=m
Koºul operatörünün önceliði atama operatöründen daha yüksek olduðu için, önce koºul
operatörü ele alýnýr. x > 3 ifadesinin DOÐRU olduðunu ve operatörün y + 5 deðerini ürettiðini
düºünelim. Toplam ifadenin deðerlendirilmesinde kalan ifade
y+5=m
olacak ve bu da derleme zamaný hatasýna yol açacaktýr. Çünkü y + 5 ifadesi sol taraf deðeri
deðildir, nesne göstermez. (Lvalue required).
Koºul operatörünün birinci kýsmýný (ifade1) parantez içine almak gerekmez. Ancak, okunabilirlik
açýsýndan genellikle parantez içine alýnmasý tercih edilir.
(x >= y + 3) ? a * a : b
Koºul operatörünün üçüncü operandý (ifade3) konusunda dikkatli olmak gerekir. Örneðin :
m = a > b ? 20 : 50 + 5
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
99
Buy RoboPDF
12 . BÖLÜM :
a > b ifadesinin doðru olup olmamasýna göre koºul operatörü 20 ya da 55 deðerini üretecek ve
son olarak da m deðiºkenine koºul operatörünün ürettiði deðer atanacaktýr. Ancak m
deðiºkenine a > b ? 20 : 50 ifadesinin deðerinin 5 fazlasý atanmak isteniyorsa bu durumda
ifade aºaðýdaki gibi düzenlenmelidir:
m = (a > b ? 20 : 50) + 5
Koºul operatörünün 3 operandý da bir fonksiyon çaðýrma ifadesi olabilir, ama çaðýrýlan
fonksiyonlarýn geri dönüº deðeri üreten fonksiyonlar olmasý (void olmayan) gerekmektedir. Üç
operanddan biri geri dönüº deðeri void olan bir fonksiyona iliºkin fonksiyon çaðýrma ifadesi
olursa koºul operatörü deðer üretmeyeceðinden bu durum derleme zamanýnda hata
oluºmasýna neden olacaktýr.
Aºaðýdaki kod parçasýný inceleyelim:
#include <stdio.h>
int func1(void);
int func2(void);
int func3(void);
int main()
{
int m;
}
m = func1() ? func2() : func3();
return 0;
Yukarýda koºul operatörünün kullanýldýðý ifadede m deðiºkenine, func1 fonksiyonunun geri
dönüº deðerinin 0 dýºý bir deðer olmasý durumunda func2 fonksiyonunun geri dönüº deðeri,
aksi halde func3 fonksiyonunun geri dönüº deðeri atanacaktýr.
Koºul operatörünün ürettiði bir nesne deðil bir deðerdir. Koºul operatörünün ürettiði deðer
nesne göstermediði için bu deðere bir atama yapýlamaz. Aºaðýdaki if deyimini inceleyelim:
if (x > y)
a = 5;
else
b = 5;
Yukarýdaki if deyimine x > y ifadesinin doðru olmasý durumunda a deðiºkenine, yanlýº olmasý
durumunda ise b deðiºkenine 5 deðeri atanýyor. Ayný iºi koºul operatörü kullanarak yapmak
istenip de aºaðýdaki ifade oluºturulursa:
(x > y) ? a : b = 5;
bu durum derleme zamaný hatasýna yol açacaktýr. Çünkü koºul operatörünün ürettiði a ya da b
deðiºkenlerinin deðeridir, nesnenin kendisi deðildir. Böyle bir atama sol tarafýn nesne gösteren
bir ifade olmamasýndan dolayý derleme zamanýnda hata oluºturur.
Ayný nedenden dolayý aºaðýdaki ifadenin deðerlendirilmeside derleme zamanýnda hata
oluºmasýna neden olacaktýr:
(x > 5 ? y : z)++;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
100
Buy RoboPDF
KOªUL OPERATÖRÜ
Parantez içindeki ifade deðerlendirildiðinde elde edilen y ya da z nesneleri deðil bunlarýn
deðerleridir. Yani postfix ++ operatörünün operandý nesne deðildir. Bu durumda error
oluºacaktýr. (L value required!)
Koºul Operatörünün Kullanýldýðý Durumlar
Koºul operatörü her zaman if deyimine bir alternatif olarak kullanýlmamalýdýr. Koºul
operatörünün kullanýlmasýnýn tavsiye edildiði tipik durumlar vardýr ve bu durumlarda genel
fikir, koºul operatörünün ürettiði deðerden ayný ifade içinde faydalanmak, bu deðeri bir yere
aktarmaktýr.
1. Bir önermenin doðru ya da aynlýº olmasýna göre farklý iki deðerden birinin ayný deðiºkene
aktarýlmasý durumunda:
p = (x == 5) ? 10 : 20;
m = (a >= b + 5) ? a + b : a – b;
Yukarýdaki deyimleri if else yapýsýyla 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 oluºtururken:
return (x > y ? 10 : 20);
Bu örnekte x > y ifadesinin doðru olup olmamasýna göre fonksiyonun geri dönüº deðeri 10
ya da 20 olacaktýr. Yukaridaki ifade yerine aºaðýdaki if yapýsý da kullanýlabilirdi :
if (x > y)
return 10;
else
return 20;
3. Fonksiyon çaðýrma ifadelerinde arguman olarak:
func(a == b ? x : y);
Bu ifadede func fonksiyonu a deðiºkeninin b degiºkenine eºit olup olmamasý durumuna
göre x ya da y argumanlarýyla çaðýrýlacaktýr. if deyimiyle aºaðýdaki ºekilde karºýlanabilir:
if (a == b)
func(x);
else
func(y);
4. if deyiminde koºul ifadesi olarak da koºul operatörünün kullanýldýðý görülür:
if ( y == (x > 5 ? 10 : 20))
Yukaridaki ifadede x > 5 ifadesinin doðru olup olmamasýna göre if parantezi içinde y
deðiºkeninin 10 ya da 20’ye eºitliði test edilecektir.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
101
Buy RoboPDF
12 . BÖLÜM :
Yukarýdaki durumlarda koºul operatörünün if deyimine tercih edilmesi iyi tekniktir. Bu
durumlarda koºul operatörü daha okunabilir bir yapý oluºturmaktadýr. (C’ye yeni baºlayanlar
için if yapýsý daha iyi okunabilir ya da algýlanabilir, ancak bir C programcisi için koºul
operatörünün kullanýlmasý daha okunabilir bir yapý oluºturur.)
Koºul operatörünün bilinçsizce kullanýlmamasý gerekir. Eðer koºul operatörünün ürettiði
deðerden doðrudan faydalanýlmayacaksa koºul operatörü yerine if kontrol deyimi tercih
edilmelidir. Örneðin:
x > y ? a++ : b++;
Deyiminde koºul operatörünün ürettiði deðerden faydalanýlmamaktadýr. Burada aºaðýdaki if
yapýsý tercih edilmelidir:
if (x > y)
a++;
else
b++;
Baºka bir örnek:
x == y ? printf(“eºit\n”) : printf(“eºit deðil\n”);
Bu örnekte printf fonksiyonunun bir geri dönüº deðeri üretmesinden faydalanýlarak koºul
operatörü kullanýlmýºtýr. Koºul operatörü x == y ifadesinin doðru olup olmamasýna göre, 2.
veya 3. ifade olan printf fonksiyonu çaðýrma ifadelerinden
birinin deðerini (geri dönüº
deðerini) üretecektir. (Bu da aslýnda ekrana yazýlan karakter sayýsýdýr.) Ama ifade içinde koºul
operatörünün ürettiði deðerin kullanýlmasý söz konusu deðildir. Burada da if kontrol deyimi
tercih edilmelidir :
if (x == y)
printf(“eºit\n”);
else
printf(“eºit deðil\n”);
Koºul operatörünün ikinci ve üçüncü operandlarýnýn türleri farklý ise tür dönüºtürme kurallari
diðer operatörlerde olduðu gibi devreye girecektir:
long a;
int b;
m = (x == y) ? b : a;
Bu örnekte a nesnesi long türden b nesnesi ise int türdendir. x == y karºýlaºtýrma ifadesi
yanlýº olsa bile tür dönüºümü gerçekleºecek ve int türden olan b long türe dönüºtürülecektir.
Bazý durumlarda koºul operatörünün de if kontrol deðiminin de kullanýlmasý gerekmeyebilir.
if (x > 5)
m = 1;
else
m = 0;
Yukarýdaki if deyimi koºul operatörü ile aºaðýdaki ºekilde oluºturulabilirdi :
m = (x > 5) ? 1 : 0;
Ancak koºul operatörünün üreteceði deðerlerin 1 veya 0 olabileceði durumlarda doðrudan
karºýlaºtýrma operatörünü kullanmak daha iyi teknik olarak deðerlendirilmelidir.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
102
Buy RoboPDF
KOªUL OPERATÖRÜ
m = x > 5;
Baºka bir örnek :
return x == y ? 1 : 0;
yerine
return x == y;
yazabilirdik.
Aºaðýda tanýmlanan is_leap fonksiyonunu inceleyelim, fonksiyonun geri dönüº deðerinin
üretilmesinde koºul operatörü kullanýlmayýp doðrudan mantýksal operatörlerin 0 ya da 1 deðeri
üretmeleri fikrinden faydalanýlmýºtýr:
#define BOOL
int
BOOL is_leap(int year)
{
return !(year % 4) && year % 100 || !(year % 400);
}
Koºul operatörünün öncelik yönü saðdan soladýr. (right associative). Bir ifade içinde birden
fazla koºul operatörü varsa önce en saðdaki deðerlendirilecektir.
Aºaðýdaki kod parçasýný inceleyelim :
int x = 1;
int y = 1;
m = x < 5 ? y == 0 ? 4 : 6 : 8;
printf("m = %d\n", m);
Yukarýdaki kod parçasýnda printf fonksiyonu çaðýrýmýnda m deðiºkeninin deðeri 6 olarak
yazdýrýlacaktýr. Ýfade aºaðýdaki gibi ele alýnacaktýr :
m = x < 5 ? (y == 0 ? 4 : 6) : 8;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
103
Buy RoboPDF
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
Buy RoboPDF
DÖNGÜ DEYÝMLERÝ
13 . BÖLÜM : DÖNGÜ DEYÝMLERÝ
Bir program parçasýnýn yinelemeli olarak çalýºtýrýlmasýný saðlayan kontrol deyimlerine döngü
denir. C dilinde 3 ayrý döngü deyimi vardýr:
Kontrolün baºta yapýldýðý while döngüleri
Kontrolün sonda yapýldýðý while döngüleri (do while döngüleri)
for döngüleri
Bu döngü deyimlerinden en fazla kullanýlaný for deyimidir. for deyimi yalnýzca C dilini deðil,
tüm programlama dillerinin en güçlü döngü yapýsýdýr. Aslýnda while ya da do while döngüleri
olmasa da bu döngüler kullanýlarak yazýlan kodlar, for döngüsüyle yazýlabilir. Ancak
okunabilirlik açýsýndan while ve do while döngülerinin tercih edildiði durumlar vardýr.
Kontrolun Basta Yapýldýðý while Döngüleri
Genel biçimi:
while (ifade)
deyim;
while anahtar sözcüðünü izleyen parantez içerisindeki ifadeye kontrol ifadesi (control
statement) denir. while parantezini izleyen ilk deyime döngü gövdesi denir. Döngü gövdesi
basit bir deyim olabileceði gibi, bloklanmýº birden fazla deyimden de (bileºik deyim) oluºabilir.
while deyiminin icrasý ºu ºekilde olur: Kontrol ifadesinin sayýsal deðeri hesaplanýr. Kontrol
ifadesinin sayýsal deðeri 0 dýºý bir deðerse, mantýksal olarak doðru kabul edilir ve döngü
gövdesindeki deyim ya da deyimler çalýºtýrýlýr. Kontrol ifadesinin sayýsal deðeri 0 ise mantýksal
olarak yanlýº kabul edilir programýn akýºý döngünün dýºýndaki ilk deyimle devam eder. Yani
while döngüsü, kontrol ifadesinin sayýsal deðeri 0 dýºý bir deðer olduðu sürece, döngü
gövdesini oluºturan deyim(ler)in icrasý ile devam eder.
Daha önce belirttiðimiz gibi C dilinde yalýn bir deyimin olduðu yere bileºik bir deyim de
yerleºtirilebilir. Bu durumda while döngüsü aºaðýdaki gibi de oluºturulabilir :
while (ifade) {
ifade1;
ifade2;
ifade3;
......
}
Bu durumda kontrol ifadesinin sayýsal deðeri 0 dýºý bir deðer olduðu (doðru)
parantezleri arasýnda kalan tüm deyimler icra edilecektir. Örnek:
sürece blok
#include <stdio.h>
int main()
{
int i = 0;
}
while (i < 10) {
printf ("%d\n", i)
++i;
}
return 0;
Baºka bir örnek:
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
105
Buy RoboPDF
13 . BÖLÜM :
#include <stdio.h>
#include <ctype.h>
int main()
{
char ch;
}
while (ch = getch(), toupper(ch) != 'Q')
putchar(ch);
return 0;
Baºka bir örnek daha:
int main()
{
char ch;
}
while (ch = getch(), isupper (ch))
putchar(ch);
return 0;
while parantezinin içindeki ifade yani koºul ifadesi, ifade tanýmýna uygun herhangi bir ifade
olabilir.
while (1) {
....
}
Yukarýdaki while deyiminde kontrol ifadesi olarak bir sabit olan 1 sayýsý kullanýlmýºtýr. 1 deðeri
0 dýºý bir deðer olduðundan ve kontrol ifadesi bir deðiºkene baðlý olarak deðiºemeyeceðinden,
böyle bir döngüden çýkmak mümkün olmayacaktýr. Bu tür döngülere sonsuz döngüler (infinite
loops) denir. Sonsuz döngüler bir yanlýºlýk sonucu oluºturulabildiði gibi, bilinçli olarak da
oluºturulabilir. Sonsuz döngülerden bazý yöntemlerle çýkýlabilir.
break Anahtar Sözcüðü
break anahtar sözcüðü ile bir döngü sonlandýrýlabilir. Kullanýmý
break;
ºeklindedir. Programýn akýºý break anahtar sözcüðünü gördüðünde, döngü kýrýlarak döngünün
akýºý döngü gövdesi dýºýndaki ilk deyim ile devam eder. Yani koºulsuz olarak döngüden çýkýlýr.
int main (void)
{
char ch;
}
while (1) {
ch = getch();
if (ch == 'q')
break;
putchar(ch);
}
printf("döngüden çýkýldý!..\n");
return 0;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
106
Buy RoboPDF
DÖNGÜ DEYÝMLERÝ
Yukarýdaki programda bir sonsuz döngü oluºturulmuºtur. Döngü içerisinde, döngünün her bir
iterasyonunda ch deðiºkenine klavyeden bir deðer alýnmaktadýr. Eðer klavyeden alýnan
karakter 'q' ise break anahtar sözcüðüyle programýn akýºý while döngü gövdesi dýºýndaki ilk
deyimle devam edecektir.
Ýçiçe Döngüler
Bir döngünün gövdesini baºka bir kontrol deyimi oluºturabilir. Döngü gövdesini oluºturan
kontrol deyimi bir if deyimi olabileceði gibi baºka bir döngü 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;
Ýçiçe döngülerde içerideki döngüde break deyimi kullanýldýðýnda yalnýzca içerideki döngüden
çýkýlýr, her iki döngüden birden çýkmak için goto deyimi kullanýlmalýdýr. (ileride göreceðiz)
while döngüsü bir bütün olarak tek deyim içinde ele alýnýr. Örnek:
while (1)
while (1) {
.....
.....
.....,
}
Burada ikinci while döngüsü tek bir kontrol deyimi olarak ele alýnacaðý için, bloklamaya gerek
yoktur.
while döngüsünün yanlýºlýkla boº deyim ile kapatýlmasý çok sýk yapýlan bir hatadýr.
int main()
{
int i = 10;
}
while (--i > 0);
/* burada bir boº deðim var */
printf("%d\n", i);
return 0;
Döngü while parantezi içerisindeki ifadenin deðeri 0 olana kadar devam eder ve boº deðim
döngü gövdesi olarak icra edilir. Döngüden çýkýldýðýnda ekrana 0 basýlýr.
Sonlandýrýcý ; while parantezinden sonra konulursa herhangi bir sentaks hatasý oluºmaz.
Derleyici while döngüsünün gövdesinin yalnýzca bir boº deyimden oluºtuðu sonucunu çýkartýr.
Eðer bir yanlýºlýk sonucu deðil de bilinçli olarak while döngüsünün gövdesinde boº deyim (null
statement) bulunmasý isteniyorsa, okunabilirlik açýsýndan, bu boº deyim while parantezinden
hemen sonra deðil, alt satýrda ve bir tab içeriden yazýlmalýdýr.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
107
Buy RoboPDF
13 . BÖLÜM :
while Döngüsü Ýçerisinde Postfix ++ ya da -- Operatörünün Kullanýlmasý
Bir postfix artýrým ya da eksiltme iºlemi yapýldýðýnda önce döngüye devam edilip edilmeyeceði
kararý verilir, sonra artýrým ya da eksiltim uygulanýr. Örnek :
int main()
{
int i = 0;
}
while (i++ < 100)
printf("%d\n", i);
printf("%d\n", i);
return 0;
/* ekrana 101 deðerini basar. */
Baºka bir örnek:
...
int i = 10;
while (i-- > 0)
printf("%d\n", i);
printf("%d\n", i);
n bir pozitif tam sayý olmak üzere while döngüsü kullanýlarak n defa dönen bir while döngüsü
oluºturmak için
while (n-- > 0)
ya da
while (n--)
kullanýlabilir. Aºaðýdaki içiçe döngü yapýsý bir gecikme saðlamak için kullanýlmýºtýr.
int main()
{
int i = 0;
long j;
}
while (i++ < 10) {
printf("%d\n", i);
j = 1000000L;
while (j--> 0 )
;
return 0;
Bazen döngüler bilinçli bir ºekilde boº deyimle kapatýlmak istenebilir. Bu durumda boº deyim
normal bir deyim gibi tablama kuralýna uygun olarak yerleºtirilmelidir.
Kontrolün Sonda Yapýldýðý while Döngüleri
Genel biçim;
1. do
ifade 1;
while (ifade 2);
2. do {
ifade 1;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
108
Buy RoboPDF
DÖNGÜ DEYÝMLERÝ
ifade 2;
} while (ifade);
do while döngüsünde kontrol ifadesi sondadýr. while parantezinden sonra sonlandýrýcý ";"
bulunmalýdýr. Yani buradaký sonlandýrýcý yanlýºlýk sonucu koyulmamýºtýr, deyime iliºkin
sentaksýn bir parçasýdýr. Döngü gövdesindeki 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;
}
Baºka bir örnek:
int main()
{
char ch;
}
do {
printf ("(e)vet / (h)ayýt?\n");
ch = getch();
} while (ch != 'e' && ch != 'h');
printf("ok...\n");
return 0;
Uygulama
1'den 100'e kadar sayýlarý her satýrda beº tane olacak biçimde ekrana yazan bir C programýnýn
yazýlmasý:
#include <stdio.h>
int main()
{
int i = 0;
}
do {
printf("%d ", ++i);
if (i % 5 == 0)
printf("\n");
} while (i < 100);
return 0;
Baºka bir çözüm:
#include <stdio.h>
void main()
{
int i = 0;
while (i < 100) {
printf ("%d", i);
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
109
Buy RoboPDF
13 . BÖLÜM :
}
if (i % 5 == 4)
printf("\n");
++i;
return 0;
Uygulama
Bir tamsayýnýn basamak sayýsýný 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 döngüsü kullanarak yazalým.
...
while (n > 0) {
n /= 10;
digits++;
}
...
do while döngüsü yerine while döngüsü kullanýldýðýnda, girilen sayýnýn 0 olmasý durumunda
döngü gövdesindeki deyimler hiç icra edilmeyecekti. Bu durumda ekranda:
The number has 0 digit(s)
yazýsý çýkacaktý.
for Döngüleri
for döngüleri yalnýzca C dilinin deðil, belki de tüm programlama dillerinin en güçlü döngü
yapýlarýdýr. for döngülerinin genel biçimi ºu ºekildedir:
for (ifade1; ifade2; ifade3)
deyim1;
for (ifade1; ifade2; ifade3)
deyim1;
deyim2;
...
}
{
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
110
Buy RoboPDF
DÖNGÜ DEYÝMLERÝ
Derleyici for anahtar sözcüðünden sonra bir parantez açýlmasýný ve parantez içerisinde iki
noktalý virgül bulunmasýný bekler. Bu iki noktalý virgül for parantezini üç kýsýma ayýrýr. Bu
kýsýmlar yukarýda ifade1 ifade2 ve ifade 3 olarak gösterilmiºtir.
for parantezi içinde mutlaka 2 noktalý virgül bulunmalýdýr. for parantezi içinin boº býrakýlmasý,
ya da for parantezi içerisinde 1, 3 ya da daha fazla noktalý virgülün bulunmasý derleme
zamanýnda hata oluºmasýna yol açacaktýr.
for parantezinin kapanmasýndan sonra gelen ilk deyim döngü gövdesini (loop body) oluºturur.
Döngü gövdesi basit bir deyimden oluºabileceði gibi, bileºik deyimden de yani blok içine
alýnmýº birden fazla deyimden de oluºabilir.
for parantezi içerisindeki her üç kýsýmýn da ayrý ayrý iºlevleri vardýr.
for parantezinin 2. kýsýmýný oluºturan ifadeye kontrol ifadesi denir. (control expression). Týpký
while parantezi içindeki ifade gibi, döngünün devamý konusunda bu ifade söz sahibidir. Bu
ifadenin deðeri 0 dýºý bir deðer ise, yani mantýksal olarak doðru ise, döngü devam eder. Döngü
gövdesindeki deyim(ler) icra edilir. Kontrol ifadesinin deðeri 0 ise programýn akýºý for
döngüsünün dýºýndaki ilk deyimle devam edecektir.
Programýn akýºý for deyimine gelince, for parantezinin 1. kýsmý 1 kez icra edilir ve genellikle
döngü deðiºkenine ilk deðer verme amacýyla kullanýlýr. (Böyle bir zorunluluk yoktur).
for döngüsünün 3. kýsým döngü gövdesindeki deyim ya da deyimler icra edildikten sonra,
dönüºte çalýºtýrýlýr. Ve çoðunlukla döngü deðiºkeninin artýrýlmasý ya da azaltýlmasý amacýyla
kullanýlýr. (Böyle bir zorunluluk yok.)
for (ilk deðer; koºul; iºlem) {
...
...
...
}
int main()
{
int i;
}
for (i = 0; i < 2; ++i)
printf(“%d\n”, i);
printf(“son deðer = %d\n”, i);
return 0;
Yukarýdaki programý inceleyelim:
Programýn akýºý for deyimine gelince, önce for parantezi içindeki 1. ifade icra ediliyor. Yani i
deðiºkenine 0 deðeri atanýyor.
ªimdi programýn akýºý for parantezinin 2. kýsmýna yani kontrol ifadesine geliyor ve i < 2 koºulu
sorgulanýyor. Kontrol ifadesinin deðeri 0 dýºý bir deðer olduðu için, ifade mantýksal olarak doðru
kabul ediliyor ve programýn akýºý döngü gövdesine geçiyor. Döngü gövdesi bloklanmadýðý için,
döngü gövdesinde tek bir deyim var. (basit deyim). Bu deyim icra ediliyor. Yani ekrana i
deðiºkeninin deðeri yazýlarak imleç alt satýra geçiriliyor.
Programýn akýºý bu kez for parantezinin 3. kýsýmýna geliyor ve buradaki ifade bir deyimmiº gibi
icra edeiliyor, yani i deðiºkeninin deðeri 1 artýrýlýyor. i deðiºkeninin deðeri 1 oluyor.
2. ifade yeniden deðerlendiriliyor ve i < 2 ifadesi doðro olduðu için bir kez daha döngü gövdesi
içra ediliyor.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
111
Buy RoboPDF
13 . BÖLÜM :
Programýn akýºý yine for parantezinin 3. kýsýmýna geliyor ve buradaki ifade bir deyimmiº gibi
icra edeiliyor, yani i deðiºkeninin deðeri 1 artýrýlýyor. i deðiºkeninin deðeri 2 oluyor.
Programýn akýºý yine for parantezinin 2. kýsmýna geliyor ve buradaki kontrol ifadesi tekrar
sorgulanýyor. i < 2 ifadesi bu kez yanlýº olduðu için programýn akýºý döngü gövdesine girmiyor
ve programýn akýºý döngü gövdesi dýºýndaki ilk deyimle devam ediyor.
Yani ekrana :
son deðer = 2
yazýlýyor.
Uygulama
1’den 100’e kadar olan sayýlarýn toplamýný bulan program :
int main()
{
int i;
int total = 0;
}
for (i = 0; i < 100; ++i)
total += i;
printf(“Toplam = %d”, total);
return 0;
Döngü deðiºkeninin tamsayý türlerinden birinden olmasý gibi bir zorunluluk yoktur. Döngü
deðiºkeni gerçek sayý türlerinden 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 söylendiði gibi for parantezi içindeki her 3 kýsým da ifade tanýmýna uygun ifadeler
içerebilir, yani bir döngü deðiºkenine ilk deðer verilmesi, döngü deðiºkenine baðlý bir koºul
ifadesi olmasý, döngü deðiºkeninin de azaltýlmasý ya da artýrýlmasý bir zorunluluk deðildir.
int main()
{
char ch;
}
for (ch = getch(); ch != ‘p’ ; ch = getch())
putchar(ch);
return 0;
Baºka bir örnek:
int main()
{
for (printf(“1. ifade\n"); printf(“2. ifade\n”), getch() != ‘q’; printf(“3. ifade\n));
}
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
112
Buy RoboPDF
DÖNGÜ DEYÝMLERÝ
Virgül operatörü ile birleºtirilmiº deðimlerin soldan saða doðru sýrayla icra edileceðini ve toplam
ifadenin üreteceði deðerin en saðdaki ifadenin deðeri olacaðýný hatýrlayýn.
for döngüsünün 1. kýsmý hiç olmayabilir. Örneðin döngü dýºýnda, programýn akýºý for deyiminin
icrasýna gelmeden önce, döngü deðiºkenine ilk deðer verilmiº olabilir.
...
i = 0;
for (; i < 100; ++i)
printf(“%d\n”, i);
for döngüsünün 3. kýsmý da olmayabilir. Döngü deðiºkeninin artýrýlmasý ya da eksiltilmesi for
parantezi içi yerine döngü gövdesi içerisinde gerçekleºtirilebilir.
1. ve 3. kýsmý olmayan (yalnýzca 2. kýsma sahip) bir for döngüsü örneði:
...
i = 0;
for (; i < 100; ) {
printf(“%d\n”, i);
++i;
}
...
1.ve 3. kýsmý olmayan for döngüleri tamamen while döngüleriyle eºdeðerdir. C’de for
döngüleriyle while döngüleriyle yapabildiðimiz herºeyi yapabiliriz. O zaman ºöyle bir soru
aklýmýza gelebilir: Madem for döngüleri while döngülerini tamamen kapsýyor, o zaman
while döngülerine ne gerek var? while döngülerinin bazý durumlarda kullanýlmasý for
döngülerine göre çok daha okunabilir bir yapý yaratmaktadýr.
for parantezinin 2. kýsmý da hiç olmayabilir. Bu durumda kontrol ifadesi olmayacaðý için döngü
bir koºula baðlý olmaksýzýn sürekli dönecektir. Yani sonsuz döngü oluºturulacaktýr. Ancak iki
adet noktalý virgül yine parantez içinde mutlaka bulunmak zorundadýr.
for parantezinin hiçbir kýsmý olmayabilir. Ancak yine iki noktalý virgül bulunmak zorundadýr:
...
i = 0;
for (;;) {
printf(“%d\n”, i);
++i;
if (i == 100)
break;
}
...
for (;;) ile while (1) eºdeðerdir. Ýkisi de sonsuz döngü belirtir.
Sonsuz döngü oluºturmak için for (;;) biçimi while (1)'e göre daha çok tercih edilir. Bunun
nedeni eski derleyicilerde while(1) ifadesi kullanýldýðýnda dögünün her dönüºünde kontrol
ifadesinin tekrar test edilmesidir. Ama yeni derleyicilerde böyle bir kontrol söz konusu deðildir.
Ama bazý programcýlar while (1) ifadesini tercih ederler. (Tabi burada kontrol ifadesi 1 yerine
0 dýºý herhangi bir deðer de olabilirdi ama geleneksel olarak 1 ifadesi kullanýlmaktadýr.)
Sonsuz Döngülerden Çýkýº
1. break anahtar sözcüðü ile.
Bu durumda programýn akýºý döngü gövdesi dýºýndaki ilk deyime yönlenecektir. (eðer iç içe
döngü varsa break anahtar sözcüðü ile yalnýzca içteki döngüden çýkýlacaktýr.)
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
113
Buy RoboPDF
13 . BÖLÜM :
2. return anahtar sözcüðü ile
bu durumda fonksiyonun (main de olabilir) icrasý sona erecektir.
3. goto anahtar sözcüðüyle.
Ýçiçe birden fazla döngü varsa en içteki döngü içinden en dýºtaki döngünün dýºýna kadar
çýkabiliriz. (goto anahtar sözcüðünün çok az sayýdaki faydalý kullanýmýndan biri budur.)
4. exit fonksiyonu ile. (ileride göreceðiz)
continue Anahtar Sözcüðü
continue anahtar sözcüðü de týpký break anahtar sözcüðü gibi bir döngü içerisinde
kullanýlabilir. Programýn akýºý continue anahtar sözcüðüne geldiðinde sanki döngü yinelemesi
bitmiº gibi yeni bir yinelemeye geçilir. Eðer for döngüsü içerisinde kullanýlýyorsa yeni bir
yinelemeye geçmeden önce döngünün 3. kýsmý yapýlýr. Ö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 sözcüðü bir döngüyü sonlandýrmak için, continue anahtar sözcüðü de bir
döngünün o anda içinde bulunulan yinelemesini sonlandýrmak için kullanýlýr.
continue anahtar sözcüðü özellikle, döngü içerisinde uzun if deyimlerini varsa, okunabilirliði
artýrmak amacýyla kullanýlýr.
for (i = 0; i < n; ++i) {
ch = getch();
if (!isspace(ch)) {
...
...
...
}
}
Yukarýdaki kod parçasýnda döngü içinde, klavyeden getch fonksiyonu ile deðer atanan ch
deðiºkeni boºluk karakteri deðilse, bir takým deyimlerin icrasý istenmiº. Yukarýdaki durum
continue anahtar sözcüðüyle daha okunabilir hale getirilebilir :
for (i = 0; i < n; ++i) {
ch = getch();
if (isspace(ch))
continue;
...
...
...
}
n kere dönen for deyimi kalýplarý
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
114
Buy RoboPDF
DÖNGÜ DEYÝMLERÝ
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 döngüden çýkmak için döngü deðiºkeni ile oynamak kötü bir tekniktir. Bu programlarý
okunabilirlikten uzaklaºtýrýr. Bunun yerine break anahtar sözcüðü ile döngülerden çýkýlmalýdýr.
Uygulama
Basamaklarýnýn küpleri toplamý kendisine eºit olan 3 basamaklý sayýlarý 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 sayýsý ºartlarý saglýyor\n", number);
number++;
}
return 0;
Baºka bir çözüm:
#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 sayýsý ºartlarý saðlýyor\n", i);
}
return 0;
Uygulama
Kendisine gönderilen iki tamsayýnýn obeb ve okek deðerlerini hesaplayan fonksiyonlar.
#include <stdio.h>
#include <conio.h>
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
115
Buy RoboPDF
13 . BÖLÜM :
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 gönderilen int türden argumanýn faktöriyel deðerini 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 deðiºkeninde tutulan tamsayýnýn ikinci parametre deðiºkeninde tutulan
tamsayý kuvvetini hesaplayan fonksiyon.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
116
Buy RoboPDF
DÖNGÜ DEYÝMLERÝ
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 gönderilen sayýnýn asal sayý olup olmadýðýný test eden isprime fonksiyonu.
int isprime(long number)
{
int k;
if (number
return
if (number
return
if (number
return
if (number
return
}
== 0 || number == 1)
0;
% 2 == 0)
number == 2;
% 3 == 0)
number == 3;
% 5 == 0)
number == 5;
for (k = 7; k * k <= number; k += 2)
if (number % k == 0)
return 0;
return 1;
Uygulama
Bölenlerinin toplamýna eºit olan sayýlara mükemmel tamsayý (perfect integer) sayý denir.
Örneðin 28 sayýsý bir mükemmel tamsayýdýr.
1 + 2 + 4 + 7 + 14 = 28
Kendisine gönderilen bir argumanýn mükemmel tamsayý olup olmadýðýný test eden is_perfect
fonksiyonu.
#include <stdio.h>
int is_perfect(int number);
int main()
{
int k;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
117
Buy RoboPDF
13 . BÖLÜM :
}
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 türden bir sayýyý çarpanlarýna ayýran ve çarpanlarý küçükten büyüðe ekrana yazdýran
display_factors fonksiyonunu.
#include <stdio.h>
#include <conio.h>
void factors(int number);
/* test kodu : 1111 ile 1200 arasýndaki sayýlarý çarpanlara ayýrýyor */
int main()
{
int k;
}
for (k = 1111; k < 1200; ++k) {
printf("%d sayýsýnýn ç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 alýnan cümleyi ekrana yazan ve cümle "." karakteriyle sonlanýnca yazýlan toplam
kelime sayýsýný ve ortalama kelime uzunlugunu bulan program.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
118
Buy RoboPDF
DÖNGÜ DEYÝMLERÝ
#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 sayýsý = %d\n", wordcount);
printf("ortalama uzunluk = %f\n", (double) total / wordcount);
return 0;
Uygulama
Klavyeden sürekli karakter alýnmasýný saðlayan, alýnan karakterleri ekranda gösteren, ancak
arka arkaya "xyz" karakterleri girildiðinde 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;
Çalýºma Sorularý
Prototipi aºaðýda verilen isprimex fonksiyonunu tanýmlayýnýz.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
119
Buy RoboPDF
13 . BÖLÜM :
int isprimex(long number);
isprimex fonksiyonuna gönderilen argumanýn asal olup olmadýðý test edilecek, eðer sayý asal
ise bu kez sayýnýn basamak deðerleri toplanarak elde edilen sayýnýn asal olup olmadýðý test
edilecektir. Bu iºlem sonuçta tek basamaklý bir sayý kalana kadar devam edecektir. Eðer en son
elde edilen tek basamaklý sayý dahil tüm sayýlar asal ise isprimex fonksiyonu 0 dýºý bir deðere
geri dönecektir. Eðer herhangi bir kademede asal olmayan bir sayý elde edilirse fonksiyon 0
deðerine geri dönecektir.
Yazdýðýnýz fonksiyonu aºaðýdaki 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;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
120
Buy RoboPDF
TÜR DÖNܪÜMLERÝ
14 . BÖLÜM : TÜR DÖNܪÜMLERÝ
Bilgisayarlarýn aritmetik iºlemleri gerçekleºtirmesinde bir takým kýsýtlamalar söz konusudur.
Bilgisayarlarýn aritmetik bir iºlemi gerçekleºtirmesi için (genellikle) iºleme sokulan operandlarýn
uzunluklarýnýn ayný olmasý (yani bit sayýlarýnýn ayný olmasý) ve ayný ºekilde belleðe yerleºtirilmiº
olmalarý gerekmektedir. Örnek vermek gerekirse, bilgisayar 16 bit uzunluðunda iki tam sayýyý
doðrudan toplayabilir ama 16 bit uzunluðunda bir tam sayý ile 32 bit uzunluðundaki bir
tamsayýyý ya da 32 bit uzunluðunda bir tamsayý ile 32 bit uzunluðunda bir gerçek sayýyý
doðrudan toplayamaz.
C programlama dili, deðiºik türlerin ayný ifade içerisinde bulunmalarýna izin verir. Yani tek bir
ifadede bir tamsayý türünden deðiºken, bir float sabit ya da char türden bir deðiºken birlikte
yer alabilir. Bu durumda C derleyicisi bunlarý herhangi bir iºleme sokmadan önce bilgisayar
donanýmýnýn ifadeyi deðerlendirebilmesi için uygun tür dönüºümlerini yapar.
Örneðin 16 bitlik bir int sayýyla 32 bitlik bir int sayýyý topladýðýmýzda, derleyici önce 16 bitlik
int sayýyý 32 bit uzunluðunda bir int sayýya dönüºtürecek ve ondan sonra toplama iºlemini
gerçekleºtirecektir. Yine 16 bitlik bir int sayýyla 64 bitlik bir double sayýyý çarpmak
istediðimizde derleyici önce int sayýyý 64 bitlik bir double sayýya dönüºtürecektir. Bu tür
dönüºümü daha komplekstir çünkü int ve double sayýlar bellekte farklý ºekillerde tutulurlar.
Bu tür dönüºümleri programcýnýn kontrolü dýºýnda otomatik olarak gerçekleºtirilirler. Bu tür
dönüºümlerine otomatik tür dönüºümleri (implicit type conversions) diyeceðiz. C dili
programcýya herhangi bir deðiºkenin ya da sabitin türünü, bir operatör kullanarak deðiºtirme
olanaðý da verir. Programcý tarafýndan yapýlan bu tip tür dönüºümlerine bilinçli tür dönüºümleri
(explicit type conversions/type casts) diyeceðiz.
Önce otomatik tür dönüºümlerini inceleyeceðiz. Otomatik tür dönüºümleri ne yazýk ki karmaºýk
yapýdadýr ve iyi öðrenilmemesi durumunda programlarda hatalar kaçýnýlmazdýr. Zira C dilinde
11 ana tür vardýr. Herhangi bir hataya düºmemek için bunlarýn her türlü ikili kombinezonu için
nasýl bir otomatik tür dönüºümü yapýlacaðýný çok iyi bilmemiz gerekir.
Aºaðýda belirtilen 4 durumda mutlaka otomatik bir tür dönüºümü yapýlacaktýr:
1. Aritmetik ya da mantýksal bir ifadedenin operandlarý ayný türden deðilse:
...
int x, y;
float fl;
if (fl * ix / iy) {
...
}
Bu durumda yapýlan tür dönüºümlerine genel aritmetik tür dönüºümleri diyeceðiz.
2. Atama operatörü kullanýldýðýnda atama operatörünün sað tarafýyla sol tarafý ayný türden
deðilse:
double toplam;
long sayi1, sayi2;
toplam = sayi1 + sayi2;
Bu durumda yapýlan tür dönüºümlerine atama tür dönüºümleri diyeceðiz.
3. Bir fonksiyon çaðýrýlmasý sýrasýnda kullanýlan bir argumanýn türü ile fonksiyonun ilgili
parame deðiºkeni ayný türden deðilse:
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
121
Buy RoboPDF
14 . BÖLÜM :
double sonuc;
int sayi1, sayi2;
...
sonuc = pow(sayi1, sayi2)
double pow (double taban, double us)
{
...
}
4. Bir return ifadesinin türü ile ilgili fonksiyonun geri dönüº deðerinin türü arasýnda farklýlýk
varsa:
double funktion (int para1, int para2)
{
...
return (para1 + para2)
}
3. ve 4. durumlar da bir atama iºlemi olarak düºünülebilir. Zira fonksiyon çaðýrma ifadesindeki
argumanlar parametre deðiºkenlerine kopyalanarak (atanarak) geçirilir. Yine return ifadesi de
aslýnda geçici bölgeye yapýlan bir atama iºlemidir.
Otomatik Tür Dönüºümleri
Otomatik tür dönüºümleri iki operand alan operatörlerin bulunduðu ifadelerde operandlarýn
türlerinin farklý olmasý durumunda uygulanýr. Ve otomatik tür dönüºümü sonucunda farklý iki
tür olmasý durumu ortadan kaldýrýlarak operandlarýn her ikisinin de türlerinin ayný olmasý
saðlanýr. örneðin
int i;
double d, result;
result = i + d;
Bu ifadenin sað tarafýnda yer alan i ve d deðiºkenlerinin türleri farklýdýr. (biri int diðeri double
türden). Bu durumda i ve d nesnelerinin türleri otomatik olarak ayný yapýlýr. Peki int tür mü
double türe dönüºtürülecek yoksa double tür mü int türe dönüºtürülecek? Eðer double tür
int türe dönüºtürülse bilgi kaybý söz konusu olurdu (Çünkü bu durumda gerçek sayýnýn en az
virgülden sonraki kýsmý kaybedilir).
C'de otomatik tür dönüºümleri mümkünse bilgi kaybý olmayacak ºekilde yapýlýr.
Bu durumda bilgi kaybýný engellemek için genel olarak küçük tür büyük türe dönüºtürülür.
(istisnalarý var) Bu duruma terfi (promotion) diyeceðiz.
Kurallarý detaylý olarak öðrenmek için oluºabilecek durumlarý iki ana durum altýnda inceleyelim:
1. Operandlardan birinin türü gerçek sayý türlerinden biriyse.
Operandlardan birinin long double diðerinin farklý bir tür olmasý durumunda diðer operand
long double türüne çevrilir.
Operandlardan birinin double diðerinin farklý bir tür olmasý durumunda diðer operand
double türüne çevrilir.
Operandlardan birinin float diðerinin farklý bir tür olmasý durumunda diðer operand float
türüne çevrilir.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
122
Buy RoboPDF
TÜR DÖNܪÜMLERÝ
2. Operandlardan hiçbiri gerçek sayý türlerinden deðilse:
Eðer ifade içindeki operandlardan herhangi biri char, unsigned char, short ya da
unsigned short türden ise aºaðýdaki algoritma uygulanmadan önce bu türler int türe
dönüºtürülür. Bu duruma “tam sayiya terfi” (integral promotion) denir.
Daha sonra aºaðýdaki kurallar uygulanýr:
Operandlardan birinin unsigned long diðerinin farklý bir tür olmasý durumunda (long,
unsigned int, int) diðer operand unsigned long türüne çevrilir.
Operandlardan birinin long türden diðerinin farklý bir türden olmasý durumunda (unsigned
int, int) diðer operand long türüne çevrilir.
Operandlardan biri unsigned int türden diðerinin farklý bir türden olmasý durumunda (int)
ikinci operand unsigned int türüne çevrilir.
Ýstisnalar:
Eðer operandlardan biri long int diðeri unsigned int türünden ise ve kullanýlan sistemde bu
türlerin uzunluklarý ayný ise (UNIX ve Win 32 sistemlerinde olduðu gibi) her iki tür de
unsigned long int türüne dönüºtürülür.
Eðer operandlardan biri int diðeri unsigned short türünden ise ve kullanýlan sistemde bu
türlerin uzunluklarý ayný ise (DOS'da olduðu gibi) her iki tür de unsigned int türüne
dönüºtürülür.
Otomatik tür dönüºümleri ile ilgili kurallarý aºaðýdaki tabloda özetleyelim:
operandlardan herhangi biri
yapýlacak dönüºüm
char,short,unsigned char,unsigned ilgili operand int türe dönüºtürülecek.
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
yapýlacak dönüºüm
2. operand long double türüne
çevrilecek.
2. operand double türüne çevrilecek.
2. operand float türüne çevrilecek.
2. operand unsigned long türüne
çevrilecek
2. operand long türüne dönüºtürülecek.
(istisnai duruma dikkat!)
2. operand unsigned int türüne
dönüºtürülecek.
Fonksiyon çaðýrma ifadeleri de, operatörlerle birlikte baºka ifadeleri oluºturuyorsa, otomatik tür
dönüºümlerine neden olabilir. Zira geri dönüº deðerine sahip olan fonksiyonlar için fonksiyonun
çaðýrýlma ifadesi, fonksiyonun geri dönüº deðerini temsil etmektedir. Örneðin:
int i = 5;
...
pow(2, 3) + i
ifadesinde pow fonksiyonunun geri dönüº deðeri double türden olduðu için, int türden olan i
deðiºkeni de, iºlemin yapýlabilmesi için double türüne çevrilerek iºleme sokulacaktýr.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
123
Buy RoboPDF
14 . BÖLÜM :
Atama Tür Dönüºümleri
Bu tür dönüºümlerin çok basit bir kuralý vardýr: Atama operatörünün sað tarafýndaki tür, atama
operatörünün sol tarafýndaki türe otomatik olarak dönüºtürülür.
Küçük türlerin büyük türlere dönüºtürülmesinde bilgi kaybý söz konusu deðildir. Örneðin :
double leftx;
int righty = 5;
leftx = righty;
yukarýdaki örnekte righty deðiºkeninin türü int’tir. Önce double türe otomatik dönüºüm
yapýlacak ve double hale getirilen 5 sabiti (5.) leftx deðiºkenine atanacaktýr.
Aºaðýda 16 bitlik sistemler için bazý örnekler verilmektedir :
TÜR
desimal
hex
dönüºtürülecektür 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ý küçük türden büyük türe dönüºtürüldüðünde sayýnýn yüksek anlamlý
bitleri negatifliðin korunmasý amacýyla 1 ile beslenmektedir. (Hex olarak F ile)
Derleyici tarafýndan yapýlan otomatik, atama tür dönüºümlerinde, büyük türün küçük türe
dönüºtürülmesi durumunda bilgi kaybý söz konusu olabilir.
Aºaðýdaki basit kurallarý verebiliriz:
Eðer atama operatörünün her iki tarafý da tam sayý türlerinden ise (char, short, int, long),
atama operatörünün sað tarafýnýn daha büyük bir türden olmasý durumunda bilgi kaybý olabilir.
Bilgi kaybý ancak, atama operatörünün sað tarafýndaki deðerin, sol taraftaki türün sýnýrlarý
içinde olmamasý durumunda söz konusu olacaktýr. Bilgi kaybý yüksek anlamlý byte’larýn
kaybolmasý ºeklinde ortaya çýkar. Örnek:
long m = 0x12345678;
int y;
y = m;
printf (“m = %x\n”, m);
Yukarýdaki örnekte int türden olan y deðiºkenine long türden bir deðiºkenin deðeri atanmýºtýr.
(16 bitlik bir sistemde örneðin DOS altýnda çalýºtýðýmýzý düºünüyoruz.). DOS altýnda int türü
için sayý sýnýrlarý –32768 +32767 deðerleridir. Bu sayýlarda iki byte’lýk bir alan için iºaretli
olarak yazýlabilecek en büyük ve en küçük sayýlardýr. Hex gösterimde her bir hex digit 4 bite ve
her iki hex digit 1 byte alana tekabül edecektir. Dolayýsýyla 0x12345678 sayýsý 8 hex digit yani
4 byte uzunluðunda bir sayýdýr. Oysa atamanýn yapýlacaðý taraf int türdendir ve bu tür max. 4
hex digit (2 byte) uzunlukta olabilmektedir. Bu durumda m deðiºkenine iliºkin deðerin yüksek
anlamlý 2 byte’ý yani (4 hex digiti) kaybedilecektir. Atama iºleminden sonra, printf
fonksiyonuyla y deðiºkeninin deðeri yazdýrýldýðýnda (hex gösterimli) ekrana 5678 deðerinin
yazdýrýldýðý görülecektir.
Atama operatörünün sað tarafý gerçek sayý türlerinden bir türden ise (float, double, long
double) ve sol tarafý ise tam sayý türlerinden birine ait ise, bu herºeyden önce “undefined
behaviour” (ºüpheli kod) durumudur ve bu durumun oluºtuðu kodlardan kesinlikle kaçýnmak
gerekir. Ama derleyicilerin hemen hemen hepsi bu durumda aºaðýdaki ºekilde tür dönüºümü
yaparlar:
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
124
Buy RoboPDF
TÜR DÖNܪÜMLERÝ
Sað taraftaki gerçek sayý türündeki deðer nokta içeriyorsa, önce kesir kýsmý kaybedilir. Kesir
kýsmý kaybedildikten sonra kalan deðer eðer sol taraf türünün sýnýrlarý içinde kalýyorsa daha
fazla bir bilgi kaybý olmaz, fakat sol taraf türünün sýnýrlarý aºýlýyorsa ilave bir bilgi kaybý daha
olur ve yüksek anlamlý byte’lar kaybedilir.
Örnek:
double y = 234.12;
int x;
x = y;
printf(“x = %d\n”, x );
/* x deðiºkenine 234 deðeri atanacaktýr */
y = 32768.1;
x = y;
printf(“x = %d\n”, x );
/* x deðiºkenine -32768 deðeri atanacaktýr */
Tam Sayýya Terfi (integral promotion)
Daha önce de açýklandýðý gibi “integral promotion” bir ifade içinde bulunan char, unsigned
char, short, unsigned short türlerinin, ifadenin derleyici tarafýndan deðerlendirilmesinden
önce, otomatik olarak int türe dönüºtürülmeleri anlamýna gelir.
Peki dönüºüm signed int türüne mi unsigned int türüne mi yapýlacak, bunu nasýl bileceðiz?
Genel kural ºudur: Tür dönüºümüne uðrayacak türün bütün deðerleri int türü ile ifade
edilebiliyorsa int, edilemiyorsa unsigned int türüne dönüºüm yapýlýr.
Örneðin unsigned short ve int türlerinin ayný uzunlukta olduðu DOS iºletim sisteminde
unsigned short türü, tamsayýya terfi ettirilirken unsigned int türüne dönüºtürülür.
Eðer tam sayýya terfi ettirilecek deðer, signed char, unsigned char ya da short (signed
short) türlerinden ise dönüºüm signed int türüne yapýlacaktýr.
Bilgi kaybý ile ile ilgili ºu hususu da göz ardý etmemeliyiz. Bazý durumlarda bilgi kaybý tür
dönüºümü yapýldýðý için deðil yapýlmadýðý için oluºur. Sýnýr deðer taºmalarý buna iyi bir örnek
olabilir.
Örnek: (DOS altýnda çalýºtýðýmýzý düºünelim)
long x = 1000 * 2000;
Yukarýdaki kod ilk bakýºta normal gibi görünüyor. Zira çarpma iºleminin sonucu olan 2000000
deðeri DOS altýnda long türü sayý sýnýrlarý içinde kalmaktadýr. Oysa bilgi kaybý atama
iºleminden önce gerçekleºir. 1000 ve 2000 int türden sabitlerdir, iºleme sokulduklarýnda
çarpma operatörünün de ürettiði deðer int türden olacaktýr. Bu durumda 2 byte uzunlukta olan
int türü 2000000 sayýsýný tutamayacaðý için yüksek anlamlý byte kaybedilecektir. 2000000 hex
sistemde 0x1E8480 olarak gösterilebilir. Yüksek anlamlý byte kaybedilince iºlem sonucu
0x8480 olarak bulunur. 0x8480 negatif bir sayýdýr. Ýkiye tümleyenini alýrsak
0x8480
1000 0100 1000 0000
ikiye tümleyeni 0111 1011 1000 0000 (0x7B80 = 31616)
Görüldüðü gibi iºlem sonucu üretilecek deðer –31616 dir. Bu durumda x deðiºkeninin türü
long da olsa, atanacak deðer –31616 olacaktýr.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
125
Buy RoboPDF
14 . BÖLÜM :
Fonksiyon Çaðýrmalarýnda Tür Dönüºümü
Daha önce söylendiði gibi bir fonksiyona gönderilecek argumanlarla, bu argumanlarý tutacak
fonksiyonun parametre deðiºkenleri arasýnda tür farký varsa otomatik tür dönüºümü
gerçekleºecek ve argumanlarýn türü, parametre deðiºkenlerinin türlerine dönüºtürülecektir.
Ancak bu tür dönüºümünün gerçekleºmesi için, derleyicinin fonksiyon çaðýrma ifadesine
gelmeden önce fonksiyonun parametre deðiºkenlerinin türleri hakkýnda bilgi sahibi olmasý
gerekecektir. Derleyici bu bilgiyi iki ayrý ºekilde elde edebilir:
1. Çaðrýlan fonksiyon çaðýran fonksiyondan daha önce tanýmlanmýºsa, derleyici fonksiyonun
tanýmlamasýndan parametre deðiºkenlerinin türünü belirler.
2. Fonksiyonun prototip bildirimi yapýlmýºsa derleyici parametre deðiºkenlerinin türü hakkýnda
önceden bilgi sahibi olur.
Örnek:
#include <stdio.h>
double func(double x, double y)
{
...
}
int main()
{
int a, b;
...
funk(a, b);
return 0;
}
Yukarýdaki örnekte main fonksiyonu içinde çaðýrýlan func fonksiyonuna arguman olarak int
türden olan a ve b deðiºkenlerinin deðerleri gönderilmiºtir. Fonksiyon tanýmlamasý çaðýrma
ifadesinden önce yer aldýðý için int türden olan a ve b deðiºkenlerinin deðerleri, double türe
dönüºtürülerek func fonksiyonunun parametre deðiºkenleri olan x ve y deðiºkenlerine
aktarýlýrlar. func fonksiyonunun main fonksiyonundan daha sonra tanýmlanmasý durumunda
otomatik tür dönüºümünün yapýlabilmesi için prototip bildirimi ile derleyiciye parametre
deðiºkenlerinin türleri hakkýnda 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 çaðýrýlan fonksiyon çaðýran fonksiyondan daha sonra tanýmlanmýºsa, ve fonksiyon prototipi
bildirimi yapýlmamýºsa (tabi bu durumda derleme zamanýnda error oluºmamasý için
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
126
Buy RoboPDF
TÜR DÖNܪÜMLERÝ
fonksiyonun int türden bir geri dönüº deðerine sahip olmasý gerekecektir) tür dönüºümü
gerçekleºebilecek mi?
Bu durumda fonksiyonun parametre deðiºkenlerinin türleri hakkýnda derleyici bilgi sahibi
olamayacaðý için, fonksiyona gönderilen argumanlarý, default arguman dönüºümü denilen
dönüºüme tabi tutar. Default arguman dönüºümü ºu ºekilde olur:
char ya da short türünden olan argumanlar tamsayýya terfi ettirilir. (integral promotion).
float türünden olan argumanlar double türüne dönüºtürülür. Bunun dýºýndaki türlerden olan
argumanlarýn tür dönüºtürülmesine tabi tutulmaz.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
127
Buy RoboPDF
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
Buy RoboPDF
switch DEYÝMÝ
15 . BÖLÜM : switch DEYÝMÝ
switch deyimi ile bir ifadenin farklý deðerleri için farklý iºler yapmak mümkün hale gelir.
Özellikle else if yapýlarýna bir alternatif olarak kullanýlýr.
Genel biçimi:
switch (ifade) {
case ifade_1:
case ifade_2:
case ifade_3:
.......
case ifade_n:
default:
}
switch, case ve default anahtar sözcüklerdir.
switch Deyiminin Çalýºmasý
Derleyici switch parantezi içerisindeki ifadenin sayýsal deðerini hesaplar. Bu sayýsal deðere eºit
bir case ifadesi olup olmadýðýný araºtýrýr. Bulursa programýn akýºý o case ifadesine geçirilir.
Artýk program buradan akarak ilerler. Eðer switch parantezi içindeki ifadenin sayýsal deðeri
hiçbir case ifadesine eºit deðilse akýº default anahtar sözcüðünün bulunduðu kýsýma geçirilir.
default anahtar sözcüðünün bulunmasý zorunlu deðildir. Uygun bir case ifadesi yoksa ve
default anahtar sözcüðü de yoksa programýn akýºý switch deyiminin içine girmez ve switch
deyimi dýºýndaki 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(“dört\n”);
default: printf(“hiçbiri\n”);
}
return 0;
Burada unutulmamasý gereken noktayý tekrar edelim: Uygun bir case ifadesi bulunduðunda
programýn akýºý buraya geçirilir. Yalnýzca bulunan case ifadesini izleyen deyim ya da deyimlerin
icra edilmesi söz konusu deðildir.Uygun case ifadesini izleyen deyimlerin icrasýndan sonra
programýn akýºý daha aºaðýda bulunan case ifadlerini izleyen deyimlerin icra edilmesiyle devam
eder.
Yukarýdaki örnekte scanf fonksiyonu ile a deðiºkenine 1 atandýðýný varsayalým. Bu durumda
program çýktýsý ºu ºekilde oluºacaktýr :
bir
iki
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
129
Buy RoboPDF
15 . BÖLÜM :
üç
dört
hiçbiri
Eðer uygun case ifadesi bulunduðunda yalnýzca bu ifadeye iliºkin deyim(ler)in icra edilmesini
istersek break anahtar sözcüðünden faydalanýrýz. break anahtar sözcüðü döngülerden olduðu
gibi switch deyimlerinden de çýkmamýza 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(“dört\n”); break;
default : printf(“hiçbiri\n”); break;
}
return 0;
Uygulamalarda da switch deyiminde çoðunlukla her case ifadesi için bir break anahtar
sözcüðünün kullanýldýðýný görürüz. (Tabi böyle bir zorunluluk yok!)
case ifadelerini izleyen ":" atomundan sonraki deyimler istenildiði kadar uzun olabilir. case
ifadelerinin sýralý olmasý ya da default anahtar sözcüðünün en sonda olmasý gibi bir zorunluluk
yoktur. default herhangi bir yere yerleºtirilebilir. default ifadesi nerede olursa olsun,
programýn akýºý ancak uygun bir case ifadesi bulunamazsa default içine girecektir.
Yukarýda da anlatýldýðý gibi switch parantezi içerisindeki ifadenin sayýsal deðerine eºit bir case
ifadesi bulunana kadar derleyici derleme yönünde (yani yukarýdan aºaðýya doðru) tüm case
ifadelerini sýrasýyla kontrol eder. Bu yüzden en yüksek olasýlýða iliºkin (biliniyorsa) case
ifadesinin en baºa (diðerlerinden önce) yerleºtirilmesi iyi tekniktir.
switch kontrol deyimi belli ölçülerde else if (else if ladder - cascaded if) yapýlarýyla
karºýlanabilir. Yani switch deyimi olmasaydý yapmak istediklerimizi else if deyimi ile
yapabilirdik. Ancak bazý durumlarda else if yapýsý yerine switch deyimi kullanmak
okunabilirliði artýrmaktadýr. Örneðin aºaðýdaki iki kod iºlevsel olarak birbirinin aynýdýr:
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;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
130
Buy RoboPDF
switch DEYÝMÝ
örnek :
Bir tarih bilgisini (ay, gün, yýl) yazý ile gg – yazý – yyyy (12 - Aðustos - 2002 gibi) biçiminde
ekrana yazan, prototipi void display_date(int day, int month, int year) biçiminde 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 için ayný iºlemlerin yapýlmasý ºöyle saðlanabilir.
case 1:
case 2:
case 3:
ifade1;
ifade2;
ifade3;
break;
case 4:
Bunu yapmanýn daha kýsa bir yolu yoktur. Bazý programcýlar bu yapýyý ºu ºekilde de yazarlar:
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
131
Buy RoboPDF
15 . BÖLÜM :
case 1: case 2: case 3: case 4: case 5:
ifade1:
ifade2;
Her switch deyimini else if yapýsýyla karºýlayabiliriz, ama her else if yapýsýný switch
deyimiyle karºýlayamayýz. switch deðiminin parantezi içindeki ifadenin türü tamsayý olmak
zarundadýr. case ifadeleri de tamsayý sabit ifadesi olmak zarundadýr. switch deyimi, tamsayý
türünden bir ifadenin deðerinin deðiºik tamsayý deðerlerine eºitliðinin test edilmesi ve eºitlik
durumunda farklý iºlerin yapýlmasý için kullanýlýr. Oysa else if yapýsýnda her türlü karºýlaºtýrma
söz 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;
Yukarýdaki else if yapýsýný switch deyimiyle karºýlayamayýz.
ªöyle bir soru aklýmýza gelebilir : Madem her switch yapýsýný else if yapýsýyla
karºýlayabiliyoruz, o zaman switch deyimine ne gerek var? Yani switch deyiminin varlýðý C
diline ne kazandýrýyor?
switch deyimi bazý durumlarda else if yapýsýna göre çok daha okunabilir bir yapý
oluºturmaktadýr, yani switch deyiminin kullanýlmasý herºeyden önce kodun daha kolay
okunabilmesi ve anlamlandýrýlmasý açýsýndan bir avantaj saðlayacaktýr.
case ifadelerinin tam sayý türünden (integral types) sabit ifadesi olmasý gerekmektedir.
Bilindiði gibi sabit ifadeleri derleme aºamasýnda derleyici tarafýndan net sayýsal deðerlere
dönüºtürülebilir.
case 1 + 3:
/* legal */
mümkün çünkü 1 + 3 sabit ifadesi ama ,
case x + 5:
/* error */
çünkü sabit ifadesi deðil. Derleyici derleme aºamasýnda sayýsal bir deðer hesaplayamaz.
case ‘a’ :
/* geçerli, bir sabit ifadesidir. */
case 3.5 :
/* gerçek sayý (double) türünden olduðu için geçerli deðildir. */
case ifadelerini izleyen deyimlerin 15 - 20 satýrdan uzun olmasý okunabilirliði zayýflatýr. Bu
durumda yapýlacak iºlemlerin fonksiyon çaðýrma biçimine dönüºtürülmesi doðru bir tekniktir.
switch (x) {
case ADDREC:
addrec();
break;
case DELREC:
delrec();
break;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
132
Buy RoboPDF
switch DEYÝMÝ
}
case FINDREC:
findrec();
break;
gibi. (Bu örnekte case ifadelerindeki ADDREC, DELREC vs. daha önce tanýmlanmýº sembolik
sabitlerdir.)
Sembolik sabitler derleme iºleminden önce öniºlemci tarafýndan deðiºtirilecekleri için, case
ifadelerinde yer alabilirler :
#define TRUE
#define FALSE
#define UNDEFINED
...
1
0
2
case TRUE:
case FALSE:
case UNDEFINED:
Yukarýdaki ifadeler, sembolik sabitlerin kullanýldýðý geçerli birer case ifadesidir.
char türünün de bir tamsayý türü olduðunu hatýrlatarak case ifadelerinin doðal olarak
karakter sabitleri de içerebileceðini belirtelim.
char ch;
ch = getch();
switch (ch) {
case ‘E’ : deyim1; break;
case ‘H’ : deyim2; break;
default : deyim3;
}
Bir switch deyiminde ayný sayýsal deðere sahip birden fazla case ifadesi olmaz. Bu durum
derleme zamanýnda hata oluºturur.
switch deyimi baºka bir switch deyiminin, do while ya da for deyiminin gövdesini
oluºturabilir. Bu durumda dýºarýdaki döngünün bloklanmasýna gerek olmayacaktýr, çünkü
switch deyimi gövdeyi oluºturan tek bir deyim olarak ele alýnacaktýr :
...
for ((ch = getch()) != ESC)
switch (rand() % 7 + 1) {
case 1: printf("Pazartesi"); break;
case 2: printf("Salý"); break;
case 3: printf("Çarºamba"); break;
case 4: printf("Perºembe"); break;
case 5: printf("Cuma"); break;
case 6: printf("Cumartesi"); break;
case 7: printf("Pazar");
}
Yukarýdaki kod parçasýnda switch deyimi dýºtaki for döngüsünün gövdesini oluºturmaktadýr,
ve switch deyimi tek bir deyim (kontrol deyimi) olarak ele alýnacaðýndan, dýºtaki for
döngüsünün bloklanmasýna gerek yoktur (tabi bloklama bir hataya neden olmayacaktýr.) Ancak
case ifadeleri içinde yer alan break anahtar sözcüðüyle yalnýzca switch deyiminden çýkýlýr, for
döngüsünün dýºýna çýkmak için case ifadesi içinde goto anahtar sözcüðü kullanýlmalýdýr.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
133
Buy RoboPDF
15 . BÖLÜM :
Uygulama
Kendisine gönderilen bir tarihi ingilizce (15th Aug. 2000 ) formatýnda 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);
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
134
Buy RoboPDF
switch DEYÝMÝ
Uygulama
Kendisine gönderilen bir tarihin (gün, ay, yýl ) o yýlýn kaçýncý günü olduðunu 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 arasýnda geçerli 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);
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
135
Buy RoboPDF
15 . BÖLÜM :
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 gönderilen karakter türkçe'ye özel
karakterlerden birisi ise (ç, ý, ð, ü vs.) bu karakterlerin ingilizce benzerine aksi halde karakterin
kendisine geri dönen 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;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
136
Buy RoboPDF
switch DEYÝMÝ
}
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;
}
}
Çalýºma Sorusu:
Ýki basamaklý bir sayýyý yazý olarak ekrana basan num_text isimli fonksiyonu yazýnýz.
Fonksiyonun prototipi :
void num_text(int n);
ºeklindedir.
Fonksiyonun parametre deðiºkeni yazýlacak olan iki basamaklý sayýdýr. Aºaðýdaki 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;
}
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
137
Buy RoboPDF
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
Buy RoboPDF
ÖNݪLEMCÝ KAVRAMI
16 . BÖLÜM : ÖNݪLEMCÝ KAVRAMI
ªimdiye kadar tek bir yapý halinde ele aldýðýmýz C derleyicileri aslýnda, iki ayrý modülden
oluºmaktadýr:
1. Öniºlemci Modülü
2. Derleme Modülü
Ýsim benzerliði olsa da öniºlemcinin bilgisayarýn iºlemcisi ya da baºka bir donanýmsal
elemanýyla hiçbir ilgisi yoktur, öniºlemci tamamen C derleyicisine iliºkin yazýlýmsal bir
kavramdýr.
Öniºlemci, kaynak program üzerinde birtakým düzenlemeler ve deðiºiklikler yapan bir ön
programdýr. Öniºlemci programýnýn bir girdisi bir de çýktýsý vardýr. Öniºlemcinin girdisi kaynak
programýn kendisidir. Öniºlemcinin çýktýsý ise derleme modülünün girdisini oluºturur. Yani
kaynak program ilk aºamada öniºlemci tarafýndan ele alýnýr. Öniºlemci modülü kaynak
programda çeºitli düzenlemeler ve deðiºiklikler yapar, daha sonra deðiºtirilmiº ve düzenlenmiº
olan bu kaynak program derleme modülü tarafýndan amaç koda dönüºtürülir.
kaynak kod
öniºlemci
derleyici
amaç program
C programlama dilinde # ile baºlayan bütün satýrlar öniºlemciye verilen komutlardýr.
# karakterinin saðýnda bulunan sözcükler ki bunlara öniºlemci komutlarý denir (preprocessor
directives), öniºlemciye ne yapmasý gerektiðini anlatýr. Örneðin:
#include
#define
#if
#ifdef
#ifndef
hepsi birer öniºlemci komutudur.
Öniºlemci komutlarý derleyici açýsýndan anahtar sözcük deðildir # karakteriyle birlikte anlam
kazanýrlar, yani istersek include isimli bir deðiºken tanýmlayabiliriz ama bunun okunabilirlik
açýsýndan iyi bir fikir olmadýðýný söyleyebiliriz. Öniºlemci komutlarýný belirten sözcükler ancak
sol taraflarýndaki # karakteriyle kullanýldýklarý zaman özel anlam kazanýrlar ki bunlara öniºlemci
anahtar sözcükleri de diyebiliriz.
Öniºlemci amaç kod oluºturmaya yönelik hiçbir iº yapmaz. Öniºlemci kaynak programý # içeren
satýrlardan arýndýrýr. Derleme modülüne girecek programda artýk # içeren satýrlar yer
almayacaktýr.
Bir çok öniºlemci komutu olmakla birlikte ºimdilik yalnýzca #include komutu ve #define
öniºlemci komutlarýný inceleyeceðiz. Geriye kalan öniºlemci komutlarýný da ileride detaylý olarak
inceleyeceðiz.
#include öniºlemci komutu
genel kullaným biçimi:
#include <dosya ismi>
ya da
#include "dosya ismi"
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
139
Buy RoboPDF
16 . BÖLÜM :
#include, ilgili kaynak dosyanýn derleme iºlemine dahil edileceðini anlatan bir öniºlemci
komutudur. Bu komut ile öniºlemci belirtilen dosyayý diskten okuyarak komutun yazýlý olduðu
yere yerleºtirir. (metin editörlerindeki copy – paste iºlemi gibi)
#include komutundaki dosya ismi iki biçimde belirtilebilir:
1. Açýsal parantezlerle:
#include <stdio.h>
#include <time.h>
2. Çift týrnak içerisinde:
#include "stdio.h"
#include "deneme.c"
Dosya ismi eðer açýsal parantezler içinde verilmiºse, sözkonusu dosya öniºlemci tarafýndan
yalnýzca önceden belirlenmiº bir dizin içerisinde aranýr. Çalýºtýðýmýz derleyiciye ve sistemin
kurulumuna baðlý olarak, önceden belirlenmiº bu dizin farklý olabilir. Örneðin:
\TC\INCLUDE
\BORLAND\INCLUDE
\C600\INCLUDE
gibi. Benzer biçimde UNIX sistemleri için bu dizin, örneðin:
/USR/INCLUDE
biçiminde olabilir. Genellikle standart baºlýk dosyalarý öniºlemci tarafýndan belirlenen dizinde
olduðundan, açýsal parantezler ile kaynak koda dahil edilirler.
Dosya ismi iki týrnak içine yazýldýðýnda öniºlemci ilgili dosyayý önce çalýºýlan dizinde (current
directory), burada bulamazsa bu kez de sistem ile belirlenen dizinde arayacaktýr. Örneðin:
C:\SAMPLE
dizininde çalýºýyor olalým.
#include "strfunc.h" komutu ile önilemci strfunc.h dosyasýný önce C:\SAMPLE dizininde arar.
Eðer burada bulamazsa bu kez sistem ile belirlenen dizinde arar. Programcýlarýn kendilerinin
oluºturduklarý baºlýk dosyalarý genellikle sisteme ait dizinde olmadýklarý için iki týrnak içinde
kaynak koda dahil edilirler.
#include ile koda dahil edilmek istenen dosya ismi dosya yolu da (path) de içerebilir:
#include <sys\stat.h>
#include "c:\headers\myheader.h"
....
gibi.
Bu durumda açýsal parantez ya da iki týrnak gösterimleri arasýnda bir fark yoktur. Her iki
gösterimde de öniºlemci ilgili dosyayý yalnýzca yolun belirttiði dizinde arar.
#include komutu ile yalnýzca baslýk dosyalarýnýn koda dahil edilmesi gibi bir zorunluluk yoktur.
Herhangi bir kaynak dosya da bu yolla kaynak koda dahil edilebilir.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
140
Buy RoboPDF
ÖNݪLEMCÝ 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;
Yukarýdaki örnekte #include "topla.c" komutu ile öniºlemci komutunun bulunduðu yere topla.c
dosyasýnýn içeriðini yerleºtirecek böylece prog.c dosyasý derlendiðinde herhangi bir hata
oluºmayacaktýr.
Çünkü artýk derleme iºlemine girecek dosya:
int a = 10;
int b = 20;
int toplam;
int main()
{
toplam = a + b;
printf("%d", toplam);
return 0;
}
ºeklinde olacaktýr.
#include komutu kaynak programýn herhangi bir yerinde bulunabilir. Fakat standart baºlýk
dosyalarý gibi, içerisinde çeºitli bildirimlerin bulunduðu dosyalar için en iyi yer kuºkusuz
programýn en tepesidir.
#include komutu içiçe geçmiº (nested) bir biçimde de bulunabilir. Örneðin çok sayýda dosyayý
kaynak koda dahil etmek için ºöyle bir yöntem 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ý içerisine yalnýzca project.h dahil edilmiºtir. Öniºlemci bu dosyayý kaynak koda
dahil ettikten sonra yoluna bu dosyadan devam edecektir.
#define Öniºlemci Komutu
#define öniºlemci komutu text editörlerindeki bul ve deðiºtir özelliði (find & replace) gibi
çalýºýr. Kaynak kod içerisindeki bir yazýyý baºka bir yazý ile deðiºtirmek için kullanýlýr.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
141
Buy RoboPDF
16 . BÖLÜM :
Öniºlemci define anahtar sözcüðünden sonra boºluklarý atarak ilk boºluksuz yazý kümesini elde
eder. (Buna STR1 diyelim.) Daha sonra boºluklarý atarak satýr sonuna kadar olan tüm
boºluklarýn kümesini elde eder. (Buna da STR2 diyelim) Kaynak kod içerisinde STR1 yazýsý
yerine STR2 yazýsýný yerleºtirir. (STR2 yazýsý yalnýzca boºluktan ibaret de olabilir. Bu durumda
STR1 yazýsý yerine boºluk yerleºtirilir, yani STR1 yazýsý silinmiº olur.) Örnekler :
#define SIZE
100
öniºlemci komutuyla, öniºlemci kaynak kod içerisinde gördüðü tüm SIZE sözcükleri yerine 100
yerleºtirecektir. Derleme modülüne girecek kaynak programda artýk SIZE sözcüðü hiç yer
almayacaktýr.
#define kullanýlarak bir yazýnýn bir sayýsal deðerle yer deðiºtirmesinde kullanýlan yazýya
"sembolik sabit" (symbolic constants) denir. Sembolik sabitler nesne deðildir. Derleme
modülüne giren kaynak kodda sembolik sabitler yerine bunlarýn yerini sayýsal ifadeler almýº
olur.
Sembolik sabitler basit makrolar (simple makro) olarak da isimlendirirler ama biz "sembolik
sabit" demeyi yeðliyoruz.
Sembolik sabitlerin kullanýlmasýnda dikkatli olunmalýdýr. Öniºlemci modülünün herhangi bir
ºekilde aritmetik iºlem yapmadýðý yalnýzca metinsel bir yer deðiºtirme yaptýðý unutulmamalýdýr:
#define MAX
10 + 20
int main()
{
int result;
}
result = MAX * 2;
printf("%d\n", result);
return 0;
Yukarýdaki örnekte result deðiºkenine 50 deðeri atanýr. Ancak ön iºlemci komutunu
#define MAX
(10 + 20)
ºeklinde yazsaydýk, result deðiºkenine 60 deðeri atanmýº olurdu.
Bir sembolik sabit baºka bir sembolik sabit tanýmlamasýnda kullanýlabilir. Örneðin:
#define
#define
MAX
MIN
100
(MAX - 50)
Öniºlemci " " içerisindeki yazýlarda deðiºiklik yapmaz. (stringlerin bölünemeyen atomlar
olduðunu hatýrlayalým.) Yer deðiºtirme iºlemi büyük küçük harf duyarlýðý ile yapýlýr. Ancak
sembolik sabitler geleneksel olarak büyük harf ile isimlendirilirler. Bunun nedeni, kodu okuyan
kiºinin deðiºkenlerle sembolik sabitleri ayýrt edebilmesine yardýmcý olmaktýr. Bilindiði gibi
geleneksel olarak deðiºken isimlendirmesinde C dilinde aðýrlýklý olarak küçük harfler
kullanýlmaktadýr.
#define komutu ile ancak deðiºkenler ve anahtar sözcükler yer deðiºtirilebilir. Sabitler ve
operatörler yer deðiºtiremez.
Aºaðýdaki #define öniºlemci komutlarý geçerli deðildir:
#define
#define
+
100
200
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
142
Buy RoboPDF
ÖNݪLEMCÝ KAVRAMI
Sembolik sabitler C dilinin deðiºken isimlendirme kurallarýna uygun olarak isimlendirilir:
#define BÜYÜK
10
tanýmlamasýnda hata oluºur. (Hata tanýmlama satýrýnda deðil sembolik sabitin kod içinde
kullanýldýðý yerlerde oluºur. Tanýmlanan sembolik sabit kod içinde kullanýlmazsa hata da
oluºmayacaktýr.)
Öniºlemci #include komudu ile kaynak koda dahil edilen dosyanýn içerisindeki öniºlemci
komutlarýný da çalýºtýrýr. Ýçinde semboli sabit tanýmlamalarý yapýlmýº bir dosya #include
komudu ile kaynak koda dahil edildiðinde, bu sembolik sabitler de kaynak kod içinde
tanýmlanmýº gibi geçerli olur.
#define sembolik sabit tanýmlamalarýnda stringler de kullanýlabilir :
#define
HATA_MESAJI
"DOSYA AÇILAMIYOR \n"
...
printf(HATA_MESAJI);
...
Sembolik sabit tanýmlamasýnda kullanýlacak string uzunsa okunabilirlik açýsýndan birden fazla
satýra yerleºtirilebilir. Bu durumda son satýr dýºýnda diðer satýrlarýn sonuna "\" karakteri
yerleºtirilmelidir.
Öniºlemci deðiºtirme iºlemini yaptýktan sonra #define komutlarýný koddan çýkartýr.
Okunabilirlik açýsýndan tüm sembolik sabit tanýmlamalarý alt alta getirecek ºekilde yazýlmalýdýr.
Seçilen sembolik sabit isimleri kodu okuyan kiºiye bunlarýn ne amaçla kullanýldýðý hakkýnda fikir
vermelidir.
C'nin baºlýk dosyalarýnda bazý sembolik sabitler tanýmlanmýºtýr. Örneðin stdio.h içerisinde
#define NULL
0
biçiminde bir satýr vardýr. Yani stdio.h dosyasý koda dahil edilirse NULL sembolik sabiti 0 yerine
kullanýlabilir. math.h içinde de pek çok matematiksel sabit tanýmlanmýºtýr.
Bir sembolik sabitin tanýmlanmýº olmasý kaynak kod içerisinde deðiºtirilebilecek bir bilginin
olmasýný zorunlu hale getirmez. Tanýmlanmýº bir sembolik sabitin kaynak kod içerisinde
kullanýlmamasý hataya yol açmaz.
#define Öniºlemci Komutu Neden Kullanýlýr
1. Okunabilirliði ve algýnalabilirliði artýrýr. Bir takým sabitlere onlarýn ne amaçla kullanýldýðýný
anlatan yazýlar karºýlýk getirilirse programa bakan kiºiler daha iyi anlamlandýrýr.
#define PERSONEL_SAYISI 750
int main()
{
if (x == PERSONEL_SAYISI)
...
return 0;
}
2. Bir sabitin program içerisinde pekçok yerde kullanýldýðý durumlarda deðiºtirme iºlemi tek
yerden yapýlabilir. Böylece söz konusu program sembolik sabite baglý olarak yazýlýp, daha
sonra sembolik sabitin deðiºtirilmesiyle farklý parametrik deðerler için çalýºtýrýlabilir.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
143
Buy RoboPDF
16 . BÖLÜM :
3. Sayýsal sabitlerin kullanýlmasýnda tutarsýzlýklarý ve yazým yanlýºlarýný engeller.
Örneðin matematiksel hesaplamalar yapan bir kodda sýksýk pi sayýsýný kullandýðýmýzý
düºünelim. pi sayýsý yerine
#define
PI
3.14159
sembolik sabitini kullanabiliriz. Her defasýnda pi sayýsýnýn sabit olarak koda girersek, her
defasýnda ayný deðeri yazamayabiliriz. Örneðin bazen 3.14159 bazen 3.14156
girebileceðimiz gibi yanlýºlýkla 3.15159 da girebiliriz. Sembolik sabit kullanýmý bu tür
hatalarý ortadan kaldýrýr.
4. Sembolik sabitler kullanýlarak C sintaksýnda küçük deðiºiklikler yapýlabilir.
#define
#define
#define
FOREVER
BEGIN
END
}
for(;;)
{
Böyle bir sembolik sabit kullanýmýný kesinlikle tavsiye etmiyoruz. Okunabilirliði artýrmasý
deðil azaltmasý söz konusudur. Bir C programcýsý için en okunabilir kod C'nin kendi
sentaksýnýn kullanýldýðý koddur.
#define komutu kaynak kodun herhangi bir yerinde kullanýlabilir. Ancak tanýmlandýðý yerden
kaynak kodun sonuna kadar olan bölge içerisinde etki gösterir.
Ancak en iyi tanýmlama yeri kaynak kodun tepesidir. Geleneksel olarak sembolik sabitler
#include satýrlarýndan (bir satýr boºluk verildikten sonra) hemen sonra yer alýrlar.
Sembolik Sabitlerin Kullanýlmasýnda Çok Yapýlan Hatalar
1. Sembolik sabit tanýmlamasýnda gereksiz yere = karakterini kullanmak.
#define
N = 100 /* yanlýº */
Bu durumda öniºlemci N gördüðü yere = 100 yapýºtýracaktýr. Örneðin int a[N] gibi bir dizi
tanýmlanmýºsa öniºlemci bu tanýmlamayý a[N = 100] yapar ki bu da derleme aºamasýnda
hata (error) ile neticelenir.
2. Sembolik sabit tanýmlama satýrýný ; ile sonlandýrmak.
#define
N
100;
/* yanlýº */
Bu durumda öniºlemci N gördüðü yere 100; yerleºtirir. int a[N]; tanýmlamasý int a[100;]
haline gelir. Derleme aºamasýnda hata oluºur. (Borland derleyicileri hata mesajý :Array
bounds missing ])Bu tür hatalarda derleyici sembolik sabit kaç yerde kullanýlmýºsa o kadar
error verecektir.
3. Sembolik sabitlerle yer deðiºtirecek ifadelerin operatör içermesi durumunda bu ifadeleri
paranteze almadan yerleºtirmek.
#define
...
SIZE
i = SIZE * 5
...
5 + 10
/* 5 + 10 * 5
= 55 (75 deðil) */
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
144
Buy RoboPDF
goto DEYÝMÝ
17 . BÖLÜM : goto DEYÝMÝ
Diðer programlama dillerinde olduðu gibi C dilinde de programýn akýºý, bir koºula baðlý
olmaksýzýn kaynak kod içinde baºka bir noktaya yönlendirilebilir. Bu C dilinde goto deyimi ile
yapýlmaktadýr.
goto deyiminin genel sentaksý aºaðýdaki ºekildedir.
<goto label;>
....
<label:>
<statement;>
goto C dilinin 32 anahtar sözcüðünden biridir. (anahtar sözcüklerin küçük harfle yazýldýklarýný
tekrar hatýrlatalým.) Label (etiket) programcýnýn verdiði bir isimdir. ªüphesiz C dilinin
isimlendirme kurallarýna uygun olarak seçilmelidir. Programýn akýºý bu etiketin yerleºtirilmiº
olduðu yere yönlendirilecektir. Etiket, goto anahtar sözcüðünün kullanýldýðý fonksiyon içinde,
en az bir deðimden önce olaçak ºekilde, herhangi bir yere yerleºtirilebilir. Etiket isminden
sonra gelen : atomu sentaksý tamamlar. Etiketin goto anahtar sözcüðünden daha sonraki bir
kaynak kod noktasýna yerleºtirilmesi zorunluluðu yoktur, goto anahtar sözcüðünden önce de
tanýmlanmýº olabilir. Örneklerle açýklayalým:
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 içerisinde, bir deyimden önce herhangi bir yere yerleºtirilebilir.
Yani ayný fonksiyon içinde bulunmak kaydýyla goto anahtar sözcüðünün yukarýsýna ya da
aºaðýsýna etiketi yerleºtirebiliriz. Bu da aslýnda deðiºik bir faaliyet alaný tipidir. C dili
standartlarýnda bu faaliyet alaný türüne "fonksiyon faaliyet alaný" denmiºtir.
Yapýsal programlama tekniðinde goto deyiminin kullanýlmasý tavsiye edilmez. Çünkü goto
deyiminin kullanýlmasý birtakým dezavantajlar doðurur:
1. goto deyimi programlarýn okunabilirliðini bozar. Kodu takip eden kiºi goto deyimiyle
karºýlaºtýðýnda fonksiyonun içinde etiketi arayacak, ve programý bu noktadan takip etmeye
koyulacaktýr.
2. goto deyimlerinin kullanýldýðý bir programda bir deðiºiklik yapýlmasý ya da programýn,
yapýlacak eklemelerle, geliºtirilmeye çalýºýlmasý daha zor olacaktýr. Programýn herhangi bir
yerinde bir deðiºiklik yapýlmasý durumunda, eðer program içerisinde baºka yerlerden kodun
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
145
Buy RoboPDF
17 . BÖLÜM :
akýºý deðiºikliðin yapýldýðý yere goto deyimleri ile atlatýlmýº ise, bu noktalarda da bir
deðiºiklik yapýlmasý gerekebilerecektir.
Bu olumsuzluklara karºýn, bazý durumlarda goto deyiminin kullanýlmasý programýn
okunabilirliðini bozmak bir yana, diðer alternatiflere göre daha okunabilir bir yapýnýn
oluºmasýna yardýmcý olacaktýr:
Ýçiçe birden fazla döngü varsa, ve içteki döngülerden birindeyken, yalnýzca bu döngüden deðil,
bütün döngülerden birden çýkýlmak isteniyorsa goto deyimi kullanýlmalýdýr.
Aºaðýdaki kod parçasýnda içiçe 3 döngü bulunmaktadýr. En içteki döngünün içinde func
fonksiyonu çaðýrýlarak fonksiyonun geri dönüº deðeri test edilmekte, fonksiyon eðer 0 deðerine
geri dönüyorsa programýn akýºý goto deyimiyle tüm döngülerin dýºýna yönlendirilmektedir:
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("döngü dýºýndaki ilk deyim\n");
...
Oysa goto deyimini kullanmasaydýk, ancak bir bayrak (flag) kullanarak, ve her döngünün
çýkýºýnda bayrak olarak kullanýlan deðiºkenin deðerinin deðiºtirilip deðiºtirilmediðini kontrol
ederek bunu baºarabilirdik:
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;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
146
Buy RoboPDF
goto DEYÝMÝ
}
printf("döngü dýºýndaki ilk deyim\n");
...
Yine aºaðýdaki kod parçasýnda goto deyimiyle hem switch deyimðinden hem de switch
deyiminin içinde bulunduðu for döngüsünden çýkýlmaktadýr.
...
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;
}
Yukarýdaki kod parçasýnda option deðiºkeninin deðeri
EXITPROG olduðunda programýn akýºý
goto deyimiyle
sonsuz döngünün dýºýna gönderilmiºtir. goto deyimi yerine break anahtar sözcüðü kullanýlsaydý,
yalnýzca switch deyiminden çýkýlmýº olunacaktý.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
147
Buy RoboPDF
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
Buy RoboPDF
RASTGELE SAYI ÜRETÝMÝ
18 . BÖLÜM : RASTGELE SAYI ÜRETÝMÝ
Rasgele sayý üretimi matematiðin önemli konularýndan biridir. Rasgele sayýlar ya da daha doðru
ifadeyle, rasgele izlenimi veren sayýlar (sözde rasgele sayýlar - pseudo random numbers)
istatistik, ekonomi, matematik gibi pekçok alanda olduðu gibi programcýlýkta da
kullanýlmaktadýr.
Rasgele sayýlar bir rasgele sayý üreticisi (random number generator) tarafýndan üretilirler.
Rasgele sayý üreticisi aslýnda matematiksel bir fonksiyondur. Söz konusu fonksiyon bir
baºlangýç deðeri alarak bir deðer üretir. Daha sonra ürettiði her deðeri girdi olarak alýr ve
tekrar baºka bir sayý üretir . Üreticinin ürettiði sayýlar rasgele izlenimi vermektedir.
C standartlarý rasgele tamsayý üreten bir fonskiyonun standart bir C fonksiyonu olarak
tanýmlanmasýný zorunlu kýlmýºtýr. Bu fonksiyonun prototip bildirimi aºaðýdaki gibidir:
int rand(void);
C standartlarý rand fonksiyonunun rasgele sayý üretimi konusunda kullanacaðý algoritma ya da
teknik üzerinde bir koºul koymamýºtýr. Bu konu derleyiciyi yazanlarýn seçimine baðlý
(implementation dependent) býrakýlmýºtýr. rand fonksiyonunun prototipi standart bir baºlýk
dosyasý olan stdlib.h içinde bildirilmiºtir.
Bu yüzden rand fonksiyonunun çaðýrýlmasý durumunda bu baºlýk dosyasý "include" öniºlemci
komuduyla kaynak koda dahil edilmelidir.
#include <stdlib.h>
rand fonksiyonu her çaðýrýldýðýnda [0, RAND_MAX] aralýðýnda rasgele bir tamsayý deðerini geri
döndürür. RAND_MAX stdlib.h baºlýk dosyasý içinde tanýmlanan bir sembolik sabittir,
derleyicilerin çoðunda RAND_MAX sembolik sabiti 32767 olarak, yani 2 byte'lýk signed int
türünün maximum deðeri olarak tenýmlanmýºtýr.
Aºaðýdaki program parçasýnda 0 ile 32767 arasýnda 10 adet rasgele sayý üretilerek ekrana
yazdýrýlmaktadýr :
#include <stdio.h>
#include <stdlib.h>
int main()
{
int k;
}
for (k = 0; k < 10; ++k)
printf("%d ", rand());
return 0;
Yukarýdaki kaynak kodla oluºturulan programýn her çalýºtýrýlmasýnda ekrana ayný sayýlar
yazýlacaktýr. Örneðin yukarýdaki programý DOS altýnda Borland Turbo C 2.0 derleyicisi ile
derleyip çalýºtýrdýðýmýzda ekran çýktýsý aºaðýdaki gibi oldu:
346 130 10982 1090 11656 7117 17595 6415 22948 31126
Oluºturulan program her çalýºtýrýldýðýnda neden hep ayný sayý zinciri elde ediliyor? rand
fonksiyonu rasgele sayý üretmek için bir algoritma kullanýyor. Bu algoritma derleyiciden
derleyiciye deðiºsede, rasgele sayý üretiminde kullanýlan ana tema aynýdýr. Bir baºlangýç deðeri
ile iºe baºlanýr. Buna tohum deðer diyoruz. Bu deðer üzerinde bazý iºlemler yapýlarak rasgele
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
149
Buy RoboPDF
17 . BÖLÜM :
bir sayý elde edilir. Tohum deðer üzerinde yapýlan iºlem bu kez elde edilen rasgele sayý
üzerinde tekrarlanýr...
rand fonksiyonu rasgele sayý üretmek için bir baºlangýç deðeri kullanýyor. Rasgele sayý
üreticilerinin (random number generator) kullandýklarý baºlangýç deðerine tohum deðeri (seed)
denir. rand fonksiyonunu içeren programý her çalýºtýrdýðýmýzda ayný tohum deðerinden
baºlayacaðý için ayný sayý zinciri elde edilecektir. ݺte ikinci fonksiyon olan srand fonksiyonu,
rasgele sayý üreticisinin tohum deðerini deðiºtirmeye yarar:
void srand (unsigned seed);
srand fonksiyonuna gönderilen arguman rasgele sayý üreticisinin tohum deðerini deðiºtir.
srand() fonksiyonuna baºka bir tohum deðeri gönderdiðimizde fonksiyonun ürettiði rasgele sayý
zinciri deðiºecektir. Yukarýdaki programa bir ilave yaparak yeniden çalýºtýrýn.
#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 oluºturduðumuz programý her çelýºtýrdýðýmýzda yine yukarýdaki sayý zinciri elde
edilecek. Zira rand fonksiyonunun kullanmakta olduðu önceden seçilmiº (default) tohum
deðerini kullanmasak da, rasgele sayý üretme mekanizmasý bu kez her defasýnda bizim srand
fonksiyonuyla göndermiº olduðumuz tohum deðerini kullanacak. Programý birkaç kere çalýºtýrýp
ayný sayý zincirini ürettiðini test edin.
Bir çok durumda programýn her çalýºtýrýlmasýnda ayný rasgele sayý zincirinin üretilmesi
istenmez. Programýn her çalýºmasýnda farklý bir sayý zincirinin elde edilmesi için programýn her
çalýºmasýnda srand fonksiyonu baºka bir deðerle, rasgele sayý üreticisinin tohum deðerini set
etmelidir. Bu amaçla çoðu zaman time fonksiyonundan faydalanýlýr:
time fonksiyonu standart bir C fonksiyonudur, prototip bildirimi standart bir baºlýk dosyasý olan
time.h içindedir. time fonksiyonu, parametre deðiºkeni gösterici olan bir fonksiyon olduðundan
ileride detaylý olarak ele alýnacaktýr. ªimdilik time fonksiyonunu iºimizi görecek kadar
inceleyeceðiz. time fonksiyonu 0 argumanýyla çaðýrýldýðýnda 01.01.1970 tarihinden fonksiyonun
çaðýrýldýðý ana kadar geçen saniye sayýsýný geri döndürür. Fonksiyonun geri dönüº deðeri
derleyicilerin çoðunda long türden bir deðerdir. Ýçinde rasgele sayý üretilecek programda,
srand fonksiyonuna arguman olarak time fonksiyonunun geri dönüº deðeri arguman olarak
gönderilirse, program her çalýºtýðýnda rasgele sayý üreticisi baºka bir tohum deðeriyle ilk
deðerini alacaktýr, böyle progarmýn her çalýºtýrýlmasýnda farklý sayý zinciri üretilecektir.
srand(time(0));
srand fonksiyonunun bu ºekilde çaðýrýmý derleyicilerin çoðunda randomize isimli bir makro
olarak tanýmlanmýºtýr. Yukarýdaki fonksiyon çaðýrýmý yerinde bu makro da çaðýrýlabilir. Makrolar
konusunu ileride detaylý olarak inceºeyeceðiz :
randomize();
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
150
Buy RoboPDF
RASTGELE SAYI ÜRETÝMÝ
Yukarýdaki örnek programý her çalýºtýðýnda 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 aralýkta rasgele sayý üretmek isteyebiliriz. Bu durumda mod
operatörü kullanýlabilir :
rand()
rand()
rand()
rand()
%
%
%
%
2
6
6+1
6+3
Yalnýzca 0 ya da 1 deðerini üretir.
0 - 5 aralýðýnda rasgele bir deðer üretir
1 - 6 aralýðýnda rasgele bir deðer üretir.
5 - 8 aralýðýnda rasgele bir deðer üretir.
Karmaºýk olasýlýk problemleri, olsýlýða konu olayýn bir bilgisayar programý ile simule edilemesi
yoluyla çözülebilir. Ýyi bir rasgele sayý üreticisi kullanýldýðý takdirde, olasýlýða konu olay bir
bilgisayar programý ile simule edilir ve olay bilgisayarýn iºlem yapma hýzýndan faydanlanýlarak
yüksek sayýlarda tekrar ettirilir. ªüphesiz hesap edilmek istenen olaya iliºkin olasýlýk deðeri,
yapýlan tekrar sayýsýna ve rasgele sayý üreticisinin kalitesine baðlý olacaktýr. Aºaðýdaki kod yazý
tura atýlmasý olayýnda tura gelme olasýlýðýný 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 olasýlýðý = %lf", (double) heads_counter / TIMES);
getch();
}
return 0;
Yukarýdaki programý TIMES sembolik sabitinin farklý deðerleri için çalýºtýrdýðýmýzda ekran çýktýsý
aºaðýdaki ºekilde oldu:
#define TIMES 100
tura gelme olasýlýðý = 0.480000
#define TIMES 500
tura gelme olasýlýðý = 0.496000
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
151
Buy RoboPDF
17 . BÖLÜM :
#define TIMES 2500
tura gelme olasýlýðý = 0.506800
#define TIMES 10000
tura gelme olasýlýðý = 0.503500
#define TIMES 30000
tura gelme olasýlýðý = 0.502933
#define TIMES 100000
tura gelme olasýlýðý = 0.501450
#define TIMES 1000000
tura gelme olasýlýðý = 0.500198
#define TIMES 10000000
tura gelme olasýlýðý = 0.500015
#define TIMES 2000000
tura gelme olasýlýðý = 0.500198
Aºaðýdaki main fonksiyonunda uzunluklarý 3 - 8 harf arasýnda deðiºen ingiliz alfabesindeki
harfler ile oluºturulmuº rasgele 10 kelime ekrana yazdýrýlmaktadýr:
#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);
Programýn ekran çýktýsý:
USPFY
KDUP
BUQJB
LMU
PKPBKFA
WQM
NQHPTXL
QCANSTEH
XZU
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
152
Buy RoboPDF
RASTGELE SAYI ÜRETÝMÝ
MNRI
OXUTGISR
XBNG
BYOQ
TFO
MQUCSU
OIHFPJ
BLVD
WDDEM
OHMHJBZY
ALIAQ
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
153
Buy RoboPDF
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
Buy RoboPDF
DÝZÝLER
19 . BÖLÜM : DÝZÝLER
Bellekte ardýºýl bir biçimde bulunan ve ayný türden nesnelerin oluºturduðu veri yapýsýna dizi
(array) denir. Dizilerin kullanýlmasýný gerektiren iki önemli özellikleri vardýr:
1. Dizi elemanlarý bellekte ardýºýl (contiguous) olarak bulunurlar.
2. Dizi elemanlarý ayný türden nesnelerdir.
Diziler bileºik nesnelerdir. Yani bir dizinin tanýmlanmasýyla birden fazla sayýda nesne birlikte
tanýmlanabilir. (Bileºik sözcüðü ingilizce "aggregate" sözcüðünün karºýlýðý olarak kullanýlmýºtýr.)
10 elemanlýk bir dizi tanýmlamak yerine, ºüphesiz farklý isimlere sahip 10 ayrý nesne de
tanýmlanabilir. Ama 10 ayrý nesne tanýmlandýðýnda bu nesnelerin bellekte ardýºýl olarak
yerleºmeleri garanti altýna alýnmýº bir özellik deðildir. Oysa dizi tanýmlamasýnda, dizinin elemaný
olan bütün nesnelerin bellekte ardýºýl olarak yer almalarý garanti altýna alýnmýº bir özelliktir.
Dizilerde bir veri türü olduðuna göre dizilerin de kullanýlmalarýndan önce tanýmlanmalarý
gerekir.
Dizilerin Tanýmlanmasý
Dizi tanýmlamalarýnýn genel biçimi:
<tür> <dizi ismi> [<eleman sayýsý>];
Yukaridaki gösterimde köºeli parantez eleman sayýsýnýn seçimlik olduðunu deðil, eleman sayýsý
bilgisinin köºeli parantez içine yazýlmasý gerektiðini göstermektedir.
tür
dizi ismi
eleman sayýsý
: Dizi elemanlarýnýn türünü gösteren anahtar sözcüktür.
: Ýsimlendirme kurallarýna uygun olarak verilecek herhangi bir isimdir.
: Dizinin kaç elemana sahip olduðunu gösterir.
Örnek Dizi Bildirimleri:
double a[20];
/* a, 20 elemanlý ve elemanlarý double türden olan bir dizidir*/
float ave[10];
/* ave 10 elemanlý ve her elemaný float türden olan bir dizidir. */
unsigned long total[100]; /* total 100 elemanlý ve her elemaný unsigned long türden olan
bir dizidir */
char path[80];
/* path 80 elemanlý ve her elemaný char türden olan bir dizidir. */
Tanýmlamada yer alan eleman sayýsýnýn mutlaka tamsayý türlerinden birinden sabit ifadesi
olmasý zorunludur. (Sabit ifadesi [constant expression] tanýmýný hatýrlayalým; deðiºken ve
fonksiyon çaðýrýmý içermeyen, yani yalnýzca sabitlerden oluºan ifadelere, sabit ifadesi denir.)
int dizi[x]; /* x dizisinin bildirimi derleme zamanýnda hata olusturur .*/
int dizi[5.]; /* gerçek sayý türünden sabit ifadesi olduðu için derleme zamanýnda hata
olusturur . */
int sample[10 * 20]
/* sample dizisinin bildirimi geçerlidir. Eleman sayýsýný gösteren
ifade sabit ifadesidir. */
Dizi bildirimlerinde eleman sayýsý yerine sýklýkla sembolik sabitler kullanýlýr:
#define
MAXSIZE
...
int dizi[MAXSIZE];
...
100
/* geçerli bir bildirimdir */
Diðer deðiºken bildirimlerinde olduðu gibi, virgül ayýracýyla ayrýlarak, birden fazla dizi tek bir
tür belirten anahtar sözcükle tanýmlanabilir.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
155
Buy RoboPDF
19 . BÖLÜM :
int x[100], y[50], z[10];
x, y ve z elemanlarý int türden olan dizilerdir.
Dizi tanýmlamalarý diðer deðiºken tanýmlamalarý ile kombine edilebilir.
int a[10], b, c;
a int türden 10 elemanlý bir dizi, b ve c int türden nesnelerdir.
Dizi elemanlarýnýn her biri ayrý birer nesnedir. Dizi elemanlarýna index operatörüyle []
ulaºýlabilir. Index operatörü bir gösterici operatörüdür. Göstericiler konusunda ayrýntýlý bir
ºekilde ele alýnacaktýr.
Ýndex operatörünün operandý dizi ismidir. (Aslýnda bu bir adres bilgisidir, çünkü dizi isimleri
adres bilgisi belirtirler.) Köºeli parantez içinde dizinin kaçýncý indisli elemanýna ulaºacaðýmýzý
gösteren bir tamsayý ifadesi olmalýdýr.
C dilinde dizilerin ilk elemaný sýfýrýncý indisli elemandýr.
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. sýradaki elemaný. */
ave[0]
/* ave dizisinin 0. indisli yani birinci sýradaki elemaný */
total[j]
/* total dizisinin j indisli elemaný */
Görüldüðü gibi bir dizinin n. elemaný ve bir dizinin n indisli elemaný terimleri dizinin farklý
elemanlarýna iºaret eder. Bir dizinin n indisli elemaný o dizinin n + 1 . elemanýdýr.
Bir dizi tanýmlamasý ile karºýlaºan derleyici, tanýmlanan dizi için bellekte yer tahsis
edecektir..Ayrýlacak yer ºüphesiz dizinin eleman sayýsý * bir elemanýn bellekte kapladýðý yer
kadar byte olacaktýr. Örneðin:
int a[5];
gibi bir dizi tanýmlamasý yapýldýðýný düºünelim. DOS iºletim sisteminde çalýºýyorsak, derleyici a
dizisi için bellekte 2 * 5 = 10 byte yer ayýracaktýr. Bellekte bu dizinin yerleºimi aºaðýdaki gibi
olacaktýr :
...
-------------------------------------------------------------
...
a[0]
a[1]
a[2]
a[3]
a[4]
...
10 byte
Dizi kullanýmýnýn getirdiði en büyük avantaj döngü deyimleri kullanarak tüm dizi elemanlarýný
kolay bir ºekilde eriºilebilmesidir.
Dizi indis ifadelerinde ++ ya da – operatörlerinin kullanýldýðý sýk görülür.
int a[20];
int k = 10;
int i =5;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
156
Buy RoboPDF
DÝZÝLER
a[k++] = 100; /* a dizisinin 10 indisli elemanýna yani 11. elemanýna 100 deðeri atanýyor. */
a[--i] = 200;
/* a dizisinin 4 indisli elemanýna yani 5. elemanýna 200 deðeri atanýyor. */
Ýndex operatörünün kullanýlmasýyla artýk dizinin herhangi bir elemaný diðer deðiºkenler gibi
kullanýlabilir.
Örnekler:
a[0] = 1;
/* a dizisinin ilk elemanýna 0 deðeri atanýyor. */
printf(“%d\n”, sample[5]);
/* sample dizisinin 6. elemaný yazdýrýlýyor. */
++val[3];
/* val dizisinin 4. elemaný 1 artýrýlýyor. */
val[2] = sample[2];
/* val dizisinin 3. elemanýna sample dizisinin 3. elemaný atanýyor. */
Diziler üzerinde iºlem yapmak için sýklýkla for ve while döngüleri kullanýlýr. Aºaðýda SIZE
elemanlý ve sample isimli bir dizi için for ve while döngülerinin kullanýldýðý bazý kalýplar
gösterilmektedir:
for (i = 0; i < SIZE; ++i)
sample[i] = 0;
i = 0;
while (i < SIZE) {
sample[i] = 0;
++i;
}
/* sample dizisinin bütün elemanlarý sýfýrlanýyor */
for (i = 0; i < SIZE; i++) {
scanf(“%d”, &sample[i]);
++i;
}
i = 0;
while (i < SIZE) {
scanf(“%d”, &sample[i]);
++i;
}
/* sample dizisinin elemanlarýna scanf fonksiyonuyla klavyeden deðer 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 tanýmlamasý yapýldýðý zaman derleyici tanýmlamasý yapýlmýº dizi için bellekte toplam dizi
uzunluðu kadar yer ayýrýr. Örneðin :
double a[10];
gibi bir tanýmlama yapýldýðýnda dizi için bellekte ardýºýl (contigious) toplam 80 byte’lýk bir yer
ayýrýlacaktýr.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
157
Buy RoboPDF
19 . BÖLÜM :
Dizinin son elemaný a[9] olacaktýr. Çok sýk yapýlan bir hata, dizinin son elemaný diye bellekte
derleyici tarafýndan tahsis edilmemiº bir yere deðer atamaktýr.
a[10] = 5.;
deyimiyle bellekte rasgele 8 byte’lýk bir alana (güvenli olmayan) bir yere 5. deðeri
yazýlmaktadýr.
Dizilere ilk deðer verilmesi (array initialization)
Dizilere ilk deðer verme iºleminin genel ºekli aºaðýdaki gibidir :
<tür> <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 yukarýdaki gibi ilk deðer verildiðinde, verilen deðerler dizinin ilk elemanýndan
baºlayarak dizi elemanlarýna sýrayla atanmýº olur.
Dizilerin tüm elemanlarýna ilk deðer verme zorunluluðu yoktur. Dizinin eleman sayýsýndan daha
az sayýda elemana ilk deðer verilmesi durumunda kalan elemanlara otomatik olarak 0 deðeri
atanmýº olur. Bu kural hem yerel hem de global diziler için geçerlidir.
Bu durumda bütün dizi elemanlarýna 0 deðeri atanmak isteniyorsa bunun en kýsa yolu :
int a[20] = {0};
yalnýzca dizinin ilk elemanýna 0 deðeri vermektir. Bu durumda derleyici dizinin kalan
elemanlarýna otomatik olarak 0 deðeri atayacaktýr.
Dizi elemanlarýna ilk deðer verilmesinde kullanýlan ifadeler, sabit ifadeleri olmalýdýr.
int a[10] = {b, b + 1, b + 2};
gibi bir ilk deðer verme iºlemi derleme zamaný hatasý oluºturur.
Bir diziye ilk deðer verme iºleminde dizi eleman sayýsýndan daha fazla sayýda ilk deðer vermek
derleme zamanýnda hata oluºumuna neden olur :
int b[5] = {1, 2, 3, 4, 5, 6};
/* error */
yukarýdaki örnekte b dizisi 5 elemanlý olmasýna karºýn, ilk deðer verme ifadesinde 6 deðer
kullanýlmýºtýr.
dizi elemanlarýna ilk deðer verme iºleminde dizi uzunluðu belirtilmeyebilir, bu durumda
derleyici dizi uzunluðunu verilen ilk deðerleri sayarak kendi hesaplar ve dizinin o uzunlukta
açýldýðýný kabul eder. Örneðin :
int sample[] = {1, 2, 3, 4, 5};
derleyici yukarýdaki ifadeyi gördüðünde sample dizisinin 5 elemanlý olduðunu kabul edecektir.
Bu durumda yukarýdaki gibi bir bildirimle aºaðýdaki gibi bir bildirim eºdeðer olacaktýr:
int sample[5] = {1, 2, 3, 4, 5};
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
158
Buy RoboPDF
DÝZÝLER
baºka ö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 uzunluðunu 13, count dizisinin uzunluðunu ise 10 olarak varsayacaktýr.
yerel ve global diziler
Bir dizi de, diðer nesneler gibi yerel ya da global olabilir. Yerel diziler bloklarýn içlerinde
tanýmlanan dizilerdir. Global diziler ise tüm bloklarýn dýºýnda tanýmlanýrlar. Global bir dizinin
tüm elemanlarý global nesnelerin özelliklerine sahip olacaktýr. Yani dizi global ise dizi elemaný
olan nesneler dosya faaliyet alanýna (file scope) sahip olacak, ve ömür karakteri açýsýndan da
statik ömürlü (static storage duration) olacaklardýr. Global bir dizi söz konusu olduðunda eðer
dizi elemanlarýna deðer verilmemiºse, dizi elemanlarý 0 deðeriyle baºlatýlacaktýr. Ama yerel
diziler söz konusu olduðunda, dizi elemaný olan nesneler blok faaliyet alanýna (block scope)
sahip olacaklar, ömür açýsýndan ise dinamik ömür karakterinde olacaklardýr. (dynamic storage
class) Deðer atanmamýº dizi elemanlarý içinde rasgele deðerler (garbage values) bulunacaktýr.
Aºaðýdaki örneði 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];
tanýmlamasýndan sonra, a dizisi elemanlarýna b dizisinin elemanlarý kopyalanmak istenirse
a = b;
/*
hata
*/
yukarýdaki gibi bir atama derleme zamaný hatasý verecektir. Çünkü a ve b dizi isimleridir. C
dilinde dizi isimleri nesne göstermezler. Dizi isimleri dizilerin bellekte yerleºtirildikleri alanýn
baºlangýcýný gösteren ve dizinin türü ile ayný türden adres deðerleridir. (Dolayýsýyla sabit
deðerlerdir.)
Dizileri ancak bir döngü kullanarak kopyalayabiliriz :
for (i = 0; i < SIZE; ++i)
a[i] = b[i];
Yukarýdaki döngü deyimiyle b dizisinin her bir elemanýnýn deðeri a dizisinin ilgili indisli
elemanýna atanmýºtýr. Dizilerin kopyalanmasý için baºka bir yöntem de bir standart C
fonksiyonu olan memcpy (memory copy) fonksiyonunu kullanmaktýr. Bu fonksiyon göstericiler
konusundan sonra ele alýnacaktýr.
dizilerle ilgili uygulama örnekleri:
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
159
Buy RoboPDF
19 . BÖLÜM :
Dizilerin kullanýlmasýný teºvik eden temel nedenlerden biri ayný türden nesnelerin bir dizi altýnda
tanýmlanmasýyla, döngüler yardýmýyla dizi elemanlarýnýn çok kolay bir ºekilde iºleme
tutulabilmesidir. Aºaðýdaki örneklerde bu temalar iºlenmiºtir :
Uygulama 1 : Bir dizi elemanlarýnýn toplamýnýn 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 içindeki en küçük sayýyý 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 küçük eleman = %d\n", min);
}
return 0;
eðer en küçük elemanýn kendisiyle birlikte, dizinin kaçýncý elemaný olduðu da bulunmak
istenseydi :
int indis;
...
for (k = 1; k < SIZE; ++k)
if (min > dizi[k]) {
min = dizi[k];
indis = k; /* en küçük eleman yenilendikçe indisi baºka bir deðiºkende saklanýyor. */
}
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
160
Buy RoboPDF
DÝZÝLER
Uygulama 3: Bir diziye klavyeden deðer alarak daha sonra dizi elemanlarýný ekrana yazdýran
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 içerisindeki elemanlarý küçükten büyüðe doðru bubble sort algoritmasýyla
sýraya 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 algoritmanýn performansý basit bir düzenleme ile artýrýlabilir. Dýºtaki döngünün her
dönüºünde en büyük sayý en sona gidecektir. Bu durumda içteki döngünün her defasýnda SIZE
– 1 kez dönmesine gerek yoktur. Ýçteki döngü SIZE – 1 – i kez dönebilir.
...
for (i = 0; k < SIZE - 1; ++k)
for (k = 0; k < SIZE - 1; ++k)
...
Bubble sort algoritmasýný sýraya dizme iºlemi tamamlandýðýnda dýºtaki döngüyü sonlandýracak
biçimde düzenleyebiliriz :
#include <stdio.h>
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
161
Buy RoboPDF
19 . BÖLÜM :
#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 düzenleme diðerine göre daha iyi de olsa performans açýsýndan çok ciddi bir farklýlýðý
yoktur.
Ayný algoritmayý bir do while döngüsü 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;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
162
Buy RoboPDF
DÝZÝLER
}
Uygulama 5: Bir dizi içerisindeki elemanlarý küçükten büyüðe insertion sort algoritmasýyla
sýraya 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;
sýralama yönünü küçükten büyüðe yapmak yerine büyükten küçüðe yapmak için içerideki
döngüyü
for (j = i; j > 0 && dizi[j - 1] < temp; --j)
ºeklinde deðiºtirmek yeterli olacaktýr.
Uygulama 6 : Bir dizi içerisindeki elemanlarý küçükten büyüðe selection sort algoritmasýyla
sýraya 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;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
163
Buy RoboPDF
19 . BÖLÜM :
}
}
for (k = 0; k < SIZE; ++k)
printf(“%d\n”, a[k]);
return 0;
karakter dizileri
Karakter dizileri char türden dizilerdir. Karakter dizilerinin bazý ilave özellikler dýºýnda diðer dizi
türlerinden bir farký yoktur. char türden diziler daha çok içlerinde yazý tutmak için tanýmlanýrlar.
char s[100];
yukarýdaki tanýmlamada s dizisi bütün elemanlarý char türden olan 100 elemanlý bir dizidir.
char türden bir dizi içinde bir yazý tutmak demek, dizinin herbir elemanýna sýrayla yazýnýn bir
karakterini atamak anlamýna gelecektir. (Bu arada char türden bir dizinin içinde bir yazý
tutmanýn zorunlu olmadýðýný, böyle bir dizinin pekala küçük tamsayýlarý tutmak amacýyla da
kullanýlabileceðini hatýrlatalým)
Yukarýda tanýmlanan dizi içinde "Ali" yazýsýný tutmak isteyelim :
s[0] = 'A';
s[1] = 'l';
s[2] = 'i';
ªimdi ºöyle bir problem ortaya çýkýyor. Dizi 100 karakterlik olmasýna karºýn biz dizi içinde 100
karakter uzunluðundan daha kýsa olan yazýlar da tutabiliriz. Peki biz yazýya tekrar ulaºmak
istediðimizde bunu nasýl yapacaðýz? Yazýnýn uzunluk bilgisini bilmiyoruz ki! Örneðin yazýyý
ekrana yazdýrmak istediðimizde, int türden dizilerde kullandýðýmýz ºekilde aºaðýdaki gibi bir
döngü kullanýrsak :
for (k = 0; k < 100; ++k)
putchar(s[k]);
bu döngü ile yalnýzca ALi yazýsý ekrana yazdýrýlmayacak dizinin diðer 97 elemanýnýn da
görüntüleri (rasgele deðerler) ekrana yazdýrýlacak.
Programlama dilleri bu duruma bir çözüm bulma konusunda iki temel yaklaºým benimserler.
a. Dizinin 1. elemanýna yazýnýn uzunluk bilgisi yazýlýr. Böylece dizideki yazýya ulaºýlmak
istendiðinde önce dizinin 1. elemanýndan yazýnýn uzunluk bilgisi çekilir. Böylece döngü
deyiminin iterasyon sayýsý deðeri elde edilmiº olur. Döngü bu deðere göre oluºturulur.
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 yaklaºým kullanýlmaz.
b. Dizinin elemanlarýna yazýnýn karakterleri sýrasýyla yerleºtirilir. Yazý bittikten sonra dizinin
sýradaki elemanýna özel bir karakter yerleºtirilir. Bu özel karakter doðal olarak normal ºartlar
altýnda bir yazýnýn elemaný olamayacak bir karakter olarak seçilmelidir. Böylece char türden dizi
içinde saklanmýº yazýya tekrar ulaºýlmak istendiðinde, kullanýlacak döngü deyiminde, dizinin
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
164
Buy RoboPDF
DÝZÝLER
döngü deðiºkeni olan indisli elemanýnýn seçilen özel karaktere eºit olmadýðý sürece döngünün
dönmesi ºartý oluºturulur. C dilinin tasarýmýnda bu yaklaºým tercih edilmiºtir.
C dilinde karakterler üzerinde iºlemlerin hýzlý ve etkin bir biçimde yapýlabilmesi için “sonlandýrýcý
karakter” (NULL KARAKTER) kavramýndan faydalanýlmaktadýr.
Sonlandýrýcý karakter ASCII tablosunun (ya da sistemde kullanýlan karakter setinin) sýfýr
numaralý (‘\x0’ ya da ‘\0’) karakteridir. Dolayýsýyla sayýsal deðer olarak 0 sayýsýna eºittir.
Görüntüsü yoktur. Bu karakter DOS ve UNIX sistemlerinde sonlandýrýcý karakter olarak
kullanýlmaktadýr. stdio.h içerisinde NULL sembolik sabiti 0 olarak tanýmlandýðý için sonlandýrýcý
karaktere NULL karakter de denir. NULL karakter ‘0’ karakteri ile karýºtýrýlmamalýdýr.
‘0’ karakterinin ASCII sýra numarasý 48’dir. Dolayýsýyla tamsayý deðeri olarak 48 deðerine
sahiptir.
‘\0” karakterinin ASCII sýra numarasý 0’dýr. Dolayýsýyla tamsayý deðeri olarak 0 deðerine
sahiptir.
...
printf(“%d\n”, ‘0’);
printf(“%d\n”, ‘\0’);
...
yukarýdaki ilk printf fonksiyonunun çaðýrýlmasýyla ekrana 48 deðeri yazdýrýlýrken, ikinci printf
fonksiyonunun çaðýrýlmasýyla ekrana 0 deðeri yazdýrýlmaktadýr.
char türden dizilere ilk deðer verilmesi
char türden dizilere ilk deðer verme iºlemi (initializing) aºaðýdaki biçimlerde yapýlabilir .
Diðer türden dizilerde olduðu gibi virgüllerle ayrýlan ilk deðerler küme parantezi içinde yer alýr :
char name[12] = {‘N’, ‘e’, ‘c’, ‘a’, ‘t’, ‘i’, ‘ ‘, ‘E’, ‘r’, ‘g’, ‘i’,’n’};
Diðer dizilerde olduðu gibi dizi eleman sayýsýndan daha fazla sayýda elemana ilk deðer vermek
derleme zamanýnda hata oluºumuna neden olur.
char name[5] = {‘N’, ‘e’, ‘c’, ‘a’, ‘t’, ‘i’, ‘ ‘, ‘E’, ‘r’, ‘g’, ‘i’,’n’};
/* error */
Dizi eleman sayýsý kadar elemana ya da dizi eleman sayýsýndan daha az sayýda elemana ilk
deðer verilebilir. Daha az sayýda elemana ilk deðer verilmesi durumunda ilk deðer verilmemiº
elemanlar diðer dizilerde olduðu gibi 0 deðeriyle baºlatýlacaklardýr. 0 deðerinin NULL karakter
olduðunu hatýrlayalým :
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 elemanlarýna ilk deðer verilirken dizi boyutu belirtilmeyebilir. Bu durumda derleyici dizi
boyutunu verilen ilk deðerleri sayarak saptar ve diziyi bu boyutta açýlmýº varsayar.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
165
Buy RoboPDF
19 . BÖLÜM :
char name[ ] = {‘A’, ‘l’, ‘i’};
yukarýdaki tanýmlama
varsayacaktýr.
deyimiyle
derleyici
name
dizisinin
3
elemanlý
olarak
açýldýðýný
Boyut bilgisi vermeden, char türden dizilere tek tek ilk deðer verilmesi durumunda, ve boyut
bilgisi verilerek dizinin toplam eleman sayýsý kadar elemana tek tek ilk deðer verilmesi
durumunda, derleyici NULL karakteri dizinin sonuna otomatik olarak yerleºtirmeyecektir. Bu
durumda eðer sonlandýrýcý karakter özelliðinden faydalanýlmak isteniyorsa, NULL karakter de
verilen diðer ilk deðerler gibi programcý tarafýndan verilmelidir. Örnek :
char name[ ] = {‘A’, ‘l’, ‘i’, ‘\0’};
char isim[7] = {‘N’, ‘e’, ‘c’, ‘a’, ‘t’, ‘i’, ‘\0’};
Bu ºekilde ilk deðer vermek zahmetli olduðundan, ilk deðer vermede ikinci bir biçim
oluºturulmuºtur. Karakter dizilerine ilk deðerler çift týrnak içinde de verilebilir :
char name[ ] = “Ali”;
bu biçimin diðerinden farký derleyicinin sonuna otomatik olarak NULL karakteri yerleºtirmesidir.
...
‘A’
...
name[0
]
‘l’
name[1
]
‘i’
name[2
]
‘\0’ name[3
]
yukarýdaki örnekte derleyici diziyi 4 elemanlý olarak açýlmýº varsayacaktýr. Dizi eleman
sayýsýndan daha fazla sayýda elemana ilk deðer vermeye çalýºmak, bu biçimin kullanýlmasý
durumunda da derleme zamanýnda hata oluºumuna neden olacaktýr.
char city[5] = “Ýstanbul”;
/* error */
Bu durumun bir istisnasý vardýr. Eger tam olarak dizi eleman sayýsý kadar dizi elemanýna çift
týrnak içinde ilk deðer verilirse bu durum ERROR oluºturmaz. Derleyici bu durumda NULL
karakteri dizinin sonuna yerleºtirmez. Bu durum C dili standartlarýna yöneltilen eleºtirilerden
biridir. (C++ dilinde son kabul edilen standartlara göre bu durum da error oluºturmaktadýr.)
char name[3] =”Ali”;
...
‘A’
‘l’
‘i’
...
/* C'de hata deðil, C++'da hata */
...
name[0]
name[1]
name[2]
buraya
bu
durumda
yerleºtirilmiyor.
null
karakter
'\0' karakteri karakter dizileri üzerinde yapýlan iºlemleri hýzlandýrmak için kullanýlýr. Örneðin int
türden bir dizi kullanýldýðýnda dizi elemanlarý üzerinde döngüleri kullanarak iºlem yaparken dizi
uzunluðunun mutlaka bilinmesi gerekmektedir. Ama char türden diziler söz konusu olduðunda
artýk dizi uzunluðunu bilmemiz gerekmez, çünkü yazýnýn sonunda '\0' karakter bulunacaðýndan,
kontrol ifadelerinde bu durum test edilerek yazýnýn sonuna gelinip gelinmediði anlaºýlýr. Ancak
'\0' karakterin, karakter dizilerinde yazýlarýn son elemaný olarak kullanýlmasýnýn dezavantajý da
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
166
Buy RoboPDF
DÝZÝLER
diziye fazladan bir karakter yani '\0' karakteri eklemek zorunluluðudur. 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 gördüðümüz getchar, getch, ve getche fonksiyonlarý klavyeden tek bir karakter
alýyorlardý. Yine putchar fonksiyonu ise tek bir karakteri ekrana yazýyordu. C dilinde birden
fazla karakteri (bir stringi) klavyeden alan ya da birden fazla karakteri ekraana yazan standart
fonksiyonlar bulunmaktadýr.
gets fonksiyonu
gets fonksiyonu klavyeden karakter dizisi almakta kullanýlan standart bir C fonksiyonudur.
Kullanýcý karakterleri girdikten sonra enter tuºuna basmalýdýr. Klavyeden girilecek karakterlerin
yerleºtirileceði dizinin ismini parametre olarak alýr. daha önce de belirtildiði gibi dizi isimleri
aslýnda bir adres bilgisi belirtmektedir. gets fonksiyonunun da parametresi aslýnda char türden
bir adrestir. Ancak göstericilerle ilgili temel kavramlarý henüz öðrenmediðimiz için ºimdilik gets
fonksiyonunun char türden bir dizi içine klavyeden girilen karakterleri yerleºtirdiðini kabul
edeceðiz. Örneðin :
char name[20];
gets(name);
ile klavyeden enter tuºuna basýlana kadar girilmiº olan tüm karakterler name dizisi içine sýrayla
yerleºtirilirler. Klavyeden Necati yazýsýnýn girildiðini 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 yerleºtirdikten sonra dizinin sonuna NULL
karakter (sonlandýrýcý karakter) diye isimlendirilen 0 numaralý ASCII karakterini (ya da
kullanýlan karakter setinin 0 numaralý karakterini) koyar.
gets fonksiyonu dizi için hiç bir ºekilde sýnýr kontrolu yapmaz. gets fonksiyonu ile dizi eleman
sayýsýndan fazla karakter girilirse, d,z, taºacaðý için beklenmeyen sonuçlarla karºýlaºýlabilir. Bu
tür durumlar göstericiler konusunda (gösterici hatalarý) detaylý olarak incelenecektir.
gets fonksiyonu ‘\0’ karakterini dizinin sonuna eklediði için SIZE uzunluðunda bir dizi için gets
fonksiyonuyla alýnacak karakter sayýsý en fazla SIZE – 1 olmalýdýr. Çünkü sonlandýrýcý
karakterde diðer karakterler gibi bellekte bir yer kaplamaktadýr. Örnek :
char isim[12];
gets(isim);
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
167
Buy RoboPDF
19 . BÖLÜM :
ile klavyeden Necati Ergin isminin girildiðini düºünelim.
...
‘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’ taºma
...
isim dizisinin tanýmlanmasýyla derleyici bu dizi için bellekte 12 byte yer ayýracaktýr. isim[0]
...isim[11]
gets fonksiyonu bu durumda ‘\0’ karakterini derleyicinin dizi için tahsis etmediði bir bellek
hücresine yazacaktýr. Bu tür durumlara dizinin taºýrýlmasý (off bye one) denmektedir.
taºma durumuyla ilgili olarak ortaya çýkacak hatalar derleme zamanýna deðil çalýºma zamanýna
(run time) iliºkindir.
puts fonksiyonu
puts fonksiyonu bir karakter dizisinin içeriðini ekrana yazdýrmak için kullanýlýr. Ýçeriði
yazdýrýlacak olan karakter dizisinin ismini parametre olarak alýr. puts fonksiyonu karakter
dizisini ekrana yazdýktan sonra imleci sonraki satýrýn baºýna geçirir.
char name[20];
gets(name);
puts(name);
yukarýdaki örnekte gets fonksiyonu ile klavyeden alýnan karakter dizisi puts fonksiyonu ile
ekrana yazdýrýlmaktadýr.
karakter dizilerini ekrana yazdýrmak için printf fonksiyonu da kullanýlabilir.
printf(“%s\n”, name);
ile
puts(name);
ayný iºi yapmaktadýr. Ancak printf fonksiyonu dizi içeriðini ekrana yazdýrdýktan sonra imleci alt
satýra taºýmaz.
puts(name);
deyimi yerine aºaðýdaki kod parçasýný da yazabilirdik.
for (i = 0; name[i] != ‘\0’; ++i)
putchar(s[i]);
putchar(‘\n’);
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
168
Buy RoboPDF
DÝZÝLER
puts fonksiyonu ve %s format karakteriyle kullanýldýðýnda printf fonksiyonu, sonlandýrýcý
karakter görene kadar bütün karakterleri ekrana yazar. Bu durumda, herhangi bir ºekilde NULL
karakter ezilirse her iki fonksiyon da ilk sonlandýrýcý karakteri görene kadar yazma iºlemine
devam edecektir.
Örneðin :
char city[ ] = “Ankara”;
city[6] = ‘!’;
deyimi ile sonlandýrýcý karakter ortadan kaldýrýlýrsa (ezilirse) :
puts(name);
ºeklinde puts fonksiyonu çaðýrýldýðýnda ekrana Ankara!yazýldýktan sonra tesadüfen ilk NULL
karakter görülene kadar ekrana yazmaya devam edilir. puts ve printf fonksiyonlarý karakter
dizilerini yazarken yalnýzca NULL karakteri dikkate alýrlar. karakter dizilerinin uzunluklarýyla
ilgilenmezler.
sizeof operatörünün dizilerle kullanýlmasý
sizeof operatörü operand olarak bir dizi ismi aldýðýnda byte olarak o dizinin toplam uzunluðunu
deðer olarak üretir.
double sample[10];
sizeof(sample)
ifadesi 80 deðerini üretecektir.
sizeof operatörü operand olarak dizinin bir elemanýný aldýðýnda ürettiði deðer, dizi hangi türden
ise o türün kullanýlan sistemdeki byte olarak uzunluðu olacaktýr. yani yukarýdaki örnekte
sizeof(sample[0])
ifadesi, 8 deðerini üretecektir.
sizeof operatörünü bir dizinin uzunluk bilgisi gerektiði yerde de kullanabiliriz :
sizeof(sample) / sizeof(sample[0])
ifadesi dizi uzunluðunu verecektir. Örnek :
for (i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
a[i] = 0;
karakter dizileriyle ilgili bazý küçük uygulama örnekleri
Uygulama 7: Karakter dizisi içerisindeki yazýnýn uzunluðunu bulan program:
#include <stdio.h>
main()
{
int k = 0,
char s[50];
gets(s);
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
169
Buy RoboPDF
19 . BÖLÜM :
}
while (s[k] != ‘\0’)
++k;
printf(“uzunluk = %d\n”, k);
yukarýda while döngüsü yerine for döngüsü kullanýlabilirdi :
for (k = 0; s[k] != ‘\0’; ++k)
;
Uygulama 8: karakter dizisini tersten yazdýran 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, büyük harfleri küçük harfe küçük harfleri büyük 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("dönüºtürülmüº yazý \n");
puts(s);
return 0;
Uygulama 10 : Karakter dizisini tersyüz eden program :
#include <stdio.h>
main()
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
170
Buy RoboPDF
DÝZÝLER
{
}
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 içindeki harfleri küçükten büyüðe doðru sýralayan bir program
#include <stdio.h>
#define
#define
SIRALI
SIRASIZ 0
1
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("sýralanmýº yazý :\n");
puts(s);
getch();
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
171
Buy RoboPDF
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
Buy RoboPDF
GÖSTERÝCÝLER
20 . BÖLÜM : GÖSTERÝCÝLER
Adres Kavramý
Adres kavramý hem donanýma hem de yazýlýma iliºkindir. Donanýmsal açýdan adres bellekte yer
gösteren bir sayýdan ibarettir. Mikroiºlemci bellekte bir bölgeye ancak o bölgenin adres
bilgisiyle eriºebilir. Bellekte (RAM'de) her byte (8 bit) diðerlerinden farklý bir adresle temsil
edilir. Sýfýr sayýsýndan baºlayarak her byte’a artan sýrada bir karºýlýk getirerek elde edilen
adresleme sistemine doðrusal adresleme sistemi (linear addressing), bu sistem kullanýlarak
elde edilen adreslere de doðrusal adresler denilmektedir. Donanýmsal olarak RAM'deki her bir
byte'a okuma ya da yazma yapma amacýyla ulaºýlabilir.
Örneðin, 64 K’lýk bir belleðin doðrusal olarak adreslenmesi aºaðýdaki biçimde yapýlabilir :
BELLEK DOÐRUSAL ADRES
0 (0000)
1
2
3
4
.......... ..................
.
65533 (FFFD)
65534 (FFFE)
65535 (FFFF)
Bilgisayara iliºkin pekçok nitelikte olduðu gibi doðrusal adreslemede de 10’luk sistem yerine
16’lýk sistemdeki gösterimler tercih edilir. Bundan böyle yalnýzca adres dendiðinde doðrusal
adres anlaºýlmalýdýr.
Nesnelerin Adresleri
Her nesne bellekte yer kapladýðýna göre belirli bir adrese sahiptir. Nesnelerin adresleri,
sistemlerin çoðunda, derleyici ve programý yükleyen iºletim sistemi tarafýndan ortaklaºa olarak
belirlenir. Nesnelerin adresleri program yüklenmeden önce kesin olarak bilinemez ve programcý
tarafýndan da önceden tespit edilemez. Programcý, nesnelerin adreslerini ancak programýn
çalýºmasý sýrasýnda (run time) öðrenebilir. Örneðin:
char ch;
biçiminde bir tanýmlamayla karºýlaºan derleyici bellekte ch deðiºkeni için 1 byte yer ayýracaktýr.
Derleyicinin ch deðiºkeni için bellekte hangi byte'ý ayýracaðýný önceden bilemeyiz. Bunu ancak
programýn çalýºmasý sýrasýnda öðrenebiliriz. Yukarýdaki örnekte ch yerel bir deðiºkendir. ch
deðiºkeni ilgili blok icra edilmeye baºlandýðýnda yaratýlýp, bloðun icrasý bittiðinde de yok
olmaktadýr. ch deðiºkeninin 1A03 adresinde olduðu varsayýlarak aºaðýdaki ºekil çizilmiºtir:
ch
1A00
1A01
1A02
1A03
1A04
1A05
Tanýmlanan nesne 1 byte’dan daha uzunsa, o zaman nesnenin adresi nasýl belirlenir?
int b;
1C00
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
173
Buy RoboPDF
20 . BÖLÜM :
x
1C01
1C02
1C03
1C04
1C05
1C06
1C07
1 byte’dan uzun olan nesnelerin adresleri, onlarýn ilk byte’larýnýn (düºük anlamlý byte’larýnýn)
adresleriyle belirtilir. Yukarýdaki örnekte x deðiºkeninin adresi 1C03’tür. Zaten x deðiºkeninin
tamsayý türünden olduðu bilindiðine göre diðer parçasýnýn 1C04 adresinde olacaðý da açýktýr.
Benzer biçimde long türünden olan y deðiºkeninin bellekteki yerleºiminin aºaðýdaki gibi olduðu
varsayýlýrsa, adresinin 1F02 olduðunu söyleyebiliriz:
x
1F00
1F01
1F02
1F03
1F04
1F05
1F06
1F07
Yerel ya da global olsun, ardýºýl (contigious) bir biçimde tanýmlanmýº nesnelerin bellekte de
ardýºýl bir biçimde tutulacaðýnýn bir garantisi yoktur. Örneðin:
{
}
int x;
char ch;
...
Buradaki ch deðiºkeninin x deðiºkeninden 2 byte sonra bulunacaðýnýn bir garantisi yoktur.
Ayrý Bir Tür Olarak Adres
Yazýlýmsal açýdan RAM'de belirli bir byte'dan ne amaçla bahsetmek isteyebiliriz? O byte içinde
yer alan nesnenin deðerini tespit etmek için! Eðer tüm nesnelerimiz 1 byte uzunluðunda
olsalardý, o zaman yazýlýmsal olarak adres ile fiziksel adres arasýnda herhangi bir fark
bulunmayacaktý. Oysa RAM'deki belirli bir byte'dan söz ettiðimizde, o byte'ý (belki onu izleyen
bazý byte'larla birlikte) herhangi türden bir nesne kaplýyor olabilir. Yazýlýmsal olarak adres
bilgisi yalnýzca bellekte yer gösteren bir sayýdan ibaret deðildir; ayný zamanda o adresin
gösterdiði yerdeki bilginin ne biçimde yorumlanacaðýný belirten bir tür bilgisini de içermektedir.
Örneðin yazýlýmsal olarak 1250 adresindeki deðerden söz etmek isteseydik aºaðýdaki sorularýn
cevabý açýkta kalacaktý.
Söz konusu deðer yalnýzca 1250 adresindeki byte da mý saklanmýº yoksa bunu izleyen (1251,
1252 vs.) bytelar da nesnenin deðerinin tespit edilmesinde kullanýlacak mý? Söz konusu deðer
hangi formatta yorumlanacak? (Yani iºaretli tamsayý aritmetiðine göre mi, iºaretsiz tam sayý
aritmetiðine göre mi, gerçek sayý formatýna göre mi, vs.)
yazýlýmsal olarak bir adres bilgisinin iki bileºeni vardýr:
1. Bellekte yer gösteren sayýsal bir deðer
2. Adresin türü
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
174
Buy RoboPDF
GÖSTERÝCÝLER
Adreslerin Türleri
Bir adresin türü demekle o adrese iliºkin bellek bölgesinde bulunan bilginin derleyici tarafýndan
yorumlanýº biçimi anlaºýlmalýdýr. Örneðin:
char ch;
gibi bir bildirim sonrasýnda ch deðiºkeninin belleðe aºaðýdaki biçimde yerleºmiº olduðunu kabul
edelim:
ch
1A00
1A01
1A02
1A03
1A04
1A05
Yukarýdaki ºekle baktýðýmýzda 1A03 sayýsýnýn bir adres belirttiðini anlýyoruz. 1A03 adresinde
bulunan bilgi char türdendir. Çünkü derleyici 1A03 adresinde bulunan bilgiyi char türden bir
nesne olarak yorumlamaktadýr. Adres yalnýz baºýna sayýsal bileºeniyle bir anlam taºýmaz,
gösterdiði türle birlikte belirtilmesi gerekmektedir.
C’de adres bilgisi ayrý bir veri/nesne türüdür. Daha önce gördüðümüz 11 temel veri türüne
ilaveten 11 ayrý adres türünün de varlýðýndan söz edebiliriz.
Adres Sabitleri
Adresler tamsayý görünümünde olsalar da tamsayý sabitleri gibi belirtilmezler. Çünkü tür
bilgilerinin de belirtilmesi gerekir. Adres sabitleri, tamsayý türlerindeki sabitler üzerinde bilinçli
tür dönüºümü yapýlarak elde edilirler. Bir tamsayý sabitini adres türüne çevirmek için tür
dönüºtürme operatörü kullanýlýr.
(<tür> *) <tamsayý sabiti>
Tür dönüºtürme operatörünün içindeki * adres ya da göstericiyi temsil etmektedir. Örneðin
0x1F00
hexadesimal olarak gösterilmiº int türden bir sabittir. Ancak:
(int *) 0x1F00
int türünden bir adres sabitidir.
0x16C0L
long türden bir tamsayý sabittir. Ancak:
(long *) 0x16C0L
long türden bir adres sabitidir. Bunun anlamý ºudur: Derleyici 16C0 adresiyle belirtilen yerdeki
bilgiyi long olarak yorumlayacaktýr.
Adres türüne bilinçli dönüºüm yalnýz sabitlerle yapýlmayabilir, örneðin:
(char *) var
var isimli deðiºken hangi türden olursa olsun, yukarýdaki ifade ile char türden bir adres haline
dönüºtürülmüºtür.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
175
Buy RoboPDF
20 . BÖLÜM :
Bir adres bilgisini bir nesne içinde tutmak isteyelim. (ªu an için neden böyle bir ºey
isteyebileceðimiz sorusu akla gelebilir, ama ileride bunun çok doðal ve gerekli bir iºlem
olduðunu göreceðiz.) Bu iºi nasýl gerçekleºtireceðiz? Ýlk olarak aklýmýza ºu gelebilir: int türden
bir nesne tanýmlayalým ve adresin sayýsal bileºenini tanýmladýðýmýz int türden nesne içinde
tutalým. Yani adresin sayýsal bileºeni olan tamsayýyý int türden bir nesneye atayalým. Bu
durumda iki önemli sakýnca ortaya çýkacaktýr:
Söz konusu int nesnenin deðerine programýn herhangi bir yerinde tekrar ulaºtýðýmýzda, bunun
bir adres bilgisinin (yani iki bileºenli bir bilginin) sayýsal bileºeni mi yoksa int türden normal bir
deðer mi olarak yorumlanacaðýný nereden bileceðiz? Peki örneðin deðiºkenin isminden,
deðerinin bir adres bilgisinin sayýsal bileºeni olduðu sonucunu çýkardýðýmýzý düºünelim, bu
durumda adresin tür bileºeninin ne olduðunu nereden anlayacaðýz?
O zaman belki de ºu önerilecektir: int türden bir adres bilgisini int türden bir nesnede, char
türden bir adres bilgisini char türden bir nesnede, double türden bir adres bilgisini ise double
türden bir nesnede saklayalým, vs. Ama örneðin 64K'lýk bir adres alanýnýn söz konusu olduðunu
düºünelim. toplam 65535 byte söz konusu olabileceðine göre bize 2byte uzunluðunda bir
nesne gerekecek. Örneðin 1 byte uzunlukta bir nesne içinde ancak ilk 255 byte'a iliºkin sayýsal
bileºenleri tutarken, 8 byte uzunluðunda bir nesne içinde de gerekmediði halde çok büyük bir
alana iliºkin adres bilgisini tutabiliriz.
int sabitleri int türden deðiºkenlere, gerçek sayý sabitleri gerçek sayý türünden deðiºkenlere
doðal olarak atanýyorlar. Yani her sabit türünün doðal olarak atanabileceði türden bir deðiºken
tanýmlayabiliyoruz. ݺte adres de ayrý bir tür olduðuna göre adres türünün de doðal olarak
atanabileceði deðiºkenler tanýmlanabilir. Bu deðiºkenlere (nesnelere) gösterici (pointer) denir.
‘a’
/* char türden bir sabittir */
char a;
/* a char türden bir deðiºkendir */
int b;
/* b int türden bir deðiºkendir */
2000L
/* long türden bir sabittir */
long l;
/* l long türden bir deðiºkendir */
(<tür> *) 0x1B00
/* adres sabiti */
pointer
/* içinde adres tutan bir deðiºken */
Gösterici (pointer) içinde adres bilgisi tutan bir deðiºkendir (nesnedir). Göstericiler de nesne
olduklarý için bellekte bir yer kaplarlar. Göstericilerin bellekte kapladýklarý yerdeki 1’ler ve
0’larýn bir tamsayý olarak yorumlanýr, ve yorumlanan bu deðer bir adres bilgisinin sayýsal
bileºenini gösterir.
Peki adres bilgisinin iki bileºenli bir bilgi olduðunu söylemiºtik. Göstericinin deðeri adresin
sayýsal bileºeni olarak yorumlanacaksa adresin tür bileºeni nasýl elde edilecek? Zira bellekte
yalnýzca 1 ler ve 0 lar var. Göstericilerin tuttuðu adres bilgilerinin sayýsal bileºenleri göstericiler
içinde saklanan tamsayýnýn deðeridir. Adres bilgisinin tür bileºeni ise göstericinin tanýmlanmasý
sýrasýnda bildirilen türdür.
Göstericilerin Bildirimleri
Göstericiler adres bilgilerini saklamak ve adreslerle ilgili iºlemler yapmak için kullanýlan
nesnelerdir. Göstericilerin içlerinde adres bilgileri bulunur. Bu nedenle gösterici ile adres hemen
hemen eº anlamlý olarak düºünülebilir. Ancak gösterici deyince bir nesne, adres deyince bir tür
akla gelmelidir.
Gösterici bildirimlerinin genel biçimi ºöyledir:
<tür> *<gösterici ismi>;
<tür> göstericinin (içerisindeki adresin) türüdür. char, int, float... gibi herhangi bir tür
olabilir.
Burada * göstericiyi ya da adresi temsil etmektedir.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
176
Buy RoboPDF
GÖSTERÝCÝLER
Örnek gösterici bildirimleri:
float *f;
char *s;
int *dizi;
unsigned long *PDWORD;
Gösterici bildirimlerinin diðer türlere iliºkin bildirimlerden * atomu ile ayrýlmaktadýr.
char s;
bildiriminde s char türden bir deðiºken iken
char *s;
bildiriminde s char türden bir göstericidir. Ýçerisine char türden bir adres konulmalýdýr. Bu
bildirimden derleyici ºu bilgileri çýkaracaktýr:
s bir nesnedir, yani bellekte bir yer kaplar. s nesnesi için bellekte ayrýlan yerdeki 1 ler ve 0 lar
char türden bir adresin sayýsal bileºeni olarak yorumlanýrlar. Bu adresin tür bileºeni ise char
türüdür.
Burada * bir operatör deðildir. Sentaks olarak nesnenin bir gösterici olduðunu anlatmaktadýr.
Ritchie stilinde, okunabilirlik açýsýndan * ile gösterici ismi bitiºik yazýlmalýdýr. Gösterici
bildirimleri ile normal bildirimler bir arada yapýlabilir. Örneðin :
int *p, a;
Burada p int türden bir göstericidir ama a int türden bir normal bir deðiºkendir.
Ayný türden birden fazla göstericinin bildirimi yapýlacaksa araya virgül konularak, her gösterici
deðiºkenin bildirimi * atomu ile yapýlmalýdýr.
char *str, *ptr;
Yukarýdaki bildirimde str ve ptr char türden göstericilerdir.
long *p1, *p2, l, k[20];
Yukarýdaki bildirimde p1 ve p2 long türden göstericiler, l long türden bir deðiºken ve k ise
long türden 20 elemanlý bir dizidir.
Göstericilerin Uzunluklarý
Bir gösterici tanýmlamasýyla karºýlaºan derleyici –diðer tanýmlamalarda yaptýðý gibi- bellekte o
gösterici için bir yer tahsis eder. Derleyicilerin göstericiler için tahsis ettikleri yerlerin uzunluðu
donaným baðýmlý olup, sistemden sisteme deðiºebilmektedir. 32 bit sistemlerde (örneðin UNIX
ve Windows 95 sistemlerinde) göstericiler 4 byte uzunluðundadýr. 8086 mimarisinde ve DOS
altýnda çalýºan derleyicilerde ise göstericiler 2 byte ya da 4 byte olabilirler. DOS’ta 2 byte
uzunluðunda ki göstericilere yakýn göstericler (near pointer), 4 byte uzunluðundaki
göstericilere ise uzak göstericiler (far pointer) denilmektedir. Biz uygulamalarýmýzda ºimdilik
göstericilerin 2 byte olduðunu varsayacaðýz.
Göstericilerin uzunluklarý türlerinden baðýmsýzdýr. Örneðin:
char *str;
int *p;
float *f;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
177
Buy RoboPDF
20 . BÖLÜM :
DOS altýnda str, p ve f isimli göstericilerin hepsi de bellekte 2 byte ya da 4 byte yer kaplarlar.
Çünkü göstericilerin türü yalnýzca içinde tuttuklarý adres bilgisinin hangi tür olarak
yorumlanacaðý ile ilgilidir.
Bir göstericiye ayný türden bir adres bilgisi yerleºtirilmelidir. Örneðin :
int *p;
p = 100;
Burada p göstericisine adres olmayan bir bilgi atanmaktadýr. C dilinin kurallarýna göre, derleme
zamanýnda bir hata oluºumuna yol açmaz ama yanlýºtýr. (Derleyiciler bu durumu bir uyarý
mesajý ile bildirirler.) Bu durum ileride detaylý olarak ele alýnacaktýr.
int *p;
p = (char *) 0x1FC0;
Burada int türden p göstericisine char türden bir adres bilgisi atanmaktadýr. C dilinin
kurallarýna göre, derleme zamanýndan bir hata oluºumuna yol açmaz ama yanlýºtýr.
(Derleyiciler bu durumu bir uyarý mesajý ile bildirirler.)
int *p;
p = (int *) 0x1FC5;
/* geçerli ve uygun bir atamadýr */
Bir adres bilgisi göstericiye atandýðýnda adresin sayýsal bileºeni gösterici içerisine yerleºtirilir.
int *p;
p = (int *) 0x1FC3;
Burada bellekte p gösterici deðiºkeninin tutulduðu yere 0x1FC3 sayýsal deðeri yerleºtirilecektir.
...
0001
1111
1100
0011
...
p
p göstericisinin bellekte bulundugu yere 1FC3 deðeri
yazýlýyor.
Göstericilere kendi türlerinden bir adres bilgisi atanmasýnýn gerektiðini söylemiºtik. ªimdiye
kadar adres bilgilerini yalnýzca adres sabitleri ºeklinde gördük ve örneklerimizde de
göstericilere adres sabitlerini atadýk. Peki adres sabitleri dýºýnda adres bilgileri taºýyan baºka
ifadeler mevcut mudur? Evet. Örneðin diziler konusunu incelerken dizi isimlerinin, nesne
göstermediðini, bir adres bilgisi olduðunu söylemiºtik, ºimdi bu konuyu daha detaylý olarak
inceleyeceðiz:
Dizi isimleri bir adres bilgisi belirtir. Adres bilgisinin iki bileºeni olduðuna göre örneðin:
char s[10];
gibi bir dizi tanýmlamasý yapýldýðýnda dizi ismi olan s bir adres bilgisi belirtecektir. Peki bu
bilginin tür bileºeni ve sayýsal bileºenleri nelerdir?
Dizi isimleri, türleri dizinin türleriyle ayný ve sayýsal bileºenleri dizi için bellekte ayrýlan bloðun
baºlangýç yerini gösteren bir adres bilgisi olarak ele alýnýrlar. Örneðin yukarýdaki örnekte dizinin
bellekte aºaðýdaki ºekilde yerleºtirildiðini düºünelim:
s[0] 1C00
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
178
Buy RoboPDF
GÖSTERÝCÝLER
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 türden 1C00 adresine eºdeðerdir.
Göstericilere kendi türlerinden bir adres bilgisi atamak gerektiðine göre aºaðýdaki atamalarýn
hepsi legal ve doðrudur:
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 göstericinin içine ayný türden bir dizinin ismi atanmalýdýr. Örneðin:
int *p;
char s[] = “Necati”;
p = s;
Yukarýdaki örnekte int türden bir göstericiye char türden bir adres bilgisi atanmýºtýr. Derleme
zamanýnda error oluºumuna neden olmaz ama yanlýºtýr, ileride detaylý olarak incelenecektir.
C dilinde hiçbir deðiºkenin ya da dizinin tahsisat yeri programcý tarafýndan belirlenemez.
Programcý deðiºkeni tanýmlar, derleyici onu herhangi bir yere yerleºtirebilir.
Dizi isimleri göstericiler gibi sol taraf deðeri olarak kullanýlamaz. Örneðin, s bir dizi ismi olmak
üzere
++s;
deyimi error oluºturur. Çünkü dizi isimleri nesne göstermezler.
Özetle, adres belirten 3 tür ifade ele alýndý.
1. Adres sabitleri.
2. Göstericiler.
3. Dizi isimleri.
Göstericiler içlerinde adres bilgileri taºýdýklarýna göre bir göstericiye ayný türden baºka bir
göstericinin deðerinin atanmasý da tamamen uygundur.
int *p, *q;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
179
Buy RoboPDF
20 . BÖLÜM :
p = (int *) 0x1AA0;
q = p;
Yukarýdaki atama ile q göstericisine p göstericisinin deðeri atanmýºtýr. Yani bu atama
deyiminden sonra q göstericisinin de içinde (int *) 0x1AA0 adresi bulunacaktýr.
...
0001
1010
1010
0000
...
...
...
0001
1010
1010
0000
p
p göstericisine (int *) 1AA0 adresi atanýyor.
q
q göstericisine de p göstericisinin içindeki deðer
atanýyor
int k;
gibi bir tanýmlama yaptýðýmýzda k deðiºkeni int türdendir, içindeki deðer int olarak
yorumlanacaktýr.
20
gibi, tek bir sabitten oluºan bir ifade de int türdendir, çünkü 20 int türden bir sabittir. Baºka
bir deyiºle
k
ifadesiyle
20
ifadesinin türleri aynýdýr. Her iki ifadenin türü de int türüdür. Ancak k ifadesi nesne gösteren
bir ifade iken 20 ifadesi nesne göstermeyen bir ifadedir. (sað taraf deðeridir)
int *ptr;
gibi bir tanýmlama yapýldýðýnda ptr nesnesinin türü nedir? ptr içinde int türden bir adres
sakladýðýna göre ptr nesnesinin türü int türden bir adrestir.
int a[100];
Yukarýdaki tanýmlamadan sonra
a
gibi bir ifade kullanýlýrsa bu ifadenin türü de "int türden bir adres" dir. Ancak ptr ifadesi nesne
gösteren bir ifadeyken, yani bir sol taraf deðeriyken, a ifadesi nesne gösteren bir ifade
deðeridir. Sol taraf deðeri olarak kullanýlamaz.
Yine bir adres sabitinden oluºan
(int *) 0x1A00
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
180
Buy RoboPDF
GÖSTERÝCÝLER
ifadesinin türü de int türden bir adrestir. Ancak bu ifade de sol taraf deðeri deðildir.
Görüldüðü gibi göstericiler, belirli bir adres türünden, nesnelerdir. (sol taraf deðerleridir.)
Gösterici Operatörleri
C dilinde toplam 4 tane gösterici operatörü vardýr. Bu operatörler göstericiler ve adres
bilgileriyle kullanýlabilirler.
Gösterici operatörleri ºunlardýr :
*
&
[]
->
içerik operatörü
adres operatörü
köºeli parantez operatörü
ok operatörü
indirection operator (dereferencing operator)
address of operator
index operator (subscript operator)
arrow operator
Bu operatörlerden ok operatörü yapý türünden adreslerle kullanýldýðý için yapýlar konusunda
detaylý olarak incelenecektir.
Gösterici Operatörlerinin Ayrýntýlý Ýncelenmesi
& Adres Operatörü (adress of operator)
Adres operatörü tek operand alan önek konumunda bir operatördür. (unary prefix). Operatör
öncelik tablosunun ikinci seviyesinde yer alýr. Bu operatörün ürettiði deðer operandý olan
nesnenin adresidir. Yani operatörün ürettiði adres bilgisinin sayýsal bileºeni nesnenin bellekteki
fiziksel adres numarasý, tür bileºeni ise nesnenin türü ile ayný türdür. & operatörünün operandý
mutlaka bir nesne olmalýdýr. Çünkü yalnýzca nesnelerin (sol taraf deðerlerinin) adres bilgilerine
ulaºýlabilir. & operatörüne operand olarak nesne olmayan bir ifade gönderilirse bu durum
derleme zamanýnda hata oluºumuna neden olacaktýr. (Borland derleyicileri bu durumda ºöyle
bir error mesajý verirler : “must take address of memory location”)
int k;
&k
ifadesini ele alalým. Bu ifadenin ürettiði deðer int türden bir adres bilgisidir. Adres bilgilerinin
iki bileºeni olduðunu söylemiºtik. Yukarýdaki ifadenin ürettiði bilginin sayýsal bileºeni k
nesnesinin bellekte yerleºtirildiði yerin baºlangýç adresi, tür bileºeni ise int türüdür. Zira k
deðiºkeni int türden bir deðiºkendir.
& operatörü diðer tek operand alan (unary) operatörler gibi, operatör öncelik tablosunun 2.
seviyesinde bulunur. Bilindiði gibi bu öncelik seviyesinin öncelik yönü “saðdan sola”dýr.
Adres operatörü ile elde ettiðimiz adres ayný türden bir göstericiye atanmalýdýr. Örneðin
aºaðýdaki programda bir göstericiye farklý türden bir adres atanmýºtýr:
char ch = 'x';
int *p;
p = &ch;
/* error deðil ama yanlýº */
Bu durumda C'de adres belirten 4 tür ifade görmüº olduk:
1.
2.
3.
4.
Adres sabitleri.
Göstericiler.
Dizi isimleri.
& operatörü ile oluºturulmuº ifadeler.
Tabi bu operatörün ürettiði adres bilgisi nesne deðildir. Örneðin:
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
181
Buy RoboPDF
20 . BÖLÜM :
int x;
++&x
/* error */
gibi bir iºlem error ile neticelenir. ++ operatörünün operandý nesne olmalýdýr. Yukarýdaki
ifadede ++ operatörüne operand olan &x ifadesi bir nesne göstermemektedir. Yalnýzca bir
adres deðeridir.
* Ýçerik Operatörü (indirection operator)
Ýçerik operatörü de önek konumunda bulunan ve tek operand alan bir operatördür (unary
prefix). Bir gösterici, * operatörünün operandý olursa, elde edilen ifade p göstericisinin
içerisindeki RAM adresinde bulunan, nesneyi temsil eder. Dolayýsýyla, * operatörü ile
oluºturulan bir ifade bir nesneyi temsil etmektedir, ve sol taraf deðeri olarak kullanýlabilir.
int a;
gibi bir bildirimde a nesnesinin türü int’dir. Çünkü a nesnesi içerisinde int türden bir bilgi
tutulmaktadýr.
int *p;
bildiriminde p nin türü int türden bir adrestir.
char *ptr;
gibi bir bildirimden iki ºey anlaºýlýr:
ptr char türden bir göstericidir. Ýçerisine char türden bir adres bilgisi yerleºtirilir. ptr
göstericisi * operatörü ile birlikte kullanýldýðýnda elde edilen nesne char türdendir. Yani *ptr
char türden bir nesnedir.
Örneðin:
int *p;
p = (int *) 0x1FC3;
*p = 100;
Burada *p’nin türü int’dir. Dolayýsýyla *p = 100 gibi bir iºlemden yalnýzca 0x1FC3 byte’ý deðil,
0x1FC3 ve 0x1FC4 bytelarýndan her ikisi birden etkilenir.
Göstericinin içerisindeki adresin sayýsal bileºeni nesnenin düºük anlamlý byte’ýnýn adresini içerir.
Bu durumda bir göstericinin içerisine RAM’deki herhangi bir bölgenin adresi atanabilir. Daha
sonra * operatörü ile o RAM bölgesine eriºilebilir.
* operatörünün operandý bir adres bilgisi olmak zorundadýr. Yani operand adres sabiti olabilir.
Dizi ismi olabilir. Bir gösterici olabilir. Adres operatörü ile elde edilmiº bir adres ifadesi olabilir.
* operatörü yalnýz göstericilerle deðil, her tür adres bilgisi ile (adres sabitleri ve dizi isimleri
vs.) de kullanýlabilir. Bu operatör operandý ile belirtilen adresteki nesneye eriºmekte kullanýlýr.
Bu operatör ile elde edilen deðer, operandý olan adreste bulunan deðerdir.
* operatörü bir adrese uygulandýðýnda ifade bir nesne belirtir. Nesnenin türü operand olarak
kullanýlan adresin türü ile ayný türdendir. Örneðin :
int main()
{
char s[] = “Balýkesir”;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
182
Buy RoboPDF
GÖSTERÝCÝLER
putchar(*s);
}
return 0;
* operatörü operatör öncelik tablosunun 2. düzeyinde saðdan sola öncelikli bulunmaktadýr.
Örneðin :
*s + 1;
ifadesinde önce *s yapýlýr. Sonra + operatörü yapýlýr. Oysa ifade *(s + 1) biçiminde olsaydý
önce + operatörü yapýlýrdý.
Derleyiciler * operatörünün çarpma operatörü mü yoksa adres operatörü mü olduðunu ifade
içerisindeki kullanýmýna bakarak anlar. Çarpma operatörü iki operand alýrken adres operatörü
önek konumundadýr ve tek operand alýr. Örnek :
*s * 2
ifadesinde 1. * adres operatörü iken 2. * aritmetik çarpma operatörüdür.
[] Köseli Parantez (index) Operatörü :
Dizi elemanlarýna eriºmekte kullandýðýmýz köºeli parantez aslýnda unary prefix bir gösterici
operatörüdür.
[] içerisine tamsayý türünden bir ifade yazýlýr. (Ýfadenin deðeri pozitif olmak zorunda deðildir.)
[] operatörünün operandý dizi ismi olmak zorunda deðildir. Bir adres bilgisi olmak zorundadýr.
[] operatörünün operandý bir dizi ismi olabilir. Gösterici olabilir. Diðer adres belirten ifadeler
olabilir.
p[n] ile *(p + n) tamamen eºdeðerdir.
Yani köºeli parantez operatörü bir adresten n ilerisinin içeriðini almak için kullanýlýr. [] operaötü
ile elde edilen nesnenin türü operandý olan adresin türü ile ayný türdendir. Örneðin:
#include <stdio.h>
int main()
{
char s[] = "Ýstanbul";
char *p;
p = s + 1;
putchar(p[2]);
return 0;
}
[] operatörü öncelik tablosunun en yüksek düzeyinde bulunur. Örneðin:
&p[n]
ifadesinde önce [] yapýlýr, nesne elde edilir daha sonra nesnenin adresi alýnýr.
[] içerisindeki ifadenin sayýsal deðeri negatif olabilir. Örneðin p[-2] geçerli bir ifadedir.
#include <stdio.h>
int main()
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
183
Buy RoboPDF
20 . BÖLÜM :
{
char ch = '0';
(&ch)[0] = 'b'
putchar(ch);
return 0;
}
&ch ifadesi parantez içine alýnmasaydý [] operatörünün önceliði söz konusu olacaðýndan önce
ch[0] yapýlýrdý. Buradan da bir nesne elde edilemeyeceðinden (& operatörünün operandýnýn
nesne olmasý gerektiðinden) hata oluºurdu.
Adreslerle ݺlemler / Adreslerin Artýrýlmasý ve Eksiltilmesi (gösterici
aritmetiði)
C dilinde adreslerle tamsayý türünden sayýlar toplama ve çýkarma iºlemlerine sokulabilir. Ýki
adres ayný türden ise karºýlaºtýrma operatörleri ile iºleme sokulabilir. Burada adreslerin sayýsal
bileºenleri iºleme sokulmaktadýr.
C dilinde bir adres bilgisi tamsayý türleri ile artýrýlabilir veya eksiltilebilir. Sonuç ayný türden bir
adres bilgisi olur. Bir adres bilgisi 1 artýrýldýðýnda adresin sayýsal bileºeni adresin türünün
uzunluðu kadar artmaktadýr. Bu durumda örneðin DOS'da char türden bir göstericiyi, 1
artýrdýðýmýzda adresin sayýsal bileºeni 1 int türden bir göstericiyi 1 artýrdýðýmýzda ise adresin
sayýsal bileºeni 2 artar. Bu durumda p[n] ifadesi p adresinden n byte ilerisinin içeriði deðil, p
adresinden n * p göstericisinin türünün uzunluðu kadar byte ilerinin içeriði anlamýna gelir.
Ýki adres bilgisinin toplanmasý faydalý bir iºlem olmadýðý gerekçesiyle yasaklanmýºtýr. Ancak iki
adres bilgisi birbirinden çýkartýlabilir. Ýki adres birbirinden çýkartýlýrsa sonuç int türden olur. Ýki
adres birbirinden çýkartýldýðýnda önce adreslerin sayýsal bileºenleri çýkartýlýr, sonra elde edilen
deðer adresin türünün uzunluðuna bölünür. Örneðin a int türden bir adres olmak üzere:
&a[2] - &a[0] ifadesinden elde edilen deðer 2'dir.
#include <stdio.h>
int main()
{
int a[5] = {1, 2, 3, 4, 5};
int *p;
p = a;
printf("%p adresindeki deðer = %d\n", p, *p);
++p;
printf("%p adresindeki deðer = %d\n", p, *p);
return 0;
}
++ ve -- operatörlerinin gösterici operatörleriyle birlikte kullanýlmasý
++*p durumu
x = ++*p;
*p = *p + 1; anlamýna gelir. *p bir nesne gösterdiði için nesnenin deðeri 1 artýrýlacaktýr.
Yukarýdaki deyimle x deðiºkenine *p nesnesinin artýrýlmýº deðeri atanacaktýr.
*++p durumu
p göstericisinin deðeri 1 artýrýlýr. Artýrýlmýº adresteki nesneye ulaºýlmýº olur.
x = *++p;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
184
Buy RoboPDF
GÖSTERÝCÝLER
deyimi ile x deðiºkenine artýrýlmýº adresteki bilgi atanýr.
*p++ durumu
++ operatörü ve * operatörünün ikisi de 2. öncelik seviyesindedir ve bu öncelik seviyesine
iliºkin öncelik yönü saðdan soladýr. Önce ++ operatörü ele alýnýr ve bu operatör ifadenin geri
kalan kýsmýna p göstericisinin artmamýº deðerini gönderir. Bu adresteki nesneye ulaºýlýr ve
daha sonra p göstericisinin deðeri 1 artýrýlýr.
x = *p++;
deyimi ile x deðiºkenine *p nesnesinin deðeri atanýr daha sonra p göstericisinin deðeri 1
artýrýlýr.
&x++
/* error */
x nesnesinin artmamýº deðeri ifadenin geri kalanýna gönderilir. (Adres operatörüne operand
olur.) Bu da bir nesne olmadýðý için error oluºur. (Adres operatörünün operandý nesne olmak
zorundadýr.)
&++x /* error */
x nesnesinin artmýº deðeri ifadenin geri kalanýna gönderilir. (Adres operatörüne operand olur.)
Bu da bir nesne olmadýðý için error oluºur. (Adres operatörünün operandý nesne olmak
zorundadýr.)
++&x /* error */
x nesnesinin adresi ++ operatörüne operand olur. ++ operatörünün operandý nesne olmak
zorunda olduðu için derleme zamanýnda error oluºacaktýr.
& operatörü ile ++ ya da -- operatörlerinin her türlü kombinasyonu derleme zamanýnda hata
oluºmasýna neden olur.
++p[i] Durumu
Ýndex operatörü 1. öncelik seviyesinde, ++ operatörü ise 2. öncelik seviyesindedir. Bu
durumda önce derleyici tarafýndan indeks operatörü ele alýnýr. p[i] ifadesi bir nesne gösterir.
Dolayýsýyla ++ operatörüne operand olmasýnda bir sakýnca yoktur. Söz konusu ifade
p[i] = p[i] + 1;
anlamýna gelmektedir. Yani p[i] nesnesinin deðeri 1 artýrýlacaktýr.
p[i]++ Durumu
x = p[i]++;
Önce p[i] nesensinin artmamýº deðeri üretilir, ifadenin geri kalanýna p[i] nesnesinin artmamýº
deðeri kullanýlýr. Yani yukarýdaki örnekte x deðiºkenine p[i] nesnesinin artýrýlmamýº deðeri
atanýr, daha sonra p[i] nesnesi 1 artýrýlýr.
p[++i] Durumu
x = p[++i];
Önce i 1 artýrýlýr. Daha sonra artýrýlmýº adresteki bilgi x deðiºkenine atanýr.
p[i++] Durumu
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
185
Buy RoboPDF
20 . BÖLÜM :
x = p[i++];
Burada p[i] nesnesinin deðeri x deðiºkenine atanýr. Daha sonra i deðiºkeni 1 artýrýlýr.
p++[i] durumu
x = p++[i];
Pek tercih edilen bir ifade deðildir.Burada önce p[i] x deðiºkenine atanýr. Sonra p göstericisinin
deðeri 1 artýrýlýr.
Göstericilere Ýlk Deðer Verilmesi
Diðer türden deðiºkenlerde olduðu gibi göstericilere de tanýmlanmalarý sýrasýnda ilk deðer
verilebilir. Göstericilere ilk deðer verme iºlemi göstericinin türünden bir adres bilgisi ile
yapýlmalýdýr. Örnekler:
char s[100];
double x;
int *ptr = (int *) 0x1A00;
char * str = (char *) 0x1FC0;
chat *p = s;
double *dbptr = &x;
Fonksiyon Parametre Deðiºkeni Olarak Göstericilerin Kullanýlmasý
Bir fonksiyonun parametre deðiºkeni herhangi bir türden gösterici olabilir.
void func(int *p)
{
...
}
Bir fonksiyonun parametre deðiºkeni bir gösterici ise fonksiyon da ayný türden bir adres bilgisi
ile çaðýrýlmalýdýr.
Bir fonksiyonun baºka bir fonksiyonun yerel deðiºkenini deðiºtirebilmesi için o fonksiyonun
yerel deðiºkeninin 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 deðer elde edip, çaðýran fonksiyona bu deðeri iletmek isterse 2 yöntem
kullanýlabilir:
1. Elde edilen deðer çaðýrýlan fonksiyon tarafýndan geri dönüº deðeri olarak üretilir.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
186
Buy RoboPDF
GÖSTERÝCÝLER
2. Elde edilen deðer çaðýran fonksiyonun göndermiº olduðu adrese yerleºtirilir. Tabi bunun için
çaðýrýlan fonksiyonun parametre deðiºkeninin bir gösterici olmasý gerekir. Bir örnekle
gösterelim:
Kendisine gönderilen bir sayýnýn faktoriyelini hesaplayana ve bu deðeri parametre olarak
gönderilen adrese kopyalayan bir fonksiyon yazalým.
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 deðiºken olsun. C dilinde bir fonksiyon
func(a);
biçiminde çaðýrýlmýºsa, çaðýrýlan bu fonksiyonun, a deðiºkenini deðiºtirme ºansý yoktur. (Bu tür
fonksiyon çaðýrýmýna "deðer ile çaðýrma" (call by value) denmektedir. Fonksiyonun a
deðiºkenini deðiºtirebilmesi için
func(&a);
biçiminde çaðýrýlmasý gerekir. Örneðin scanf fonksiyonuna & operatörü ile bir nesnenin
adresinin arguman olarak yollanmasýnýn nedeni budur. Bu ºekilde fonksiyon çaðýrmaya C'de
"adres ile çaðýrma" (call by reference) denmektedir.
int türden iki yerel nesnenin deðerlerini deðiºtirmek (swap etmek) istediðimizi düºünelim.
Bunu bulunduðumuz fonksiyon içerisinde aºaðýdaki gibi yapabiliriz:
int main()
{
int a = 10, b = 20, temp;
temp = a;
a = b;
b = temp;
/*....*/
}
swap iºleminin bir fonksiyon tarafýndan yapýlmasýný istersek, aºaðýdaki gibi bir fonksiyon iºimizi
görür müydü?
void swap(int x, int y)
{
int temp = x;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
187
Buy RoboPDF
20 . BÖLÜM :
x = y;
y = temp;
}
int main()
{
int a = 10, b = 20;
swap(a, b);
printf("a = %d\nb = %d\n", a, b);
return 0;
}
Yukarýdaki program çalýºtýlýdýðýnda ekrana
a = 10
b = 20
yazacaktýr. Zira swap fonksiyonu a ve b deðiºkenlerinin deðerlerini deðiºtirmemiºtir. Zaten
yerel nesneler olan a ve b deðiºkenlerinin deðerleri ancak adresleri bir fonksiyona gönderilerek
deðiºtirilebilirdi. Oysa bizim yukarýdaki swap fonksiyonumuz a ve b deðiºkenlerinin deðerlerini
parametre deðiºkenleri olan x ve y deðiºkenlerine kopyalýyor. Yani deðerleri deðiºtirilen
parametre deðiºkenleri x ve y'nin deðerleri. Ýstediðimiz amacý gerçekleºtirecek fonksiyon
dýºarýdan adres alacaðý için gösterici parametre deðiºkenlerine sahip olmalý:
void swap(int *p1, int *p2)
{
int temp = *p1;
*p1 = *p2;
*p2 = temp;
}
Dizilerin Fonksiyonlara Göstericiler Yoluyla Geçirilmesi
Bir diziyi fonksiyona geçirebilmek için dizinin baºlangýç adresinin ve uzunluðunun geçirilmesi
yeterlidir. Dizinin baºlangýç adresini alacak parametre deðiºkeninin ayný türden bir gösterici
olmasý gerekir. Fonksiyonun 2. parametresi dizinin uzunluðunu tutacak int türden bir deðiºken
olabilir. Bir dizinin baºlangýç adresini parametre olarak alan fonksiyon dizi elemanlarýna köºeli
parantez operatörü ya da içerik operatörü ile eriºebilir. Ancak dizi elemanlarýnýn kaç tane
olduðu bilgisi fonksiyon tarafýndan bilinemez. Bu nedenle dizi uzunluðunu ikinci bir parametre
olarak fonksiyona yolluyoruz. Örnek:
#include <stdio.h>
void display (int *p, int size)
{
int i;
for (i = 0; i < size; ++i)
printf("%d ", p[i]);
}
int main()
{
int a[5] = {3, 8, 7, 6, 10};
display(a, 5);
return 0;
}
Dizi uzunluðu hakkýnda fonksiyona bilgi vermek amacý ile baºka teknikler de kullanýlýr. Dizi
uzunluðunu dizinin birinci parametresinde saklayabiliriz. Yukarýdaki fonksiyonu, dizi
uzunluðunu birinci dizi elemanýnda saklayarak yeniden yazalým:
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
188
Buy RoboPDF
GÖSTERÝCÝLER
void disp (int *p)
{
int i;
for (i = 1; i < p[0]; ++i)
printf("%d ", p[i]);
}
int main()
{
int a[6] = {6, 3, 8, 7, 6, 10};
saklýyor */
/* birinci eleman dizi uzunluðu bilgisini
disp(a);
return 0;
}
Bir dizi içerisinde, çözülen problemin koºullarýna baðlý olarak, belirli bir deðerin bulunmasý
olanaksýzsa, bu deðer dizi sonunu belirten bir iºaret olarak kullanýlabilir. Bir dizi içinde
öðrencilerin aldýklarý notlarý sakladýðýmýzý varsayalým. Öðrencilerin negatif bir not almalarý
mümkün olmadýðýna göre dizi içerisinde negatif bir sayý bulunamaz. Bu durumda biz -1 gibi bir
deðeri dizi sonunu belirtmek amacýyla kullanabiliriz. Yukarýdaki örneði yeniden yazalým:
void display (int *p)
{
int i;
for (i = 0; p[i] != -1; ++i)
printf("%d ", p[i]);
}
int main()
{
int a[6] = {3, 8, 7, 6, 10, -1};
display(a, 5);
return 0;
}
n elemanlý int türden bir dizinin aritmetik ortalamasýný 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];
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
189
Buy RoboPDF
20 . BÖLÜM :
return
total / size;
}
size elemanlý int türden bir
yazýlmasý:
dizi içerisindeki en büyük sayýya geri dönen 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};
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 yöntemiyle int türden bir diziyi küçükten büyüðe sýraya dizen fonksiyon örneði:
#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]);
}
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
190
Buy RoboPDF
GÖSTERÝCÝLER
Geri Dönüº Deðeri Adres Türünden Olan Fonksiyonlar
Bir fonksiyon parametre deðiºkeni olarak bir gösterici alabildiði gibi, adres türlerinden bir geri
dönüº deðerine de sahip olabilir. Geri dönüº deðerinin adres olduðu, fonksiyon tanýmlanýrken *
operatörü ile aºaðýdaki biçimde belirtilmektedir.
<adresin türü> *<fonksiyon ismi> ([parametreler])
{
...
}
Örneðin int türden bir adrese geri dönen ve parametre deðiºkeni almayan sample isimli
fonksiyon aºaðýdaki gibi tanýmlanabilir:
int *sample(void)
{
...
}
Yukarýdaki fonksiyon tanýmlama ifadesinden * atomu kaldýrýlýrsa fonskiyon int türden bir deðer
döndürür.
Bir adres türüne geri dönen bir fonksiyonun çaðýrýlma ifadesi, ayný türden bir göstericiye
atanmalýdýr.
int *ptr;
ptr = sample();
gibi.
Benzer ºekilde:
char *str;
char *func(void) {
...
}
str = func();
...
Adrese geri dönen fonksiyonlara C programlarýnda çok rastlanýr. Standart C fonksiyonlarýndan
bir çoðu, adres türünden bir deðer döndürür.
Bir dizinin en büyük elemanýný bulup bu elemanýn deðerine geri dönen getmax fonksiyonunu
daha önce tasarlamýºtýk. ªimdi ayný fonksiyonu en büyük elemanýn adresine geri dönecek
ºekilde tasarlayalým:
#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;
}
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
191
Buy RoboPDF
20 . BÖLÜM :
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;
}
Göstericilere Ýliºkin Uyarýlar ve Olasý Gösterici Hatalarý
Bir Göstericiye Farklý Türden Bir Adres Atanmasý:
Bir göstericiye farklý türden bir adres atandýðýnda, C derleyicileri durumu ºüpheyle karºýlayarak
bir uyarý mesajý verirler. Yani bu iºlem hata (error) deðil uyarý gerektirmektedir. Ancak
derleyici yine de farklý türden adresin sayýsal bileºenini hedef göstericiye atar. Borland
derleyicileri bu durumda aºaðýdaki uyarý mesajýný verirler:
warning : suspicious pointer coversion in function ......
Bu iºlemin faydalý bir gerekçe ile yapýlma ihtimali zayýftýr. Ancak bazan bilinçli olarak da
yapýlabilir. O zaman bilinçli olarak yapýldýðý konusunda derleyiciyi ikna etmek gerekmektedir.
int *p;
char s[ ] = "Ankara";
p = s;
/* uyarý */
Uyarý bilinçli tür dönüºtürmesiyle kesilebilir.
p = (int *) s;
Tür dönüºtürme operatörü kullanýlarak char türden bir adres int türden bir adrese
dönüºtürülmüºtür.
Bir göstericiye farklý türden bir adres atanmasý durumunda, otomatik tür dönüºümü
sonucunda, atama operatörünün sað tarafýndaki ifadenin türü, atama operatörünün sol
tarafýndaki nesnenin türüne dönüºtürülecek, ve dönüºtürülmüº olan adres bilgisi nesneye
atanacaktýr.
Örneðin int türden bir göstericiye char türden bir adres atadýðýmýzý düºünelim:
int main()
{
char s[20] = "Necati Ergin";
int *p;
}
p = s;
...
return 0;
Bu durumda int türden p göstericisini içerik operatörü ya da indeks operatörüyle
kullandýðýmýzda elde ettiðimiz nesne char türden deðil int türden olacaktýr. Böyle bir durumun
bilinçli olarak yapýlmýº olma ihtimali azdýr, ve bilinçli olarak yapýlmasý durumunda tür
dönüºtürme operatörü kullanýlarak, derleyicinin vereceði uyarý mesajý kesilmelidir. (derleyici
ikna edilmelidir)
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
192
Buy RoboPDF
GÖSTERÝCÝLER
C++ dilinde bir göstericiye farklý türden bir adres atanmasý durumunda, derleme zamanýnda
hata oluºacaktýr. Yani bu durum uyarý seviyesinden error seviyesine yükseltilmiºtir.
Bir Göstericiye Adres Olmayan Bir Deðerin Atanmasý
Bu da bilinçli olarak yapýlma ihtimali çok az olan bir iºlemdir. C derleyicileri ºüpheli olan bu
durumu bir uyarý mesajý ile programcýya bildirirler. Örneðin bu uyarý mesajý Borland
derleyicilerinde:
"nonportable pointer conversion"
ºeklindedir. Peki bir göstericiye adres bilgisi olmayan bir deðer atarsak ne olur? Yine otomatik
tür dönüºümü söz konusudur. Atama operatörünün sað tarafýndaki ifadenin türü, atama
operatörünün sol tarafýnda bulunan nesne gösteren ifadenin türüne çevrilerek, atama
yapýlacaktýr. Dolayýsýyla, atanan deðer göstericinin türünden bir adrese çevrilecek ve
göstericiye atanacaktýr. Örneðin:
int main()
{
int k, *ptr;
k = 1356;
ptr = k;
...
return 0;
/* uyarý */
}
Yukarýdaki örnekte ptr = k; atama deyiminden sonra bellekte ptr göstericisi için ayrýlan yere
1356 yazýlacaktýr. Yani *ptr ifadesi ile int türden bir nesneye ulaºýlacaktýr ki bu nesne de 1356
ve 1357 adreslerinde bulunan nesnedir.
Bu durumun bilinçli olarak yapýlmasý durumunda yine tür dönüºtürme operatörü kullanýlarak
derleyici ikna edilmeli ve uyarý mesajý kesilmelidir:
int main()
{
int k, *ptr;
k = 1356;
ptr = (int * ) k;
...
return 0;
/* uyarý
yok */
}
Yazýlarýn Fonksiyonlara Parametre Olarak Geçirilmesi
Yazýlar karakter dizilerinin içerisinde bulunurlar. Bir yazýyý fonksiyona parametre olarak
geçirebilmek için yazýnýn yalnýzca baºlangýç adresini fonksiyona geçirmek yeterlidir. Yani
fonksiyon yazýnýn (karakter dizisinin) baºlangýç adresi ile çaðýrýlýr. Yazýyý içinde tutan char
türden dizinin uzunluk bilgisini fonksiyona geçirmeye gerek yoktur. Çünkü yazýlarý saklamak
amacýyla kullanýlan karakter dizilerinin sonu null (ASCII karakter tablosýnda 0 sýra numaralý
karakter.) karakterle iºaretlenmiºtir. Karakter dizileri üzerinde iºlem yapan algoritmalar dizinin
sonunu null karakter yardýmýyla belirlerler.
Yazýlarla iºlem yapan fonksiyon char türden bir gösterici ile üzerinde iºlem yapacaðý karakter
dizisinin baºlangýç adresini alýr. Fonksiyon, null karakter görene kadar bir döngü ile yazýnýn
bütün karakterlerine eriºir.
str char türünden bir gösterici olmak üzere yazý üzerinde null karakter görene kadar iºlem
yapabilecek döngüler ºöyle oluºturulabilir:
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
193
Buy RoboPDF
20 . BÖLÜM :
while (*str != '\0') {
...
++str;
}
for (i = 0; str[i] != '\0'; ++i) {
...
}
Örneðin puts fonksiyonunun parametre deðiºkeni char türünden bir göstericidir. puts fonksiyonunu
myputs ismi ile yeniden yazalým:
#include <stdio.h>
void myputs(char *str)
{
while (*str != '\0') {
putchar(*str);
++str;
}
putchar('\n');
}
int main()
{
char s[] = "Deneme";
myputs(s);
return 0;
}
Yazýlarla Ýlgili ݺlem Yapan Fonksiyonlar
Bir grup standart C fonksiyonu vardýr ki, bu fonksiyonlar bir yazýnýn baºlangýç adresini
parametre olarak alarak yazý ile ilgili birtakým faydalý iºlemler yaparlar. Bu fonksiyonlara string
fonksiyonlarý denir. String fonksiyonlarýnýn prototipleri string.h dosyasý içindedir. Bu
fonksiyonlardan bazýlarýný inceleyelim :
strlen Fonksiyonu
Bu fonksiyon bir yazýnýn karakter uzunluðunu (kaç karakterden oluºtuðu bilgisini) elde etmek
için kullanýlýr.
Fonksiyonun prototipi:
unsigned int strlen(char *str);
ºeklindedir. Fonksiyonun parametre deðiºkeni uzunluðu hesaplanacak yazýnýn baºlangýç
adresidir. Fonksiyon null karakter görene kadar karakterlerin sayýsýný 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;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
194
Buy RoboPDF
GÖSTERÝCÝLER
}
standart C fonksiyonu olan strlen fonksiyonunu kendimiz yazsaydýk aºaðýdaki biçimlerde
yazabilirdik:
#include <stdio.h>
unsigned
unsigned
unsigned
strlen1 (char *str);
strlen2(char *str);
strlen3(char *str);
int main()
{
char s[100];
printf("bir yazý giriniz
gets(s);
printf("yazýnýn uzunluðu
printf("yazýnýn uzunluðu
printf("yazýnýn uzunluðu
: ");
: %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 deðiºkeni hem döngü deðiºkeni hem de sayaç olarak kullanýlmýºtýr.
null karakter '\0' sayýsal deðer olarak 0 deðerine eºit olduðu için yukarýdaki döngülerin koºul
ifadelerini aºaðýdaki ºekilde yazabilirdik:
while (*str)
for (i = 0; str[i]; ++i)
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
195
Buy RoboPDF
20 . BÖLÜM :
Yukarýdaki koºul ifadelerinde de *str ya da str[i] 0 deðerine eºit olduðunda kodun akýºý döngü
dýºýndaki ilk deyimle devam ederdi. Ancak okunabilirlik açýsýndan null karakterle
karºýlaºtýrmanýn açýkça yapýlmasý daha uygundur.
strchr fonksiyonu
Fonksiyonun ismi olan strchr "string character" sözcüklerinin kýsaltýlarak birleºtirilmesinden
elde edilmiºtir. strchr fonksiyonu bir karakter dizisi içinde belirli bir karakteri aramak için
kullanýlan standart bir C fonksiyonudur. Prototipi string.h dosyasý içinde bulunmaktadýr.
strchr fonksiyonunun prototipi aºaðýdaki gibidir:
char *strchr(char *str, int ch);
Bu fonksiyon, 2. parametresi olan ch karakterini, 1. parametresi olan str adresinden
baºlayarak null karakter görene kadar arar. (Aranan karakter null karakterin kendisi de
olabilir.) Fonksiyonun geri dönüº deðeri, ch karakterinin yazý içinde bulunabilmesi durumunda
ilk bulunduðu yerin adresidir. Eðer ch karakteri yazý içinde bulunamazsa, fonksiyon NULL
adresine geri dönecektir.
strchr fonksiyonunu kendimiz yazsaydýk aºaðýdaki ºekilde yazabilirdik:
#include <stdio.h>
#include <string.h>
int main()
{
char s[100];
char *p, ch;
printf("bir yazý giriniz : ");
gets(s);
printf("yazý içinde arayacaðýnýz 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;
}
Yukarýda verilen main fonksiyonununda strchr fonksiyonunu çaðýrdýðýmýz yerde kendi
yazdýðýmýz my_strchr fonksiyonunu çaðýrarak fonksiyonun doðru çalýºýp çalýºmadýðýný test
edebiliriz.
if (ch == '\0')
return str;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
196
Buy RoboPDF
GÖSTERÝCÝLER
deyimleri aranan karakterin null karakter olup olmadýðýný test etmek için eklenmiºtir. while
döngüsü yerine for döngüsü de kullanabilirdik;
...
int i;
for (i = 0; str[i] != '\0'; ++i)
if (ch == str[i])
return (str + i);
...
strcpy fonksiyonu
fonksiyonun ismi olan strcpy, string ve copy sözcüklerinin kýsaltýlarak birleºtirilmesinden elde
edilmiºtir.Fonksiyon ikinci parametresinde tutulan adresten baºlayarak, NULL karakter görene
kadar, (NULL karakter dahil olmak üzere) tüm karakterleri sýrasýyla birinci parametresinde
tutulan adresten baºlayarak sýrayla yazar. Fonksiyonun prototipi string.h dosyasý içindedir.
Fonksiyonun prototipi aºaðýdaki gibidir:
char *strcpy(char *dest, char *source);
Fonksiyonun geri dönüº deðeri kopyalamanýn yapýlmaya baºlandýðý adrestir. (Yani dest adresi)
#include <stdio.h>
#include <string.h>
int main()
{
char dest[100] = "C öðreniyoruz!";
char source[100];
printf("kopyalanacak yazýyý giriniz : ");
gets(source);
printf("kopyalama yapýlmadan önce kopyalamanýn yapacaðý yerde bulunan yazý :
\n");
puts(dest);
strcpy(dest, source);
printf("kopyalamadan sonra kopyalamanýn yapýldýðý yerde bulunan yazý : \n");
puts(dest);
return 0;
}
strcpy fonksiyonunu kendimiz yazmak isteseydik aºaðýdaki ºekilde yazabilirdik :
char *_strcpy(char *dest, char *source)
{
int i;
for (i = 0; (dest[i] = source[i]) != '\0'; ++i)
;
return dest;
}
fonksiyon içinde kullanýlan for döngüsünde önce atama yapýlmýº, daha sonra atama ifadesinin
deðeri (k, bu da atama operatörünün sað tarafýnda bulunan deðerdir) NULL karakter ile
karºýlaºtýrýlmýºtýr. Böylece ilgili adrese NULL karakter de kopyalandýktan sonra döngüden
çýkýlmýºtýr.
fonksiyonu aºaðýdaki gibi de yazabilirdik :
...
for (i = 0; source[i] != '\0'; ++i)
dest[i] = source[i];
dest[i] = '\0';
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
197
Buy RoboPDF
20 . BÖLÜM :
...
for döngüsünde indeks operatörü kullanýldýðý için, birinci parametre deðiºkenine kopyalanan
dest adresi deðiºtirilmemiº ve fonksiyonun sonunda bu dest adresi ile geri dönülmüºtür.
Fonksiyonun tasarýmýnda whilde döngüsü kullansaydýk, ve dest içindeki adresi deðiºtirseydik,
fonksiyonun dest göstericisinin ilk deðeriyle geri dönebilmesini saðlayabilmek için, dest
göstericisindeki deðeri deðiºtirmeden önce, bu deðeri baºka bir gösterici içinde saklamak
gerekecekti :
char *_strcpy(char *dest, char *source)
{
char *temp = dest;
while ((*source++ = *dest++) != '\0')
;
return temp;
}
Yazýlan fonksiyonlarýn doðru çalýºýp çalýºmadýklarýný ayný main fonksiyonu ile test edebiliriz.
strcat fonksiyonu
fonksiyonun ismi string ve concatanate sözcüklerinin kýsaltýlarak birleºtirilmesiyle elde
edilmiºtir.
strcat fonksiyonu bir karakter dizisinin sonuna baºka bir karakter dizisinin kopyalanmasý
amacýyla kullanýlmaktadýr. Fonksiyonun prototipi string.h dosyasý içindedir. Fonksiyonun
prototipi aºaðýdaki gibidir:
char *strcat(char *s1, char *s2);
strcat fonksiyonu eklemenin yapýlacaðý ve baºlangýç adresi s1 birinci parametre deðiºkeninde
tutulan yazýnýn sonundaki NULL karakteri ezerek, baºlangýç adresi ikinci parametre
deðiºkeninde tutulan yazýyý birinci yazýnýn sonuna (NULL karakter de dahil olmak üzere)
eklemektedir. Yani iºlem sonunda s1 dizisi s2 dizisi kadar büyümektedir.
Fonksiyonun geri dönüº deðeri, sonuna eklemenin yapýldýðý yazýnýn baºlangýç adresidir. (Yani
s1 adresi)
#include <stdio.h>
#include <string.h>
int main()
{
char s1[100], s2[100];
printf("sonuna ekleme yapýlacak yazýyý giriniz : ");
gets(s1);
printf("girdiðiniz yazýnýn uzunluðu = %d\n", strlen(s1));
printf("eklemek istediðiniz yazýyý giriniz : ");
gets(s2);
printf("eklenecek yazýnýn uzunluðu = %d\n", strlen(s2));
strcat(s1, s2);
printf("ekleme yapýldýktan sonra 1. yazý : ");
puts(s1);
printf("ekleme yapýldýktan sonra yazýnýn uzunluðu : %d\n", strlen(s1));
return 0;
}
strcat fonksiyonunu kendimiz yazsaydýk aºaðýdaki ºekilde yazabilirdik :
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
198
Buy RoboPDF
GÖSTERÝCÝLER
char *_strcat(char *s1, char *s2)
{
char *temp = s1;
while (*s1 != '\0')
++s1;
while ((*s1++ == *s2++) != '\0')
;
return temp;
/* strcpy(s1, s2); */
}
Yazýlan fonksiyonun doðru çalýºýp çalýºmadýðýný ayný main fonksiyonu ile test edebiliriz.
strset fonksiyonu
Standart olmayan bu fonksiyon derleyicilerin çoðunda bulunur. Fonksiyonun ismi string ve set
sözcüklerinin kýsaltýlarak birleºtirilmesinden elde edilmiºtir. Bir karakter dizisinin belirli bir
karakterle doldurulmasý amacýyla kullanýlmaktadýr. Prototipi string.h dosyasý içinde
bulunmaktadýr. Fonksiyonun prototipi aºaðýdaki gibidir :
char *strset(char *str, int ch);
Fonksiyon birinci parametre deðiºkeninde baºlangýç adresi olan yazýyý NULL karakter görene
kadar ikinci parametre deðiºkeninde tutulan karakterle doldurur. (yazýnýn sonundaki NULL
karaktere dokunmaz) .
Fonksiyonun geri dönüº deðeri yine doldurulan yazýnýn baºlangýç adresidir.
#include <stdio.h>
#include <conio.h>
int main()
{
char s[100];
int ch;
printf("bir yazý giriniz :");
gets(s);
printf("yazýyý hangi karakterle doldurmak istiyorsunuz : ");
ch = getchar();
printf("\nyazýnýn %c karakteriyle doldurulduktan sonraki hali : %s\n", ch,
strset(s, ch));
return 0;
}
strset fonksiyonunu kendimiz yazsaydýk aºaðýdaki º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;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
199
Buy RoboPDF
20 . BÖLÜM :
while (*str != '\0') {
*str = ch;
++str;
}
return temp;
}
strcmp fonksiyonu
Standart bir C fonksiyonudur. Fonksiyonun ismi string ve compare sözcüklerinin kýsaltýlarak
birleºtirilmesinden elde edilmiºtir. Fonksiyon iki karakter dizisini karºýlaºtýrmakta kullanýlýr.
Karºýlaºtýrma, iki karakter dizisi içindeki yazýnýn kullanýlan karakter seti tablosu gözönünde
bulundurularak, öncelilk ya da eºitlik durumunun sorgulanmasýdýr. Örneðin :
Adana yazýsý Ankara yazýsýndan daha küçüktür. Çünkü eºitliði bozan 'n' karakteri ASCII
tablosunda 'd' karakterinden sonra gelmektedir.
ankara yazýsý ANKARA yazýsýndan daha büyüktür. Çünkü küçük harfler ASCII tablosunda
büyük harflerden sonra gelmektedir.
kalem yazýsý kale yazýsýndan daha büyüktür.
strcmp fonksiyonunun string.h içerisindeki prototipi aºaðýdaki gibidir :
int strcmp(char *s1, char *s2);
fonksiyon 1. parametre deðiºkeninde baºlangýç adresi tutulan yazý ile, ikinci parametre
deðiºkeninde baºlangýç adresi tutulan yazýlarý karºýlaºtýrýr.
fonksiyonun geri dönüº deðeri
1. yazý 2.yazýdan daha büyükse pozitif bir deðere
1. yazý 2. yazýdan daha küçükse negatif bir deðere
1.yazý ve 2. yazý birbirine eºit ise 0 deðerine geri döner.
#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 doðru!..\n");
else
printf("Parola yanlýº!..\n");
return 0;
}
strcmp fonksiyonunu kendimiz yazsaydýk aºaðýdaki ºekillerde yazabilirdik :
int _strcmp(char *s1, char *s2)
{
while (*s1 == *s2) {
if (*s1 == '\0')
return 0;
++s1;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
200
Buy RoboPDF
GÖSTERÝCÝLER
++s2;
}
return *s1 - *s2;
}
strrev fonksiyonu
Standart olmayan bu fonksiyon derleyiclerin çoðunda bulunur. Fonksiyonun ismi ingilizce string
ve reverse söcüklerinin kýsaltýlarak birleºtirilmesinden elde edilmiºtir. Karakter dizilerini ters
çevirmek amacýyla kullanýlýr. string.h içerisinde yer alan prototipi aºaðýdaki gibidir :
char *strrev(char *str);
fonksiyon parametre deðiºkeninde baºlangýç adresi tutulan yazýyý tersyüz eder. Fonksiyonun
geri dönüº deðeri tersyüz edilen yazýnýn baºlangýç adresidir.
#include <stdio.h>
#include <string.h>
main()
{
char s[100];
printf("ters çevirilecek yazýyý giriniz : ");
gets(s);
printf("yazýnýzýn ters çevrilmiº hali : \n");
puts(setrev(s));
return 0;
}
strrev fonksiyonunu kendimiz yazsaydýk aºaðýdaki º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 sözcüklerinin
kýsaltýlarak birleºtirilmesinden elde edilmiºtir. Fonksiyon bir yazýnýn (karakter dizisinin) ilk n
karakterini baºka bir yazýya(karakter dizisine) kopyalamakta kullanýlýr. Fonksiyonun string.h
içerisindeki prototipi aºaðýdaki gibidir :
char *strncpy(char *dest, char *source, int n);
fonksiyon 1. parametre deðiºkeninde baºlangýç adresi tutulan yazýya, ikinci parametre
deðiºkeninde adresi tutulan yazýdan, üçüncü parametresinde tutulan sayýda karakteri kopyalar.
Fonksiyonun geri dönüº deðeri kopyalamanýn yapýlacaðý adrestir. (Yani dest adresi)
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
201
Buy RoboPDF
20 . BÖLÜM :
üçüncü parametre olan n sayýsý eðer kopyalanacak yazýnýn uzunluðundan daha küçük ya da
eºit ise fonksiyon kopyalama sonunda NULL karakteri birinci dizinin sonuna eklemez.
n <= strlen(source) ise NULL karakter eklenmiyor.
üçüncü parametre olan n sayýsý eðer kopyalanacak yazýnýn uzunluðundan daha büyük
fonksiyon kopyalama sonunda NULL karakteri birinci dizinin sonuna ekler.
ise
n > strlen(source) ise NULL karakter ekleniyor.
#include <stdio.h>
#include <string.h>
int main()
{
char dest[100], source[100];
int n;
printf("birinci yazýyý giriniz : ");
fflush(stdin);
gets(dest);
printf("ikinci yazýyý giriniz : ");
gets(source);
printf("ikinci yazýdan 1. yazýya kaç karakter kopyalamak istiyorsunuz : ");
scanf("%d", &n);
strncpy(dest, source, n);
printf("kopyalamadan sonra 1. yazýnýn yeni ºekli : ");
puts(dest);
return 0;
}
strncpy fonksiyonunu kendimiz yazsaydýk aºaðýdaki º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
sözcüklerinin kýsaltýlarak birleºtirilmesiyle elde edilmiºtir. Bir karakterden dizisinin sonuna
baºka bir karakter dizisinden belirli bir sayýda karakteri kopyalamak amacýyla kullanýlýr. string.h
içinde bulunan prototipi aºaðýdaki gibidir :
char *strncat(char *s1, char *s2, int n);
fonksiyon 1. parametre deðiºkeni içinde baºlangýç adresi verilen yazýnýn sonuna (NULL
karakteri ezerek), 2. parametresinde baºlangýç adresi tutulan karakter dizisinden, 3.
parametresinde tutulan tamsayý adedi kadar karakteri kopyalar.
fonksiyonun geri dönüº deðeri sonuna ekleme yapýlacak yazýnýn baºlangýç adresidir. (yani s1
adresi)
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
202
Buy RoboPDF
GÖSTERÝCÝLER
fonksiyonun çalýºmasýný açýklayacak bir örnek aºaðýda verilmiºtir :
#include <stdio.h>
#include <string.h>
int main()
{
char dest[100], source[100];
int n;
printf("birinci yazýyý giriniz : ");
fflush(stdin);
gets(dest);
printf("ikinci yazýyý giriniz : ");
gets(source);
printf("ikinci
yazýdan
1.
yazýnýn
sonuna
kaç
istiyorsunuz : ");
scanf("%d", &n);
strncat(dest, source, n);
printf("eklemeden sonra 1. yazýnýn yeni ºekli : ");
puts(dest);
return 0;
}
karakter
kopyalamak
strncmp fonksiyonu
Standart bir C fonksiyonudur. Fonksiyonun ismi ingilizce string number compare sözcüklerinin
kýsaltýlarak birleºtirilmesiyle elde edilmiºtir. strcmp fonksiyonuna benzer, ancak bu fonksiyon
iki yazýnýn tümünü deðil de, belirli bir sayýda karakterlerini karºýlaºtýrma amacýyla kullanýlýr.
fonksiyon 1. parametre deðiºkeninde baºlangýç adresi tutulan yazý ile, ikinci parametre
deðiºkeninde baºlangýç adresi tutulan yazýlarýn, üçüncü parametresinde tutulan sayýdaki
karakterlerini karºýlaºtýrýr.
fonksiyonun geri dönüº deðeri
1. yazýnýn n karakteri 2.yazýnýn n karakterinden daha büyükse pozitif bir deðere
1. yazýnýn n karakteri 2.yazýnýn n karakterinden daha küçükse negatif bir deðere
1.yazý ve 2. yazýnýn n kakateri birbirine eºit ise 0 deðerine geri döner.
/* büyük harf küçük harf duyarlýðý ile (case sensitive) bir yazý içinde baºka bir yazýyý arayan
mystrstr fonksiyonu. Fonksiyon aranan yazýyý aramanýn yapýlacaðý yazý içinde bulursa bulduðu
yazýnýn baºlangýç adresine, bulamazsa NULL adresine geri dönmektedir.
*/
#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("aramanýn yapýlacaðý yazýyý girin : ");
gets(s1);
printf("aranacak yazýyý girin :");
gets(s2);
ptr = mystrstr(s1, s2);
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
203
Buy RoboPDF
20 . BÖLÜM :
if (ptr)
puts(ptr);
else
puts("aradýðýnýz yazý bulunamadý\n");
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;
}
strupr ve strlwr fonksiyonlarý
Standart C fonksiyonlarý olmamalarýna karºýn hemen hemen her derleyicide bulunurlar.
Ýsimleri string upper ve string lower kelimelerinin kýsaltýlarak birleºtirilmesinden elde edilmiºtir.
Bu fonksiyonlarýn bir yazýnýn tüm karakterleri için büyük harf küçük harf dönüºtürmesi
yaparlar. Fonksiyonlarýn geri dönüº deðerleri parametresi ile verilen adresin aynýsýdýr. Geri
dönüº deðerlerine genellikle ihtiyaç duyulmaz. Her iki fonksiyon da ingiliz alfabesinde olan
harfler için dönüºüm yaparlar. Türkçe karakterler için de dönüºüm yapacak bir fonksiyon
kullanmak istiyorsak kendimiz yazmalýyýz.
#include <stdio.h>
#include <string.h>
int main()
{
char s[ ] = "C programcýsý olmak için çok çalýºmak gerekir!";
strupr(s);
puts(s);
return
0;
}
strupr ve strlwr fonksiyonlarýný kendimiz de aºaðýdaki º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;
}
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
*/
204
Buy RoboPDF
GÖSTERÝCÝLER
}
return temp;
char *_strlwr(char *str)
{
char *temp = str;
while (*str != '\0') {
if (isupper(*str))
/* if (*str >= 'A' && *str <= 'Z')
* str = tolower(*str);
/* *str = *str - 'A' + 'a'; */
++str;
}
return temp;
*/
}
strlwr ve strupr fonksiyonlarýnýn türkçe versiyonlarýný aºaðýdaki º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;
}
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
205
Buy RoboPDF
20 . BÖLÜM :
char türden bir göstericiyi NULL karaktere öteleme
Bir göstericiyi NULL karakteri gösterir hale getirmek için 3 yöntem kullanýlabilir :
char *p;
i.
p += strlen(p);
ii.
p = strchr(p, '\0');
iii.
while (*p != '\0')
++ptr;
Yukarýdakiler içinde en hýzlý çalýºabilecek kod üçüncüsüdür. 2. biçim tercih edilebilir ama 1.
yöntem pek tercih edilmez.
Aºaðýdaki döngüden çýktýktan sonra p göstericisi NULL karakterden bir sonraki adresi
göstermektedir :
while (*p++ != '\0')
;
GÖSTERÝCÝ HATALARI
Göstericileri kullanarak RAM üzerinde herhangi bir bölgeye eriºebiliriz. Bir programýn çalýºmasý
sýrasýnda bellekte çalýºýyor durumda olan baºka programlar da olabilir. Göstericileri kullanarak
o anda çalýºmakta olan programýn bellek alanýna veri aktarýlýrsa oradaki programýn kodu
bozulacaðý için programýn çalýºmasýnda çeºitli bozukluklar çýkabilecektir. Bu bozukluk tüm
sistemi olumsuz yönde etkileyebilir.
Kim tarafýndan kullanýldýðýný bilmediðimiz bellek bölgelerine güvenli olmayan bölgeler denir.
Güvenli olmayan bölgelere veri aktarýlmasýna da "gösterici hatalarý" denir.
Gösterici hatalarý yapýldýðýnda sistem kilitlenebilir, programlar yanlýº çalýºabilirler. Gösterici
hatalarý sonucundaki olumsuzluklar hemen ortaya çýkmayabilir.
Gösterici hatalarý güvenli olmayan bölgelere eriºildiðinde deðil oralara veri aktarýldýðýnda
oluºur.
Gösterici hatalarý derleme sýrasýnda derleyici tarafýndan tespit edilemezler. Programýn çalýºma
zamaný sýrasýnda olumsuzluklara yol açarlar. tanýmlama yöntemiyle tahsis edilmiº olan bellek
bölgelerine güvenli bölgeler denir. Bir nesne tanýmlandýðýnda, o nesne için derleyici tarafýndan
bellekte ayrýlan yer, programcý için ayrýlmýº bir alandýr ve güvenlidir.
gösterici hatasý oluºturan tipik durumlar
1) ilk deðer verilmemiº göstericilerin yol açtýðý hatalar :
daha önce belirtildiði gibi göstericiler de birer nesnedir. Diðer nesnelerden farklarý içlerinde
adres bilgileri tutmalarýdýr. Göstericiler de nesne olduklarýna göre diðer nesneler gibi yerel ya
da global olabilirler. Global olarak tanýmlanmýº göstericiler 0 deðeriyle baºlatýlýrken, yerel
göstericiler rasgele deðerlerle baºlatýlýrlar. (garbage value)
Yerel bir gösterici tanýmlandýktan sonra, herhangi bir ºekilde bu göstericiye bir deðer atamasý
yapýlmaz ise göstericinin içinde rasgele bir deðer bulunacaðýndan, bu gösterici *operatörü ile
ya da [ ] operatörü ile kullanýldýðýnda, bellekte rasgele bir yerde bulunan bir nesneye
ulaºýlacaktýr. Dolayýsýyla, elde edilen nesneye bir atama yapýldýðý zaman, bellekte, bilinmeyen
rasgele bir yere yazýlmýº olunur. Bu durum tipik bir gösterici hatasýdýr. Örnekler :
main()
{
int *p;
/* p göstericisinin içinde rasgele bir adres var */
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
206
Buy RoboPDF
GÖSTERÝCÝLER
}
*p = 25;
/* p göstericisinin içindeki adreste buluna nesneye 25 deðeri atanýyor */
Yukarýdaki örnekte rasgele bir yere (güvenli olmayan bir yere) veri aktarýlmaktadýr. Verinin
aktarýldýðý yerde iºletim sisteminin, derleyicinin ya da bellekte kalan baºka bir programýn
(memory resident) kodu bulunabilir. Verinin aktarýldýðý yerde programýn kendi kodu da
bulunabilir.
Ýlk deðer verilmemiº global göstericilerin içinde (ya da statik yerel göstericilerin içerisinde) sýfýr
deðeri bulunmaktadýr. Sýfýr sayýsý (NULL adresi) göstericilerde test amacýyla kullanýlmaktadýr.
Bu adrese bir veri aktarýlmasý durumunda , derleyicilerin çoðunda isteðe baðlý olarakbu hata
çalýºma zamaný (runtime) sýrasýnda kontrol edilmektedir. Örnek :
char *ptr;
main()
{
*p = 'm';
}
/* NULL pointer assignment */
Yukarýdaki kodun çalýºtýrýlmasýnda "NULL pointer assignment" ºeklinde bir çalýºma zamaný
hatasýyla karºýlaºýlabilir. Bu kontrol derleyicinin alýºabilen program içerisine yerleºtirdiði
"kontrol kodu" sayesinde yapýlmaktadýr.
Ýlk deðer verilmemiº göstericilerin neden olduðu hatalar fonksiyon çaðýrmalarýyla da ortaya
çýkabilir :
main()
{
char *ptr;
}
gets(ptr);
/* ????? */
Yukarýdaki kod parçasýnda gets fonksiyonu ile klavyeden alýnan karakterler, bellekte rasgele bir
yere yazýlacaktýr. gets fonksiyonu klavyeden alýnan karakterleri kendisine arguman olarak
gönderilen adresten baºlayarak yerleºtirdiðine göre, daha önceki örnekte verilen hata
klavyeden girilen bütün karakterler için söz konusudur.
2) Güvenli olmayan ilk deðerlerin neden olduðu gösterici hatalarý
Bir göstericiye ilk deðer verilmesi , o göstericinin güvenli bir bölgeyi gösterdiði anlamýna
gelmeyecektir. Örneðin :
char *ptr;
...
ptr = (char *) 0x1FC5;
*ptr = 'M';
Yukarýdaki örnekte ptr göstericisine atanan (char *) 0x1FC5 adresinin güvenli olup olmadýðý
konusunda hiçbir bilgi yoktur. Adrese iliºkin bölgenin kullanýp kullanýlmadýðý bilinemez. her ne
kadar bellek alaný içerisinde belli amaçlar için kullanýlan güvenli bölgeler varsa da 1FC5 böyle
bir bölgeyi göstermemektedir.
3) dizi taºmalarýndan doðan gösterici hatalarý
Bilindiði gibi bir dizi tanýmlamasý gördüðünde derleyici, derleme sýrasýnda dizi için bellekte
toplam dizi uzunluðu kadar yer ayýrýr. C'nin seviyesi ve felsefesi gereði dizi taºmalarý derleyici
tarafýndan tespit edilmemektedir.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
207
Buy RoboPDF
20 . BÖLÜM :
main()
{
int a[10], k;
}
for (k = 0; k <= 10; ++k)
a[k] = 0;
...
Yukarýdaki örnekte döngü k deðiºkeninin 10 deðeri için de sürecektir. Oysa a[10] elemaný için
bir tahsisat yapýlmamýºtýr. Dizinin son elemaný a[9] elemanýdýr. Derleyici a dizisi için a[0]'dan
baºlayarak a[9] elemaný için bellekte toplam 10 elemanlýk yani 20 byte'lýk bir yer tahsis
edecektir. Oysa tahsis edilmemiº olan a[10] bölgesinin kim tarafýndan ve ne amaçla kullanýldýðý
hakkýnda herhangi bir bilgi bulunmamaktadýr.
(Bu konuda standartlar tarafýndan bir zorunluluk bulunmamakla birlikte derleyicilerin çoðu,
ardýºýl olarak tanýmlanan elemanlarý bellekte ardýºýl olarak (contigious) olarak yerleºtirirler.
Ama bu garanti altýna alýnmýº bir özellik deðildir. Yani bunun garanti altýna alýndýðý düºünülerek
kod yazýlmasý problemlere yol açacaktýr. Yukarýdaki örnekte a[10] bölgesi derleyicilerin
çoðunda a dizisinden hemen sonra tanýmlanan ve döngü deðiºkeni olarak kullanýlan k
deðiºkenine ayrýlacaktýr. Dolayýsýyla a[10] elemanýna 0 deðerini vermekle aslýnda k deðiºkenine
0 deðeri verilecek ve bu da döngünün sonsuz bir döngüye dönüºmesine yol açabilecektir.)
Bilindiði gibi indeks operatörü de bir gösterici operatörüdür, bu operatörü kullanarak dizi için
tahsis edilen alanýn dýºýna atama yapýlabilir. C dili bu konuda bir kontrol mekanizmasý
getirmemektedir. Ayruca a dizisi için a[-1], a[-2].. gibi ifadelerin de sentaks açýsýndan
geçerlidir ve buraya yapýlacak atamalar da gösterici hatalarýna yol açacaktýr.
Bazan dizi taºmalarýna gizli bir biçimde fonksiyonlar da neden olabilirler. Örneðin :
char str[12];
...
printf("adý soyadý : ");
gets(str);
yukarýdaki kod parçasýnda str dizisi için toplam 12 karakterlik (12 byte) yer tahsis edilmiºtir.
gets fonksiyonu klavyeden alýnan karakterleri kendisine gönderilen adresten baºlayarak belleðe
yerleºtirdikten sonra, NULL karakteri de eklemektedir. O halde yukarýdaki örnekte programýn
çalýºmasý sýrasýnda 11 karakterden fazla giriº yapýlmasý gösterici hatasýna neden olacaktýr.
Sonlandýrýcý karakter olan NULL karakter de ('\0') bellekte bir yer kaplayacaðý için tahsis
edilmiº bir bölge içinde bulunmasý gerekir. Örneðin klavyeden girilen ad ve soyad :
Necati Ergin
olsun. gets fonksiyonu bu karakterleri aºaðýdaki gibi yerleºtirecektir :
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' sonlandýrýcý karakter güvenli olmayan bir yere
yazýlýyor.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
208
Buy RoboPDF
GÖSTERÝCÝLER
...
Görüldüðü gibi sonlandýrýcý karakter, dizi için tahsis edilen bölgenin dýºýna yerleºtirilmiºtir. Bu
örnekte girilen isim daha uzun olsaydý, tahsis edilmemiº bölgeye daha fazla karakter
yazýlacaktý. Bu tür hatalarla karºýlaºmamak için dizi yeteri kadar uzun olmalý ya da standart bir
C fonksiyonu olan gets fonksiyonu yerine, dizi uzunluðundan daha fazla sayýda eleman
yerleºtirilmesine izin vermeyecek özel bir giriº fonksiyonu yazýlmalý ve kullanýlmalýdýr.
stringlerle ilgili iºlemler yapan standart C fonksiyonlarýndan strcpy, strcat, strncpy, strncat
fonksiyonlarýnýn yanlýº kullanýlmasý da benzer hatalarý oluºturabilecektir. örneðin :
char s[10] = "Eskiºehir";
...
strcpy(s, "Kahramanmaraº");
strcat(s, "li");
strncpy(s, "Kahramanmaraº", 15)
strncat(s, "liyim", 5);
/* gösterici hatasý */
/* gösterici hatasý */
/* gösterici hatasý */
/* gösterici hatasý */
yukarýdaki fonksiyonlardan hepsi tahsis edilmeyen bir bölgeye yazma yaptýklarý için gösterici
hatasýna neden olacaktýr.
void Göstericiler
void göstericiler herhangi bir türden olmayan göstericilerdir. Bildirimlerinde void anahtar
sözcüðü kullanýlýr.
void *ptr;
void *str;
void göstericilerin tür bilgisi yoktur. void göstericilerde adreslerin yalnýzca sayýsal bileºenleri
saklanýr. Bu yüzden void göstericilerle diðer türden göstericler (adresler) arasýnda yapýlan
atamalarda uyarý söz konusu deðildir. void göstericileri kullanýrken tür dönüºtürme
operatörünü kullanmaya gerek yoktur.
char *str;
void *p;
....
str = p;
/* herhangi bir uyarý mesajý alýnmaz */
p = str;
/* herhangi bir uyarý mesajý alýnmaz */
Benzer biçimde fonksiyon çaðýrma ifadelerinden argumanlarýn fonksiyon parametre
deðiºkenlerine kopyalanmasýnda da, void göstericiler söz konusu olduðunda, adres türlerinin
farklýlýðýndan dolayý uyarý mesajý alýnmaz.
funk1(void *p)
{
...
}
main()
{
int *ptr;
...
funk1(ptr);
}
/* p = ptr gibi bir atama iºlemi yapýlmaktadýr. Uyarý mesajý alýnmaz. */
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
209
Buy RoboPDF
20 . BÖLÜM :
funk2(int * p)
{
...
}
int main()
{
void *ptr;
...
funk2(ptr);
}
/* p = ptr gibi bir atama iºlemi yapýlmaktadýr. Uyarý mesajý alýnmaz. */
void göstericiler belirli bir türe ait olmadýklarý için, tür bilgisine sahip olan göstericiler üzerinde
uygulanan bazý iºlemler void türden göstericilere uygulanamazlar:
1. void türden göstericilerin * ya da [ ] operatörleriyle kullanýlmalarý derleme zamanýnda error
oluºturacaktýr. Çünkü bu operatörler nesneye eriºmek için tür bilgisine ihtiyaç duyarlar.
long l[50];
void *vptr;
vptr = l;
...
*p = 10L;
...
p[2] = 25L;
/* normal bir iºlem. void türden göstericiye long türden bir adres atanýyor. */
/* hata! void gösterici * operatörüyle kullanýlamaz. */
/* hata! void gösterici [ ] operatörüyle kullanýlamaz. */
2. void türden bir göstericiden bir tamsayýnýn toplanmasý, ya da void türden bir göstericiden bir
tamsayýnýn çýkartýlmasý derleme zamanýnda hata oluºturur. Çünkü pointer aritmetiðine göre bir
göstericiyi n kadar artýrdýðýmýzda, gösterici içindeki adresin sayýsal bileºeni n * göstericinin
türünü uzunluðu kadar artar. void göstericilerin türleri olmadýðý için bu durumda sayýsal
bileºenin ne kadar artacaðý da bilinemez.
void türden göstericiler ++ ve -- operatörlerine operand olamazlar.
++ptr;
ifadesi
ptr = ptr +1;
ifadesine eºdeðerdir.
int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
void *ptr = &k;
void *p;
p = ptr + 2; /* error! void türden bir göstericiye bir tamsayý toplanýyor! */
++ptr;
/*error ! */
--ptr;
/* error! */
ptr += 2;
/*error */
ptr -= 3;
/* error */
3. Benzer ºekilde, void türden iki adres birbirinden çýkartýlamaz. (Diðer türden adresler için,
ayný türden iki adresin birbirinden çýkartýlmasýnýn tamamen legal oldugunu ve ifadenin
deðerinin pointer aritmetiðine göre bir tamsayý oldugunu hatýrlayalým!)
void *p1, *p2;
int k;
...
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
210
Buy RoboPDF
GÖSTERÝCÝLER
k = p1 - p2;
/* error! void türden adresler birbirinden çýkarýlamaz! */
void göstericiler adreslerin sayýsal bileºenlerini geçici olarak saklamak amacýyla kullanýlýrlar.
Diðer tür göstericiler arasýndaki atama iºlemlerinde uyarý ya da hata oluºturmadýklarýndan
dolayý, türden baðýmsýz adres iºlemlerinin yapýldýðý fonksiyonlarda parametre deðiºkeni
biçiminde de bulunabilirler. Örneðin:
void sample(void *p)
{
...
}
sample isimli fonksiyonun parametre deðiºkeni void türden bir gösterici olduðundan bu
fonksiyona arguman olarak herhangi türden bir adres bilgisi gönderilebilir. Yani sample
fonksiyonu herhangi türden bir adres ile çaðýrýlabilir. Bu durumda derleme zamanýnda bir hata
oluºmadýðý gibi bir uyarý mesajý da alýnmaz.
C dilinde fonksiyonlar void türden adreslere de geri dönebilirler. Void türden adresler derleme
zamanýnda bir hata oluºmaksýzýn, ve bir uyarý mesajý alýnmadan herhangi türden bir göstericiye
atanabildiði için, bu fonksiyonlarýn geri dönüº deðerleri herhangi türden bir göstericiye
atanabilir:
main()
{
int *p;
char * str;
p = sample();
...
str = sample();
/* hata oluºmaz ve uyarý mesajý alýnmaz. */
/* hata oluºmaz ve uyarý mesajý alýnmaz. */
}
void *sample();
{
...
}
void göstericilere iliºkin uygulamalar
void göstericilerin kullanýmýný en iyi açýklayan örnek memcpy fonksiyonudur. memcpy
fonksiyonu 2. parametresiyle belirtilen adresten baºlayarak n sayýda byte’ý birinci
parametresiyle belirtilen adresten baºlayarak kopyalar. Fonksiyonun NULL karakterle ya da
yazýlarla bir iliºkisi yoktur, koºulsuz bir kopyalama yapar. Yani bir blok kopyalamasý söz
konusudur.
Uygulamada en fazla, ayný türden herhangi iki dizinin kopyalanmasý amacýyla kullanýlýr.
Fonksiyonun prototipi string.h baºlýk dosyasý içindedir.
Ö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];
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
211
Buy RoboPDF
20 . BÖLÜM :
int i;
memcpy(b, a, 2 * SIZE);
for (i = 0; i < SIZE; ++i)
printf(“%d\n”, b[i]);
}
aºaðýdaki fonksiyon çaðýrýºý da eºdeðerdir.
char s[50] = “Ali”;
char d[50];
strcpy(d, s);
memcpy(d, s, strlen(s) + 1);
memcpy fonksiyonunun gösterici olan parametreleri void türdendir. Çünkü hangi türden adres
geçirilirse geçirilsin, derleyicilerden herhangi bir uyarý mesajý alýnmaz.
void memcpy(void *dest, void *source, int n);
ancak memcpy fonksiyonunun çakýºýk bloklarýn kopyalanmasýnda davranýºý standart deðildir.
Çakýºýk bloklarýn kopyalanmasýnda ayrý prototipe sahip olan memmove fonksiyonu tercih
edilmelidir. Özellikle dizi elemanlarýnýn kaydýrýlmasý gibi uygulamalarda çakýºýk bloklarýn
kopyalanmasý söz konusu olabilir. Bu durumda memmove fonksiyonu tercih edilmelidir.
Standart C’de baºý mem ile baºlayan mem.... biçiminde bir grup fonksiyon vardýr. Bu
fonksiyonlar türden baðýmsýz olarak byte sayýsý ile iºlem yaparlar.
memset fonksiyonu
prototipi :
memset(void *p, char ch, int n);
Bu fonksiyon 1. parametresiyle belirtilen adresten baºlayarak n tane byte'ý , 2. parametresiyle
belirtilen bilgiyle doldurulur. Bu fonksiyon herhangi türden bir diziyi sýfýrlamak amacýyla
kullanýlabilir. Örneðin :
double d[100];
memset(d, 0, sizeof(d));
void gösterici parametresine sahip olan fonksiyonlarýn yazýlmasý :
Böyle bir fonksiyon yazýlýrken parametre deðiºkeni olan void gösterici önce türü belirli bir
göstericiye atanýr, daha sonra iºlemler bu göstericiyle gerçekleºtirilir.
Ö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 :
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
212
Buy RoboPDF
GÖSTERÝCÝLER
void *mymemcpy (void *dest, void *source, int n)
{
char *-dest = (char *) dest;
char *_source = (char *) source;
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 yazýlmasý
#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;
}
Göstericilerle Ýlgili Örnek Uygulamalar
Uygulama 1 : long türden bir sayýyý verilen bir adrese virgüllerle ayýrarak string olarak yazan longtoa
fonksiyonunun yazýlmasý. Fonksiyon gönderilen adrese geri dönecektir.
#include <stdio.h>
#include <string.h>
#define NEGATIVE
#define POSITIVE
(-1)
1
char *longtoa(long val, char *str)
{
int i, sign;
char digit;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
213
Buy RoboPDF
20 . BÖLÜM :
if (val < 0) {
sign = NEGATIVE;
val = -val;
}
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: büyük harf küçük harf duyarlýðý ile (case sensitive) bir yazý içinde baºka bir yazýyý arayan
mystrstr fonksiyonu. Fonksiyon aranan yazýyý aramanýn yapýlacaðý yazý içinde bulursa bulduðu yazýnýn
baºlangýç adresine, bulamazsa NULL adresine geri dönmektedir.
#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("aramanýn yapýlacaðý yazýyý girin : ");
gets(s1);
printf("aranacak yazýyý girin :");
gets(s2);
ptr = mystrstr(s1, s2);
if (ptr)
puts(ptr);
else
puts("aradýðýnýz yazý bulunamadý\n");
getch();
}
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
214
Buy RoboPDF
GÖSTERÝCÝLER
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;
}
Uygulama 3: klavyeden girilen bir yazý içerisindeki türkçe karakterlerin
sayýsýný 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 GÝRÝNÝZ : ");
gets(s);
printf("\ntürkçe karakter sayýsý = %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: Büyük harf küçük harf duyarlýðý olmadan iki stringi karºýlaºtýran 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;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
215
Buy RoboPDF
20 . BÖLÜM :
int n = 10;
while (n-- > 0) {
clrscr();
printf("1. yazýyý girin : ");
gets(s1);
printf("2. yazýyý 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 baºlangýç adresi gönderilen bir yazýnýn içindeki boºluklarý atan rem_space
fonksiyonu. Fonksiyon kendisine gönderilen adrese geri dönecektir.
#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;
}
göstericilerle ilgili örnek uygulamalar
/*
mystrstr.c
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
216
Buy RoboPDF
GÖSTERÝCÝLER
büyük harf küçük harf duyarlýðý ile (case sensitive) bir yazý içinde baºka bir yazýyý arayan mystrstr
fonksiyonu. Fonksiyon aranan yazýyý aramanýn yapýlacaðý yazý içinde bulursa bulduðu yazýnýn baºlangýç
adresine, bulamazsa NULL adresine geri dönmektedir.
*/
#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("aramanýn yapýlacaðý yazýyý girin : ");
gets(s1);
printf("aranacak yazýyý girin :");
gets(s2);
ptr = mystrstr(s1, s2);
if (ptr)
puts(ptr);
else
puts("aradýðýnýz yazý bulunamadýn");
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ý içerisindeki türkçe karakterlerin
sayýsýný 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 GÝRÝNÝZ : ");
gets(s);
printf("ntürkçe karakter sayýsý = %d", gettrknum(s));
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
217
Buy RoboPDF
20 . BÖLÜM :
return 0;
}
int gettrknum(const char *str)
{
int counter = 0;
int i;
char trk[ ] = "çðýöºüÇÐÝÖªÜ";
for (i = 0; str[i] != '_; ++i)
if (strchr(trk, str[i]))
++counter;
return counter;
}
/*
stricmp.c
Büyük harf küçük harf duyarlýðý olmadan iki stringi karºýlaºtýran
bir fonksiyonun tasarýmý 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. yazýyý girin : ");
gets(s1);
printf("2. yazýyý 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 yazýdaki kelime sayýsýný bulan
int no_of_words(char *str);
fonksiyonunun tasarlanmasý
*/
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
218
Buy RoboPDF
GÖSTERÝCÝLER
#include <stdio.h>
#include <ctype.h>
#define
#define
#define
OUT
IN
MAX_LEN
0
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("yazýnýzda %d sözcük var!.\n", wcount(s));
return 0;
}
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
219
Buy RoboPDF
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
Buy RoboPDF
STRINGLER
21 . BÖLÜM : STRINGLER
C programa dilinde iki týrnak içerisindeki ifadelere string ifadeleri ya da kýsaca stringler denir.
Örneðin:
"Kaan Aslan"
"x = %d\n"
"lütfen bir sayý giriniz : "
ifadelerinin hepsi birer stringdir.
Stringlerin tek bir atom olarak ele alýndýðýný önceki derslerden hatýrlýyoruz. C'de stringler
aslýnda char türden bir adres olarak ele alýnmaktadýr. C derleyicileri, derleme aºamasýnda bir
stringle karºýlaºtýðýnda, önce bu stringi belleðin güvenli bir bölgesine yerleºtirir, sonuna NULL
karakteri ekler ve daha sonra string yerine yerleºtirildiði yerin baºlangýç adresini koyar. Bu
durumda string ifadeleri aslýnda stringlerin bellekteki baºlangýç yerini gösteren char türden
birer adrestir. Örneðin:
char *p;
...
p = "Nuri Yýlmaz";
gibi bir kodun derlenmesi sýrasýnda, derleyici önce "Nuri Yýlmaz" stringini belleðin güvenli bir
bölgesine yerleºtirir; daha sonra yerleºtirdiði yerin baºlangýç adresini string ifadesi ile
deðiºtirir.
Stringler char türden bir adres olarak ele alýndýðýna göre char türden göstericilere
atanmalarýnda error ya da uyarý gerektiren bir durum söz konusu deðildir.
Stringlerin Fonksiyonlara Arguman Olarak Gönderilmesi
Parametre deðiºkeni char türden bir gösterici olan fonksiyonu char türden bir adres ile
çaðýrmak gerektiðini biliyoruz. Çünkü doðal olarak char türden bir göstericiye char türden bir
adres atanmalýdýr.
Derleyiciler açýsýndan stringler de char türden bir adres belirttiklerine göre, parametre
deðiºkeni char türden gösterici olan bir fonksiyonu bir string ile çaðýrmak son derece doðal bir
durumdur, ve C dilinde bu yapý çok kullanýlýr:
puts("Necati Ergin");
Burada derleyici "Necati Ergin" stringini belleðe yerleºtirip sonuna NULL karakteri koyduktan
sonra artýk bu stringi, karakterlerini yerleºtirdiði bellek bloðunun baºlangýç adresi olarak
görecektir. puts fonksiyonunun parametre deðiºkenine
de artýk char türden bir adres
kopyalanacaktýr. puts fonksiyonu parametre deðiºkeninde tutulan adresten baºlayarak NULL
karakteri görene kadar tüm karakterleri ekrana yazmaktadýr. Bu durumda ekranda
Merhaba
yazýsý çýkacaktýr. Baºka bir örnek:
char str[20];
...
strcpy(str, "Kaan Aslan");
Bu örnekte de "Kaan Aslan" stringi str adresinden baºlayarak kopyalanmaktadýr. String
ifadelerinin bulunduðu yerde char türden bir adresin bulunduðu düºünülmelidir. ªimdi
aºaðýdaki ifadeyi yorumlayalým:
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
221
Buy RoboPDF
21 . BÖLÜM :
strcpy("Ali", "Kaan");
Derleyici derleme aºamasýnda iki stringi de bellekte güvenli bir bölgeye yerleºtirir. Çalýºma
zamaný sýrasýnda strcpy fonksiyonu "Ali" stringini gösteren adresten baºlayarak "Kaan" stringini
gösteren adrese NULL karakter görene kadar kopyalama yapacaðýna göre, bu ifadenin faydalý
hiçbir anlamý olmayacaktýr. Üstelik bu ifade, ikinci string birinciden uzun olduðu için bir
gösterici hatasýna da neden olur. ªimdi aºaðýdaki ifadeyi inceleyelim:
p = "Kaan" + "Necati";
Yukarýdaki örnekte aslýnda "Kaan" stringinin baºlangýç adresi ile "Necati" stringinin baºlangýç
adresi toplanmaktadýr. Peki bu toplamýn yararlý bir sonucu olabilir mi? Derleyiciler
anlamsýzlýðýndan dolayý iki adresin toplanmasýna izin vermezler. Fakat bir göstericiden baºka
bir göstericinin deðerini çýkarmanýn yararlý gerekçeleri olabilir. Bu yüzden göstericilerin
birbirinden çýkartýlmasý derleyicilerin hepsinde geçerli bir iºlemdir. Gösterici aritmetiðine göre
bir adresten ayný türden bir baºka bir adres çýkartýldýðý zaman elde edilen sonuç bir tamsayýdýr,
ve bu sayý iki adresin sayýsal bileºenlerinin farký deðerinin adresin tür uzunluðuna bölünmesiyle
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;
Yukarýdaki programýn çalýºtýrýlmasýyla ekrana:
fark1 = 8
fark2 = 2
yazýlacaktýr.
C derleyicileri kaynak kodun çeºitli yerlerinde tamamen özdeº stringlere rastlasa bile bunlar
için farklý yerler ayýrabilirler. Derleyici özdeº stringlerin sadece bir kopyasýný da bellekte
saklayabilir. Özdeº stringlerin nasýl saklanacaðý bazý derleyicilerde programcýnýn seçimine
býrakýlmýºtýr. Derleyicinin ayarlarý arasýnda bu konuyla ilgili bir seçenek bulunur.
Örneðin bir programýn içerisinde:
printf("Dosya açýlamýyor!..\n");
...
printf("Dosya açýlamýyor!..\n");
...
printf("Dosya açýlamýyor!..\n");
ifadelerinin bulunduðunu varsayalým. Farklý yerlerde "Dosya açýlamýyor!..\n" gibi özdeº stringler
bulunsa bile derleyici bunlar için tekrar ve farklý yerler ayýrabilir. Bu da büyük uygulamalar için
belleðin verimsiz kullanýlmasýna yol açabilir.
Bellekte yer ayýrma iºlemi derleme aºamasýnda yapýlmaktadýr. Aºaðýdaki kod parçasýnýn
çalýºtýrýlmasýyla ekrana hep ayný adres basýlacaktýr :
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
222
Buy RoboPDF
STRINGLER
char *p;
int k;
...
for (k = 0; k < 10; ++k) {
p = "Necati Ergin";
printf("%p\n", p);
}
...
Eðer yer ayýrma iºlemi çalýºma zamaný sýrasýnda yapýlsaydý, o zaman farklý adresler
basýlabilirdi.
Stringlerin doðrudan karºýlaºtýrýlmasý yanlýº bir iºlemdir.
...
if (“Ankara” == “Ankara”)
printf(“dogru\n”);
else
printf(“yanlýº”\n”);
...
Yukarýdaki kodun çalýºtýrýlmasý durumunda büyük bir olasýlýkla ekrana “yanlýº” yazdýrýlacaktýr.
Çünkü derleyicinin if parantezi içindeki karºýlaºtýrma ifadesindeki iki “Ankara” stringinin
bellekte ayrý yerlere yerleºtirilmesi durumunda, bu iki string birbirinden farklý iki ayrý char
türden adres olarak deðerlendirilir. Benzer bir yanlýºlýk aºaðýdaki kod parçasýnda da yapýlmýºtýr.
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 tarafýndan dizinin yerleºtirildiði bloðun baºlangýcý olan char türden
bir adres sabiti gibi ele alýnýr. str ise char türden bir göstericidir. str göstericisine “Mavi ay”
stringi atandýðýnda, derleyici önce “Mavi ay” stringini bellekte güvenli bir yere yerleºtirir daha
sonra stringin yerleºtirildiði yerin baºlangýç adresini str göstericisine atar. programý kullananýn
parola olarak “Mavi ay” girdiðini varsayalým. Bu durumda if deyimi içinde yalnýzca s adresiyle
str göstericisinin içindeki adresin eºit olup olmadýðý kontrol edilmektedir. Bu adresler de eºit
olmadýklarý için ekrana "yanlýº parola" yazýlacaktýr. Ýki yazýnýn birbirine eºit 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”);
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
223
Buy RoboPDF
21 . BÖLÜM :
Stringlerin Ömürleri
Stringler statik ömürlü nesnelerdir. Týpký global deðiºkenler gibi programýn yüklenmesiyle
bellekte yer kaplamaya baºlarlar, programýn sonuna kadar bellekte kalýrlar. Dolayýsýyla
stringler çalýºabilen kodu büyütür. Birçok sistemde statik verilerin toplam uzunluðunda belli bir
sýnýrlama söz konusudur.
Stringler derleyici tarafýndan .obj modüle linker tarafýndan da .exe dosyasýna yazýlýrlar.
Programýn yüklenmesiyle hayat kazanýrlar.
Bir exe program 3 bölümden oluºmaktadýr:
kod
data
stack
Kod bölümünde, fonksiyonlarýn makine kodlarý vardýr. Data bölümünde, statik ömürlü nesneler
bulunmaktadýr, global deðiºkenler ve stringler bu bölümde bulunurlar. Stack bölümü yerel
deðiºkenlerin saklandýðý bellek alanýdýr. Stack bölümü her sistemde sýnýrlý bir alandýr. Örneðin
DOS iºletim sisteminde 64K büyüklüðünde bir stack söz konusudur. Yani hiç bir zaman yerel
deðiºkenlerin bellekte kapladýðý alan 64K deðerini geçemez. WINDOWS iºletim sisteminde
default stack sýnýrý 1 MB’dýr. Ancak bu sýnýr istenildiði kadar büyütülebilir.
Daha önceki derslerimizde, bir fonksiyonun yerel bir deðiºkenin adresi ile geri dönmemesi
gerektiðini söylemiºtik. Çünkü fonksiyon sonlandýðýnda yerel deðiºkenler bellekten boºaltýlacaðý
için, fonksiyonun geri döndürdüðü adres güvenli bir adres olmayacaktýr. Örneðin aºaðýdaki
program hatalýdýr:
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 dönebilir, bu durumda bir yanlýºlýk söz konusu
olmayacaktýr. Çünkü stringler programýn çalýºma süresi boyunca bellektedir. Örneðin aºaðýdaki
programda hatasýz olarak çalýºýr:
char *getday(int day)
{
char *ptr;
switch (day) {
case 0: p =
case 1: p =
case 2: p =
case 3: p =
case 4: p =
“Sunday”; break;
“Monday”; break;
“Tuesday”; break;
“Wednesday”; break;
“Thursday”; break;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
224
Buy RoboPDF
STRINGLER
case 5: p = “Friday”; break;
case 6: p = “Saturday”;
}
}
return p;
Stringlerin Birleºtirilmesi
Daha önce söylendiði gibi stringler tek bir atom olarak ele alýnmaktadýr. Bir string aºaðýdaki
gibi parçalanamaz:
char *ptr;
...
ptr = "Necati Ergin'in C Dersi
Notlarýný okuyorsunuz";
/* error */
Ancak string ifadeleri büyüdükçe bunu tek bir satýrda yazmak zorlaºabilir. Ekrandaki bir satýrlýk
görüntüye sýðmayan satýrlar kaynak kodun okunabilirlirliðini bozar. Uzun stringlerin
parçalanmasýna olanak vermek amacýyla C derleyicileri yanyana yazýlan string ifadelerini
birleºtirirler. Örneðin:
ptr = "Necati Ergin'in C Dersi"
"Notlarýný okuyorsunuz";
geçerli bir ifadedir. Bu durumda iki string birleºtirilerecek ve aºaðýdaki biçime getirilecektir.
ptr = "Necati Ergin'in C Dersi Notlarýný okuyorsunuz";
Derleyicinin iki stringi birleºtirmesi için, stringlerin arasýnda hiçbir operatörün bulunmamasý
gerekmektedir. :
p = "Necati " "Ergin";
ifadesi ile
p = "Necati Ergin";
ifadesi eºdeðerdir.
Birleºtirmenin yaný sýra, bir ters bölü karakteri ile sonlandýrýlarak sonraki satýra geçiº
saðlanabilir. Örneðin:
ptr = "Necati Ergin'in C Dersi \
Notlarýný okuyorsunuz";
ifadesi ile
ptr = "Necati Ergin'in C Dersi Notlarýný okuyorsunuz";
ifadesi eºdeðerdir. Tersbölü iºaretinden sonra string aºaðýdaki satýrýn baºýndan itibaren devam
etmelidir. Söz konusu string aºaðýdaki ºekilde yazýlýrsa:
ptr = "Necati Ergin'in C Dersi \
Notlarýný okuyorsunuz";
satýr baºýndaki boºluk karakterleride stringe katýlýr ve sonuç aºaðýdaki ifadeye eºdeðer olur:
ptr = "Necati Ergin'in C Dersi
Notlarýný okuyorsunuz";
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
225
Buy RoboPDF
21 . BÖLÜM :
Ancak ters bölü karakteri ile sonraki satýrýn baºýndan devam etme standart olarak her C
derleyicisinde geçerli olmayabilir. Çatýºmalý bir durumla karºýlaºtýðýnýzda çalýºtýðýnýz
derleyicilerin referans kitaplarýna baºvurmalýsýnýz.
Stringlerde Ters Bölü Karakter Sabitlerinin Kullanýlmasý
Stringler içerisinde ters bölü karakter sabitleri de (escape sequence) kullanýlabilir. Derleyiciler
stringler içerisinde bir ters bölü karakteri gördüklerinde, onu yanýndaki karakter ile birlikte tek
bir karakter olarak ele alýrlar. Örneðin:
char *p;
p = "Necati\tErgin";
ifadesinde \t bir karakterdir. (9 numaralý ASCII carakteri olan tab karakteri)
yani
printf("stringdeki karakter sayýsý = %d\n", strlen(p));
ifadesi ile ekrana
stringdeki karakter sayýsý = 12
yazdýrýlacaktýr.
String ifadelerinde doðrudan çift týrnak ya da ters bölü karakterleri kullanýlamaz, çünkü bu
karakterlerin özek iºlevi var. Çift týrnak karakter sabitinin kendisini ifade etmek için çift tirnak
karakterinden önce bir ters bölü karakteri kullanýlýr. Örneðin:
p = "\"Necati Ergin\"";
gibi bir string ifadesi geçerlidir. Bu durumda
puts(p);
ile ekrana
"Necati Ergin"
yazýsý basýlacaktýr.
Stringlerle Göstericilere Ýlkdeðer Verilmesi
Stringler kullanýlarak char türden göstericilere ilkdeðer verilebilir. Örneðin:
char *p = "Ýstanbul";
char *err = "Bellek yetersiz";
char *s = "Devam etmek için bir tuºa basýnýz";
...
String ifadeleri aslýnda char türden bir adres olduðuna göre ilk deðer verilen göstericilerin de
char türden göstericiler olmasý gerekir. Dizilere iki týrnak içerisinde ilk deðer vermeyle
göstericilere stringlerle ilk deðer verme arasýndaki ayýrýma dikkat etmek gerekir.
char *p = "Deneme";
char s[10] = "Deneme";
ifadeleri tamamen farklýdýr.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
226
Buy RoboPDF
STRINGLER
Göstericilere ilkdeðer verildiðinde derleyici bunu bir string ifadesi olarak ele almaktadýr. Yani
string belleðe yerleºtirildikten sonra baºlangýç adresi göstericiye atanýr. Oysa dizilerde önce dizi
için yer ayrýlýr, daha sonra karakterler tek tek dizi elemanlarýna yerleºtirilir. Dizilere ilkdeðer
verirken kullandýðýmýz iki týrnak ifadeleri adres belirtmezler (string deðildireler). Dizi
elemanlarýna tek tek char türden sabitlerle ilk deðer verme iºlemi zahmetli olduðu için,
programcýnýn iºini kolaylaºtýrmak amacý ile dile bu ilk deðer verme sentaksý eklenmiºtir.
Yani
char s[10] = "Deneme";
aslýnda
char s[10] = {'D', 'e', 'n', 'e', 'm', 'e', '\0'};
ile ayný anlamdadýr.
Ýcinde Yazý Tutan char Türden Dizilerle Bir Stringi Gösteren char Türden
Göstericilerin Karºýlaºtýrýlmasý
ªimdiye kadar almýº olduðumuz bilgileri deðerlendirdiðimizde, C dilinde bir yazýyý saklamak iki
ayrý ºekilde saðlanabilir:
1. Yazýyý char türden bir dizi içinde saklamak:
...
char s1[100] = “Necati Ergin”;
char s2[100];
char s3[100];
gets(s2);
strcpy(s2, s3);
/ * Diziye yazýnýn karakterleri klavyeden alýnýyor */
/* s3 dizisinin elemanlarý s2 dizisi içine kopyalanýyor */
2. Yazýyý bir string olarak saklayarak char türden bir göstericinin bu stringi göstermesini
saðlamak .
char *str = “Necati Ergin”;
Ýki yöntem birbirinin tamamen alternatifi deðildir ve aºaðýdaki noktalara dikkat edilmesi
gerekmektedir:
stringler statik nesneler olduklarý için programýn sonlanmasýna kadar bellekte yer kaplarlar.
Yani bir göstericinin bir stringi gösterirken daha sonra baºka bir stringi gösterir duruma
getirilmesi , daha önceki stringin bellekten silinmesi anlamýna gelmeyecektir.
char *s = “Bu string programýn sonuna kadar bellekte kalacak.”;
s = “artýk yukarýdaki string ile bir baðlantýmýz kalmayacak...”;
Yazýnýn char türden bir dizi içinde tutulmasý durumunda bu yazýyý deðiºtirmemiz mümkündür.
Dizi elemanlarýna yeniden atamalar yaparak yazýyý istediðimiz gibi deðiºtirebiliriz ama
stringlerin deðiºtirilmesi taºýnabilir bir özellik deðildir. Stringler içinde bulunan yazýlar
deðiºtirilmemelidir. Aºaðýdaki kod parçalarý taºýnabilir deðildir:
char *s = “Metin”;
char *str = “Ankara”;
s[1] = ‘Ç’;
strcpy(str, “Bolu”);
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
227
Buy RoboPDF
21 . BÖLÜM :
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
söylediðimiz gibi derleyiciler bu konuda birbirinden farklý davranabilirler. Yani yukarýdaki
örneklerde biz “Metin” ya da “Ankara” stringini deðiºtirdiðimizde, bu stringleri program içinde
baska yerlerde de kullanmýºsak, bunlarýn hepsinin deðiºtirilmiº olmasý gibi bir tehlike söz
konusudur.
char *s = "dosya açýlamýyor"; /* birinci string */
char a[] = "dosya açýlamýyor";
...
printf("%s", s);
...
printf("dosya açýlamýyor");
...
strcpy(s, "Dosya Açýldý");
...
/* ikinci string */
"dosya açýlamýyor" stringinin derleyici tarafýndan ayný adreste tek kopya olarak saklandýðýný
farsayalým. s adresinde bulunan stringe yeni bir yazý kopyalanýnca hem birinci string hemde
ikinci string deðiºmiº olur.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
228
Buy RoboPDF
GÖSTERÝCÝ DÝZÝLERÝ
22 . BÖLÜM : GÖSTERÝCÝ DÝZÝLERÝ
Göstericiler de birer nesne olduguna göre gösterici dizileri de tanýmlanabilmelidir.
Elemanlarý göstericilerden oluºan dizilere “gösterici dizileri” (pointer arrays) denir. Bildirimleri aºaðýdaki
ºekilde yapýlýr :
<tür> *<dizi ismi [dizi_uzunluðu];>
Örneðin :
char *s[10];
int *sample[50];
float *kilo[10];
Gösterici dizilerinin bildirimleri normal dizi bildirimlerinden farklý olarak * operatörü ile yapýlmaktadýr. Örneðin:
char str[100];
bildiriminde, str 100 elemanlý char türden bir diziyken
char *str[100];
bildiriminde ise, str 100 elemanlý char türden bir gösterici dizisidir.
Derleyici bir gösterici dizisi tanýmlamasý ile karºýlaºýnca diðer dizilerde yaptýðý gibi, bellekte belirtilen sayýda
gösteriyi tutabilecek kadar ardýºýl yer tahsis eder. Örneðin:
char *p[10];
bildirimi ile derleyici, s dizisinin 10 elemanlý ve her elemanýn char türden bir gösterici olduðunu anlar.
Kullanýlan sistemde göstericilerin uzunluðunun 2 byte olduðunu kabul edersek, 20 byte sürekli bir bölge
tahsis edecektir. Bu durumda;
p[0], p[1], p[2], ...p[9]
dizi elemanlarýnýn her biri char türden bir göstericidir. Elemanlarýndan her biri diðerinden baðýmsýz olarak
kullanýlabilir ve her bir eleman bir nesnedir. Aºaðýdaki örneði 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 türden bir gösterici olan, 10 elemanlý bir gösterici dizisi açýlmýº ve dizinin her
elemaný için, döngü içerisinde malloc fonksiyonu ile 30 byte büyüklüðünde bir bellek bloðu tahsis
edilmiºtir.Tahsis edilen bloklarýn baºlangýç adresleri gösterici dizisinin elemanlarýna yerleºtirildikten sonra,
gets fonksiyonu ile klavyeden girilen karakterlerin tahsis edilen bloklara aktarýlmýºtýr. s isimli dizi yerel bir dizi
olduðuna göre, dizi elemanlarý içerisinde rasgele (garbage values) deðerler olduðunu belirtelim. Dolayýsýyla
malloc fonksiyonu ile yer ayýrmadan yapýlan veri aktarýmlarý gösterici hatalarýna yol açacaktýr.
Dinamik olarak tahsis edilen alanlar, gerektiði zaman yine bir döngü yardýmýyla serbest býrakýlabilir :
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
229
Buy RoboPDF
22 . BÖLÜM :
...
for (k = 0; k < 10; ++k)
free(s[k]);
...
gösterici dizilerine ilk deðer verilmesi
Normal dizilere ilkdeðer nasýl veriliyorsa gösterici dizilerine de ilk deðer ayný biçimde verilir. rneðin:
int *p[] = {
(int *) 0x1FC0,
(int *) 0x1FC2,
(int *) 0x1FC4,
(int *) 0x1FC6,
(int *) 0x1FC8
}
Kuºkusuz ki, gösterici dizisine atanan adreslerin bir amaç doðrultusunda kullanýlabilmesi için güvenli
bölgeleri göstermesi gerekir. Bu nedenle uygulamada karakter gösterici dizisi dýºýndaki gösterici dizilerine ilk
deðer verilmesi durumuna pek raslanmaz. Gösterici dizilerine ilk deðer verme iºlemi genellikle karakter
gösterici dizilerine string ifadeleriyle ilk deðer verilmesi biçiminde karºýmýza çýkmaktadýr.
char türden gösterici dizileri
Uygulamalarda en sýk görülen gösterici dizileri char türden olan gösterici dizilerdir.
Daha önce stringler konusunda da gördüðümüz gibi, stringler C derleyicisi tarafýndan char türden adresler
olarak ele alýndýðýna göre, char türden bir gösterici dizisine stringler aracýlýðýyla ilk deðer verilebilir:
char *aylar[] = {“Ocak",
"ªubat",
"Mart",
"Nisan",
"Mayýs",
"Haziran",
"Temmuz",
"Aðustos",
"Eylül",
"Ekim",
"Kasým",
"Aralýk"
};
aylar dizisinin her bir elemaný char türden bir göstericidir. Ve bu gösterici dizisine stringler ile ilk deðer
verilmiºtir. Baºka bir deyiºle char türden bir gösterici dizisi olan aylar dizisinin her bir elemaný bir yazýyý
göstermektedir.
char türden gösterici dizilerinin kullanýlma nedenleri
1. Program içinde sýk kullanýlacak yazýlarýn her defasýnda yazýlmasý yerine bir gösterici dizisinin
elemanlarýnda saklanmasý. Aºaðýdai örnekte err dizisinin her bir elemanýnda hata mesajlarýna iliºkin yazýlar
saklanmýºtýr.
char *err[] = {“Bellek Yetersiz!”, “Hatalý ºifre”, “Dosya bulunamadý”, “Belirtilen dosya zaten var”, “ “sürücü
hazýr deðil”, "Okunacak dosya açýlamýyor", "yazýlacak dosya açýlamýyor!.."
“Belirlenemeyen
hata!”};
Artýk programýn herhangi bir yerinde yazýlardan biri yazdýrýlmak istenirse, yazdýrýlacak olan yalnýzca gösterici
dizisinin herhangi bir elemanýnda baºlangýç adresi tutulan yazýdýr :
...
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
230
Buy RoboPDF
GÖSTERÝCÝ DÝZÝLERÝ
if (fp == NULL) {
printf("%s\n", err[5]);
return 5;
}
....
2. Bazý yazýlarýn bu ºekilde bir algoritmaya baðlý olarak kullanýlmasý :
#include <stdio.h>
int dayofweek(int day, int month, int year);
char *aylar[] = {“Ocak",
"ªubat",
"Mart",
"Nisan",
"Mayýs",
"Haziran",
"Temmuz",
"Aðustos",
"Eylül",
"Ekim",
"Kasým",
"Aralýk"
};
char *gunler[] = {"Pazar",
"Pazartesi",
"Salý",
"Çarºamba",
"Perºembe",
"Cuma",
"Cumartesi"
};
void display_date(int day, int mon, int year)
{
printf("%02d ", day);
puts(aylar[mon - 1]);
printf(" %d ", year);
}
Bir yazýnýn belirli bir yazýyla ayný olup olmadýðýný, strcmp fonksiyonuyla saptayabiliriz. Peki bir yazýnýn bir
grup yazý içinde var olup olmadýðýný nasýl tespit edebiliriz? Aºaðýda tanýmlanan getmonth fonksiyonu
kendisine baºlangýç adresi gönderilen bir yazýnýn ingilizce ay isimlerinden biri olup olmadýðýný test etmekte,
eðer böyle ise bu ayýn kaçýncý ay olduðu bilgisiyle geri dönmektedir. (1 - 12) Fonksiyon, kendisine gönderilen
argumanda baºlangýç adresi tutulan yazý bir ay ismine karºýlýk gelmiyor ise 0 deðeriyle geri dönmektedir.
#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;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
231
Buy RoboPDF
22 . BÖLÜM :
}
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 yýlýn %d. ayýdýr\n", s, result);
else
printf("%s gecerli bir ay ismi deðildir\n");
}
return 0;
}
stricmp fonksiyonunun iki yazýnýn karºýlaºtýrmasýný büyük harf küçük harf duyarlýlýðý olmadan yapmasý
dýºýnda, strcmp fonksiyonundan baºka bir farký bulunmadýðýný hatýrlayalým.
Gösterici dizileri de týpký diðer diziler gibi yerel ya da global olabilecektir. Eðer dizinin global olmasý
durumunda dizi elemanlarýnýn hepsinin içinde 0 deðerleri olurken, yerel bir gösterici dizisinin içinde rasgele
deðerler olacaktýr. Dizinin her bir elemaný içinde bir adres bilgisi olduðuna göre, atama yapýlmamýº global
gösterici dizilerinin her bir elemaný içinde 0 adresi (NULL adresini) bulunurken, atama yapýlmamýº yerel
gösterici dizilerinin elemanlarý içinde rasgele deðerler bulunmaktadýr.
Bir gösterici hatasýna neden olmamak için önce gösterici dizisi elemanlarýna güvenli adresler yerleºtirmek
gerekmektedir. Stringler statik nesneler gibi ele alýndýklarý için bir gösterici dizisi elemanlarýna stringlerle
deðer vermek bir gösterici hatasýna enden olmayacaktýr. Zira stringler, daha önce de belirtildiði gibi önce
derleyici tarafýndan bellekte güvenli bir bölgeye yerleºtirilirler, daha sonra ise yerleºtirildikleri bloðun
baºlangýç adresi olarak ele alýnýrlar.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
232
Buy RoboPDF
GÖSTERÝCÝYÝ GÖSTEREN GÖSTERÝCÝLER
23 . BÖLÜM : GÖSTERÝCÝYÝ GÖSTEREN
GÖSTERÝCÝLER
konu eklenecek……….
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
233
Buy RoboPDF
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
Buy RoboPDF
DÝNAMÝK BELLEK YÖNETÝMÝ
24 . BÖLÜM : DÝNAMÝK BELLEK YÖNETÝMÝ
C dilinde bir dizi tanýmlandýðý zaman, bu dizi için derleyici tarafýndan bellekte yer ayrýlýr.
Örneðin:
int a[100];
Derleme sýrasýnda yukarýdaki gibi bir dizi tanýmlamasý ile karºýlaºan derleyici bellekte (eðer
kullanýlan sistemde int türü uzunluðunun 2 byte olduðu varsayýlýrsa) toplam 200 byte yer
ayýracaktýr. Programýn çalýºmasý sýrasýnda bir dizinin uzunluðunu deðiºtirmek mümkün deðildir.
Diziler konusunda açýklandýðý gibi, dizi tanýmlama ifadelerinde dizi boyutunu gösteren ifade
(köºeli parantezin içerisindeki ifade) sabit ifadesi olmalýdýr, deðiºken içeremez. Çünkü
derleyicinin bellekte yer ayýrmasý için, dizi boyutunu bilmesi gerekir. Oysa pratikte birçok
uygulamada açýlmasý gereken dizinin boyutu programýn çalýºmasý sýrasýnda (runtime)
belirlenmektedir.
Birtakým sayýlarýn kullanýlmak üzere klavyeden girildiðini düºünelim. Kullanýcýnýn kaç tane sayý
gireceðinin belli olmadýðýný düºünelim. Kullanýcýnýn girdiði sayýlarý tutmak için açýlan bir dizinin
boyutu ne olmalýdýr? Ya da bir dizindeki dosyalarý sýraya göre dizmek için dosya bilgilerini geçici
olarak bir dizide saklayacaðýmýzý düºünelim. Dizinin uzunluðu ne olmalýdýr? Bu baºlangýçta belli
deðildir. Çünkü dizin içinde kaç dosya olduðu belli deðildir. Bu tür örnekleri çoðaltabiliriz. Bu
tip durumlara özellikle veri tabaný uygulamalarýnda sýklýkla raslarýz. Bazý uygulamalarda
dizilerin gerçek uzunluðu programýn çalýºmasý sýrasýnda, ancak birtakým olaylar sonucunda
kesin olarak belirlenebilir. Bu durumda dizilerle çalýºan programcý herhangi bir gösterici
hatasýyla karºýlaºmamak için dizileri en kötü olasýlýðý gözönünde bulundurarak açmak
zorundadýr. Bu da belleðin verimsiz bir ºekilde kullanýlmasý anlamýna gelir. Üstelik açýlan diziler
yerel ise ilgili blok sonlanana kadar, global ise programýn çalýºmasýnýn sonuna kadar bellekte
tutulacaktýr. Oysa, dizi ile ilgili iºlem biter bitmez, dizi için ayrýlan bellek bölgesinin boºaltýlmasý
verimli bellek kullanýmý için gereklidir.
Programýn çalýºma zamaný sýrasýnda belli büyüklükte ardýºýl (contigious) bir bellek bölgesinin
programcý tarafýndan tahsis edilemesine ve istenildiði zaman serbest býrakýlmasýna olanak
saðlayan yöntemlere dinamik bellek yönetimi denir. C dilinde dinamik bellek yönetimi dinamik
bellek fonksiyonlarýyla yapýlmaktadýr. Dinamik bellek yönetiminde kullanýlan standart C
fonksiyonlarý hakkýnda aºaðýda detaylý bilgi verilmektedir. ªüphesiz bu fonksiyonlarýn dýºýnda,
ticari derleyici paketlerinin kütüphanesinde, standart olmayan dinamik bellek fonksiyonlarý da
bulunabilir. Ancak yazýlan kaynak kodun taºýnabilirliði açýsýndan standart C fonksiyonlarý tercih
edilmelidir.
ªimdi dinamik bellek yönetiminde kullanýlan standart C fonksiyonlarýný tek tek detaylý olarak
inceleyelim:
malloc fonksiyonu
malloc fonksiyonu programýn çalýºma zamaný sýrasýnda bellekten dinamik tahsisat yapmak için
kullanýlýr. Fonksiyonun prototipi aºaðýdaki gibidir :
void *malloc(size_t nbyte);
size_t türünün derleyiciye yazanlarýn seçimine baðlý olarak unsigned int ya da unsigned
long türlerinden birinin yeni tür ismi olarak tanýmlanmasý gerektiðini, ve sistemlerin hemen
hemen hepsinde size_t türünün unsigned int türü olduðunu hatýrlayalým.
Fonksiyona gönderilecek arguman tahsis edilmek istenen bloðun byte olarak uzunluðudur.
Tahsis edilen alanýn sürekli (contigous) olmasý garanti altýna alýnmýºtýr. malloc fonksiyonunun
geri dönüº deðeri tahsis edilen bellek bloðunun baºlangýç adresidir. Bu adres void türden
olduðu için, herhangi bir türden göstericiye sorunsuz bir ºekilde atanabilir. Bu adres herhangi
bir türden göstericiye atandýðý zaman artýk tahsis edilen blok gösterici yardýmýyla bir dizi gibi
kullanýlabilir. malloc fonksiyonunun istenilen bloðu tahsis etmesi garanti altýnda deðildir. Birçok
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
235
Buy RoboPDF
24 . BÖLÜM :
nedenden dolayý malloc fonksiyonu baºarýsýz olabilir. Bellekte tahsis edilmek istenen alan kadar
boº bellek bulunmamasý sýk görülen baºarýsýzlýk nedenidir. malloc fonksiyonu baºarýsýz
olduðunda NULL adresine geri döner. malloc fonksiyonu bellekten yer ayýrdýktan sonra
iºleminin baºarýlý olup olmadýðý mutlaka kontrol edilmelidir. malloc fonksiyonu ile bellekte bir
blok tahsis edilmesine iliºkin aºaðýda bir örnek verilmiºtir.
char *ptr;
ptr = (char *) malloc(30);
/* bellekte 30 byte'lýk bir yer tahsis edilmek isteniyor */
if (ptr == NULL) {
printf("cannot allocate memory\n");
exit(EXIT_FAILURE);
}
/* baºarýsýzlýk durumunda program sonlandýrýlýyor */
printf("please enter the name : ");
gets(ptr);
/* tahsis edilen alana klavyeden giriº yapýlýyor */
...
ªüphesiz, malloc fonksiyonu baºarýsýz olduðunda programý sonlandýrmak zorunlu deðiliz.
Atama ve kontrol bir defada da yapýlabilir.
if ((ptr = (char *) malloc(30)) == NULL) {
printf("cannot allocate memory\n");
exit(EXIT_FAILURE); /* baºarýsýzlýk durumunda program sonlandýrýlýyor */
}
malloc fonksiyonu ile yapýlan dinamik tahsisatýn baºarýlý olup olmadýðý mutlaka kontrol
edilmelidir. Fonksiyonun baºarýsýz olmasý durumunda, geri dönüº deðerinin aktarýldýðý gösterici
aracýlýðý ile bellege birºey yazýlmaya çalýºýlýrsa, atama NULL adrese yapýlmýº olur. (NULL pointer
assignment). Programýn yanlýº çalýºmasý kaçýnýlmazdýr.
Programcýlar çoðu kez, küçük miktarlarda ve çok sayýda bloðun tahsis edilmesi durumunda,
kontrolü gereksiz bulma eðilimindedir. Oysa kontrolden vazgeçmek yerine daha kolaylaºtýrýcý
yöntemler denenmelidir. Örneðin p1, p2, p3, p4, p5 gibi 5 ayrý gösterici için 10'ar byte alan
tahsis edilmek istensin. Bu durumda kontrol mantýksal operatörler ile tek hamlede yapýlabilir.
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 bloklarýn herhangi birinde baºarýsýz olursa bu durum if deyimi içinde tespit
edilmektedir.
malloc fonksiyonunun geri dönüº deðeri void türden bir adres olduðu için, bu adres
sorunsuzca her türden göstericiye atanabilir. Ancak okunabilirlik açýsýndan malloc
fonksiyonunun geri dönüº deðeri olan adresin, tür dönüºtürme operatörü yardýmýyla,
kullanýlacak göstericinin türüne dönüºtürülmesi tavsiye edilir. Böylece malloc fonksiyonu ile
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
236
Buy RoboPDF
DÝNAMÝK BELLEK YÖNETÝMÝ
tahsis edilen bloðun ne türden bir diziymiº gibi kullanýlacaðý bilgisi de açýkça okuyucuya
verilmiº olabilir.
C dilinin standartlaºtýrýlmasýndan önceki dönemde void türden göstericiler olmadýðý için, malloc
fonksiyonunun geri dönüº deðeri char türden bir adresti ve bu durumda, geri dönüº deðeri
olan adresin, char türü dýºýnda bir göstericiye atanmasý durumunda tür dönüºümü bir
zorunluluktu.
int türden bir dizi için dinamik olarak tahsisatý yaptýðýmýz düºünelim. Örneðin bir kullanýcýnýn
klavyeden int türden sayýlar gireceðini düºünelim. Kullanýcýdan, kaç tane sayý gireceði bilgisi
alýnsýn ve istenilen miktardaki sayýyý 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;
Yukarýdaki kod parçasýnda int türü uzunluðunun 2 byte olduðu varsayýlmýºtýr. Kaynak kod int
türü uzunluðunun 4 byte olduðu bir sistemde (örneðin UNIX) derlenirse problemler ortaya
çýkacaktýr. Bu taºýnabilirlik problemi sizeof operatörünün kullanýlmasýyla çözülür.
ptr = (int *) malloc(number * sizeof(int));
Artýk çalýºýlan sistem ne olursa olsun number sayýda tamsayý eleman için alan tahsis edilmiº
olacaktýr.
malloc fonksiyonu birden fazla çaðýrýlarak birden fazla alan tahsis edilebilir. malloc fonksiyonun
farklý çaðýrýmlarýyla tahsis edilen bloklarýn bellekte ardýºýl olmasý garanti altýna alýnmýº deðildir.
Bu yüzden fonksiyonun geri dönüº deðeri olan adres mutlaka bir göstericide saklanmalýdýr.
Aºaðýdaki kod parçasý ardýºýk olarak çaðýrýlan malloc fonksiyonlarýnýn ardýºýk bellek bloklarý
tahsis edeceðini varsaydýðý için yanlýºtýr.
#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 alanýn hemen
altýnda olmak zorunda deðildir */
for (i = 0; i < 20; ++i)
ptr[i] = 5;
return 0;
malloc fonksiyonu ile tahsis edilen bloðun içinde rasgele deðerler vardýr. Aºaðýdaki kod parçasý
ile bunu test edebiliriz.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
237
Buy RoboPDF
24 . BÖLÜM :
#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ý kullanýlarak tahsis edilebilecek bellek bölgesi heap olarak
isimlendirilmiºtir. heap alaný donanýmsal bir kavram olmayýp sistemden sisteme
deðiºebilmektedir. (C++ dilinde bu alan free store olarak isimlendirilmektedir.)
malloc fonksiyonunun parametre deðiºkeni unsigned int (size_t) türünden olduðuna göre,
DOS altýnda en fazla 65535 byte (64K) ardýºýl tahsisat yapýlabilir. Oysa UNIX, WINDOWS ve
diðer 32 bitlik sistemlerde unsigned int türü 4 byte uzunluðund olduðuna göre, bu
sistemlerde teorik olarak, malloc fonksiyonu ile 4294967295 byte (4 MB) uzunluðunda ardýºýl
bir tahsisat yapýlabilir.Tabi bu durum, tahsisatýn yapýlabileceði anlamýna gelmez.
calloc fonksiyonu
calloc fonksiyonu malloc fonksiyonuna çok benzer. Prototipi aºaðýdaki gibidir.
void *calloc(size_t nblock, size_t block_size);
calloc fonksiyonu kedisine gönderilen birinci arguman ile ikinci arguman çarpýmý kadar ardýºýl
byte'ý heap alanýndan tahsis etmek için kullanýlýr.
Elemanlarý int türden olan 100 elemanlý bir dizi için dinamik bellek tahsisatý calloc fonksiyonu
ile aºaðýdaki ºekilde yapýlabilir:
int *ptr;
...
ptr = (int*) calloc(100, sizeof(int));
if (ptr == NULL) {
printf("cannot allocate memory\n");
exit(EXIT_FAILURE);
}
...
ªüphesiz yukarýdaki kod parçasýnda calloc fonksiyonu ºu ºekilde de çaðýrýlabilirdi:
ptr = (int*) calloc( sizeof(int), 100);
calloc fonksiyonunun malloc fonksiyonundan baºka bir farký da tahsis ettiði bellek bloðunu
sýfýrlanmasýdýr. calloc fonksiyonu tarafýndan tahsis edilen bloðunun tüm byte'larýnda sýfýr
deðerleri vardýr. malloc fonksiyonu calloc fonksiyonuna göre çok daha sýk kullanýlýr. Tahsis
edilen blok sýfýrlanacaksa malloc fonksiyonu yerine calloc fonksiyonu tercih edilmelidir.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
238
Buy RoboPDF
DÝNAMÝK BELLEK YÖNETÝMÝ
Örneðin 50 elemanlý int türden bir dizi için bellekten bir bloðu dinamik olarak tahsis ettikten
sonra sýfýrlamak istediðimizi düºünelim. Bu iºlemi malloc fonksiyonu ile yaparsak, diziyi ayrýca
döngü içerisinde sýfýrlamamýz 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 sýfýrlama iºlemini kendi içerisinde yapmaktadýr.
calloc fonksiyonu, bellek tahsisatýný yapabilmek için, kendi içinde malloc fonksiyonunu çaðýrýr.
realloc fonksiyonu
realloc fonksiyonu daha önce malloc ya da calloc fonksiyonlarýyla tahsis edilmiº bellek bloðunu
büyültmek ya da küçültmek amacýyla kullanýlýr. Prototipi diðer dinamik bellek fonksiyonlarýnda
olduðu gibi stdlib.h baºlýk dosyasý içindedir.
void *realloc(void *block, unsigned newsize);
realloc fonksiyonuna gönderilen birinci arguman, daha önce tahsis edilen bellek bloðunun
baºlangýç adresi, ikinci arguman ise bloðun toplam yeni uzunluðudur.
realloc fonksiyonu daha önce tahsis edilmiº bloðun hemen altýnda sürekliliði bozmayacak
ºekilde tahsisat yapamaya çalýºýr. Eðer daha önce tahsis edilmiº bloðun aºaðýsýnda istenilen
uzunlukta sürekli yer bulamazsa realloc, bu sefer bloðun tamamý için bellekta baºka boº yer
araºtýrýr. Eðer istenilen toplam uzunlukta ardýºýl (contigious) bir blok bulunursa burayý tahsis
eder, eski bellek bloðundaki deðerleri yeni yere taºýr ve eski bellek bloðunu iºletim sistemine
iade eder. Ýstenen uzunlukta sürekli bir alan bulunamazsa NULL adresiyle geri döner.
Aºaðýdaki programda yapýlan dinamik bellek tahsisatý iºlemlerini 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;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
239
Buy RoboPDF
24 . BÖLÜM :
}
1. malloc fonksiyonu ile 5 int lik yer tahsis ediliyor. Eðer tahsisat iºlemi baºarýlý deðilse exit
fonksiyonuyla program sonlandýrýlýyor.
1A00
1A01
?
?
1A02
1A03
1A04
1A05
1A06
1A07
1A08
1A09
<--ptr
?
?
?
?
?
?
?
?
2. Bir döngü yardýmýyla tahsis edilen alana atamalar yapýlýyor.
1A00
1A01
0
1A02
1A03
1A04
1A05
1A06
1A07
1A08
1A09
<--ptr
1
2
3
4
3. realloc fonksiyonuyla tahsis edilen alan 10 int sayýlýk örneðin DOS altýnda çalýºýyorsak 20
byte'a çýkartýlýyor.
Eðer realloc fonksiyonu baºarýsýz olursa program sonlandýrýlýyor. realloc fonksiyonu baºarýlý
olmuºsa iki ihtimal söz konusudur.
1. realloc fonksiyonu daha önce tahsis edilen alanýn altýnda boºalan bularak ilave tahsisatý
buradan yapmýºtýr :
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 bloðun altýnda boº yer bulamamýº ve heap
alanýnda toplam 20 bytelýk baºka bir boº yer bulmuº olabilir. Bu durumda realloc fonksiyonu
daha önce tahsis edilmiº alandaki deðerleri de bu alana kopyalamýºtýr :
ptr------>
1F00
0
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
240
Buy RoboPDF
DÝNAMÝK BELLEK YÖNETÝMÝ
1F01
1F02
1F03
1F04
1F05
1F06
1F07
1F08
1F09
1F0A
1F0B
1F0C
1F0D
1F0E
1F0F
1F10
1F11
1F12
1F13
1
2
3
4
?
?
?
?
?
realloc fonksiyonunun bu davranýºýndan dolayý mutlaka geri dönüº deðeri bir göstericiye
atanmalýdýr. Aºaðýda sýk yapýlan çok tipik bir hata görülmektedir:
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 baºarýlý olmasý tahsis edilen bloðun altýnda ilave tahsisat yapýldýðý
anlamýna gelmez. (realloc fonksiyonu daha önce tahsis edilmiº alaný baºka bir yere taºýyarak
yeni bloðun baºlangýç adresiyle geri dönmüº olabilir. Bu durumda eski blok serbest býrakýlýr ve
artýk bu adresin bir güvenilirliði yoktur.
Yukarýdaki örnekte realloc fonksiyonunun tahsisatý daha önce tahsis edilen bloðu büyüterek
yaptýðý varsayýlmýºtýr. Eðer realloc fonksiyonu bir taºýma yapmýºsa, yukarýdaki kodda bir
gösterici hatasý yapýlmýº olacaktýr, çünkü artýk p göstericisinin gösterdiði adres güvenilir bir
adres deðildir.
Bu yüzden uygulamalarda genellikle realloc fonksiyonunun geri dönüº deðeri, realloc
fonksiyonuna gönderilen 1. adresi içinde tutan göstericiye atanýr.
ptr = realloc(ptr, 100);
gibi. Ancak bu bir zorunluluk deðildir. Eðer realloc fonksiyonu ile yapýlan tahsisatýn baºarýlý
olmamasý durumunda program sonlandýrýlmayacaksa (örneðin artýk daha fazla tahsisat
yapýlamamasý durumunda) daha önce dinamik olarak tahsis edilen bölgedeki deðerler bir
dosyaya yazýlacak ise, artýk realloc fonksiyonunun baºarýsýz olmasý durumunda, ptr
göstericisine NULL adresi atanacaðý için ptr göstericisinin daha önce tahsis edilen blok ile iliºkisi
kesilmiº olacaktýr.
Böyle bir durumda geçici bir gösterici kullanmak uygun olacaktýr:
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
241
Buy RoboPDF
24 . BÖLÜM :
temp = realloc(ptr, 100);
if (temp == NULL)
printf("cannot allocate memory!..\n);
Bu durumda ptr göstericisi halen daha önce tahsis edilen bloðun baºlangýç adresini
göstermektedir.
C standartlarý realloc fonksiyonu ile ilgili olarak aºaðýdaki kurallarý getirmiºtir:
Bir bellek bloðunu genºletmesi durumunda, realloc fonksiyonu bloða ilave edilen kýsma
herhangi bir ºekilde deðer vermez. Yani eski bloða eklenen yeni blok içinde rasgele deðerler
(garbage values) bulunacaktýr.
realloc fonksiyonu eðer daha önce tahsis edilmiº belelk bloðunu büyütemez ise NULL adresi ile
geri dönecektir ancak tahsis edilmiº olan (büyütülemeyen) bellek bloðundaki deðerler
korunacaktýr.
Eðer realloc fonksiyonuna gönderilen birinci arguman NULL adresi olursa, realloc fonksiyonu
tamamen malloc fonksiyonu gibi davranýr. Yani:
realloc(NULL, 100);
ile
malloc(100);
tamamen ayný anlamdadýr.
(Buna neden gerek görülmüºtür? Yani neden malloc(100) gibi bir çaðýrým yapmak yerine
realloc(NULL, 100) ºeklinde bir çaðýrýmý tercih edelim?
Aºaðýdaki 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;
printf("notu giriniz : ");
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
242
Buy RoboPDF
DÝNAMÝK BELLEK YÖNETÝMÝ
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("hiçbir not giriºi yapmadýnýz!..\n");
return 0;
}
printf("toplam %d tane not girdiniz\n", counter);
printf("girdi§iniz notlar aºaðýda listelenmektedir :\n");
display_array(ptr, counter);
printf("\nen buyuk not : %d\n", find_max(ptr, counter));
printf("en küçük not : %d\n", find_min(ptr, counter));
printf("notlarýn ortalamasý : %lf\n", find_ave(ptr, counter));
printf("notlarýn standart sapmasý . %lf\n", find_stddev(ptr, counter));
free(ptr);
return 0;
Yukarýdaki programda:
ptr = (int *) realloc(ptr, sizeof(int) * counter);
deyiminde, döngünün ilk turunda ptr göstericisinin deðeri NULL olduðu için realloc fonksiyonu
malloc gibi davranacak ve int türden 1 adet nesnelik yer tahsis edecektir. Ancak döngünün
daha sonraki turlarýnda realloc fonksiyonuna gönderilen adres NULL adresi olmayacaðýndan,
daha önce tahsis edilen blok döngü içinde sürekli olarak büyütülmüº olacaktýr.
Tahsis edilen bloðun serbest býrakýlmasý
malloc ya da diðer dinamik bellek fonksiyonlarý "heap" diye isimlendirilen bir bellek bölgesinden
tahsisat yaparlar. Ancak heap alaný da sýnýrlýdýr ve sürekli bu fonksiyonlarýn çaðýrýlmasý
durumunda, belirli bir noktadan sonra fonksiyonlar baºarýsýz olarak NULL adresine geri
dönecektir. heap alanýnýn büyüklüðünü aºaðýdaki 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;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
243
Buy RoboPDF
24 . BÖLÜM :
Dinamik bellek fonksiyonlarýyla tahsis edilen bir blok free fonksiyonu kullanýlarak sisteme iade
edilebilir. free fonksiyonunun prototipi de diðer dinamik bellek fonksiyonlarýnýnkiler gibi stdlib.h
baºlýk dosyasý içindedir:
void free(void *ptr);
free fonksiyonuna gönderilecek olan arguman, daha önce malloc, calloc ya da realloc
fonksiyonlarýyla tahsis edilmiº olan bellek bloðunun baºlangýç adresidir. Bu blok heap alanýna
iade edilmiº olur. Böylece malloc, calloc ya da realloc fonksiyonunun bundan sonraki bir
çaðýrýmýnda iade edilen blok, tekrar tahsis edilme potansiyelindedir.
free fonksiyonuna arguman olarak daha önce tahsis edilen bir bellek bloðunun baºlangýç adresi
yerine baºka bir adres gönderilmesi ºüpheli kod oluºturur (undefined behaviour)
yapýlmamalýdýr.
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 için tahsisat dinamik bellek fonksiyonlarý ile yapýlmamýºtýr. */
free fonksiyonu ile daha önce tahsis edilen blok sisteme iade edilir, ama bu bloðun baºlangýç
adresini tutan gösterici herhangi bir ºekilde deðiºtirilmez. Bloðun baºlangýç adresini tutan, ve
free fonksiyonuna arguman olarak gönderilen gösterici, free fonksiyonun çaðýrýlmasýndan sonra
artýk güvenli olmayan bir adresi göstermektedir.
char *ptr = malloc(100);
...
free(ptr);
...
strcpy(ptr, "Necarti Ergin");
/* yanlýº, bir gösterici hatasý!! */
Eðer realloc fonksiyonuna gönderilen ikinci arguman 0 olursa, realloc fonksiyonu tamamen free
fonksiyonu gibi davranýr.
realloc(ptr, 0);
ile
free(ptr);
tamamen ayný anlamdadýr.
(Buna neden gerk görülmüºtür? Yani neden free(ptr) gibi bir çaðýrým yapmak yerine
realloc(ptr, 0) ºeklinde bir çaðýrýmý tercih edelim?
Dinamik Olarak Tahsis Edilen Bir Alanýn Baºlangýç Adresine Geri Dönen
Fonksiyonlar
Dinamik olarak tahsis edilen bir blok, free fonksiyonuyla serbest býrakýlarak sisteme iade
edilene kadar güvenli olarak kullanýlabileceðine göre , bir fonksiyon böyle bir bloðun baºlangýç
adresine geri dönebilir. Aºaðýdaki fonksiyon tasarýmýný inceleyelim :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
244
Buy RoboPDF
DÝNAMÝK BELLEK YÖNETÝMÝ
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;
Yukarýdaki fonksiyonda kullanýcýdan isim önce kullanýcýdan, yerel bir diziye alýnýyor. Daha sonra
strlen fonksiyonu kullanýlarak ismin uzunluðu tespit ediliyor ve malloc fonksiyonu ile bu ismi ve
sonuna gelecek NULL karakteri içine alacak büyüklükte bir alan dinamik olarak tahsis ediliyor.
Daha sonra da strcpy fonksiyonu kullanýlarak, isim dinamik olarak tahsis edilen alana
kopyalanaýyor ve bu bloðun baºlangýç adresine geri dönülüyor.
Dinamik tahsisat fonksiyonun çaðýrýlmasý neticesinde yapýlacak ve tahsis edilen bloðun serbest
býrakýlmasý fonksiyonu çaðýranýn sorumluluðunda olacaktýr :
int main()
{
char *p;
...
p = getname();
...
free(p)
...
return 0;
}
Bir fonksiyon içinde dinamik olarak bir bellek bloðu tahsis etmek ve daha sonra bu bloðun
baºlangýç adresine geri dönmek C dilinde çok kullanýlan bir tekniktir:
Aºaðýda tasarýmý verilen strcon fonksiyonu birinci parametresinde baºlangýç adresi tutulan
yazýnýn sonuna ikinci parametresinde baºlangýç adresi tutulan yazýyý kopyalayacak fakat her iki
adresteki yazýlarý da bozmadan, birleºtirilmiº yazýnýn baºlangýç adresi olan bir adrese geri
dönecektir. Bu dinamik bellek fonksiyonlarýnýn kullanýlmasýyla mümkündür :
#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);
}
strcpy(ptr, s1);
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
245
Buy RoboPDF
24 . BÖLÜM :
}
strcat(ptr, s2);
return ptr;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
246
Buy RoboPDF
BELÝRLEYÝCÝLER
25 . BÖLÜM : BELÝRLEYÝCÝLER
Belirleyiciler (specifiers), bildirimler yapýlýrken kullanýlan ve nesnelerin ikincil özellikleri
hakkýnda derleyicilere bilgi veren anahtar sözcüklerdir. Belirleyicileri yer belirleyicileri (storage
class specifiers) ve tür belirleyicileri (type qualifiers) olarak iki grupta inceleyeceðiz.
Yer belirleyicileri genel olarak nesnelerin tutulduklarý yerler hakkýnda bilgi verirler. Tür
belirleyicileri ise nesnelerin içindeki deðerlerin deðiºtirilip deðiºtirilmeyeceðine iliºkin bilgi
verirler. C'de 4 tanesi yer belirleyici (auto, register, static, extern) ve 2 tane tür belirleyici
(const, volatile) vardýr. Bu belirleyici isimleri C dilinin birer anahtar sözcüðüdür.
Yer ve Tür Belirleyicileriyle Bildirim ݺlemi
Bildirimin genel biçimi:
[yer belirleyici] [tür belirleyici] <tür> nesne1, [nesne2], [nesne3], ...
auto
const
register
volatile
static
extern
Yer belirleyici, tür belirleyici ya da tür ifade eden anahtar sözcüklerin dizilimi herhangi bir
biçimde 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;
Yukarýdaki bildirimlerin hepsi geçerli bildirimlerdir. Ancak okunabilirlik açýsýndan bildirimlerin
yukarýdaki genel biçime uygun olarak yapýlmasý tavsiye edilir.
Eðer bir bildirimde yer ya da tür belirleyicileri bir tür bilgisi olmadan kullanýlýrsa, önceden
seçilmiº (default) olarak int türü bildirimin yapýldýðý kabul edilir.
const a; /* const int a; bildirimi ile eºdeðerdir. */
ªimdi yer ve tür belirleyicilerini tek tek detaylý olarak inceleyelim :
auto Belirleyicisi
auto yalnýzca yerel deðiºkenler için kullanýlabilecek bir yer belirleyicisidir. auto belirleyicisinin
global deðiºkenlerin ya da fonksiyonlarýn parametre deðiºkenlerininin bildiriminde kullanýlmasý
derleme zamanýnda hata oluºturur.
Bu anahtar sözcük, nesnenin faaliyet alaný bittikten sonra kaybolacaðýný, bellekte kapladýðý
yerin geçerliliði kalmayacaðýný gösterir. Yerel deðiºkenler bulunduklarý blok icra edilmeye
baºlandýðýnda yaratýlýyorlar, söz konusu bloðun icrasý bittikten sonra yok oluyorlardý. ݺte auto
belirleyicisi bu durumu vurgulamak için kullanýlmaktadýr. Zaten bir yerel deðiºken, baºka bir
yer belirleyici anahtar sözcük kullanýlmadýðý sürece (default olarak) auto biçiminde ele alýnýr.
Bu durumda auto yer belirleyicisinin kullanýmý gereksizdir.
{
}
auto int a;
float b;
auto yer belirleyicisi global deðiºkenlerle ya da parametre deðiºkenleriyle birlikte kullanýlmaz.
Örneðin :
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
247
Buy RoboPDF
25 . BÖLÜM :
auto int a;
/* hata çünkü global bir deðiºken auto olarak bildirilemez */
function(auto int x) /* hata parametre deðiºkeni auto biçiminde bildirilemez */
{
auto int var;/* yereldeðiºken auto olabilir */
int x;
/*yerel deðiºken auto belirleyicisi kullanýlmasa da auto olarak ele alýnýr*/
...
}
auto anahtar sözcüðü bazý mikroiºlemcilerde uyumu korumak için düºünülmüºtür. Modern
sistemlerde anlamlý bir kullanýmý yoktur.
register belirleyicisi
register belirleyicisi, deðiºkenin “bellekte deðil de CPU yazmaçlarýnýn içerisinde” tutulacaðýný
belirten bir anahtar sözcüktür. Deðiºkenlerin bellek yerine yazmaçlar içerisinde tutulmasý
programýn çalýºmasýný hýzlandýrýr.
Yazmaç (register) nedir? Yazmaçlar CPU (central processing unit) içerisinde bulunan tampon
bellek bölgeleridir. CPU içerisindeki aritmetik ve mantýksal iºlemleri yapan birimin yazmaçlar ve
belleklerle iliºkisi vardýr. Genel olarak CPU tarafýndan yapýlan aritmetik ve mantýksal iºlemlerin
her iki operandý da belleðe iliºkin olamaz. Örneðin bellekte bulunan sayi1 ve sayi2 ile
gösterdiðimiz 2 sayiyi toplayarak sayi3 ile gösterdiðimiz baºka bir bellek bölgesine yazmak
isteyelim. Bu C’deki
sayi3 = sayi1 + sayi2;
iºlemine karºýlýk gelmektedir. CPU bu iºlemi ancak 3 adýmda gerçekleºtirebilir:
1. adým : Önce sayi1 bellekten CPU yazmaçlarýndan birine çekilir
MOV reg, sayi1
2. adým : Yazmaç ile sayi2 toplanýr.
ADD reg, sayi2
3. adým: Toplam data3 ile belirtilen bellek alanýna yazýlýr.
MOV sayi3, reg
Belleðe yazma ve bellekten okuma iºlemleri yazmaçlara yazma ve yazmaçlardan okuma
iºlemlerine göre daha yavaºtýr. Çünkü belleðe eriºim için bir makine zamaný gerekmektedir.
CPU yazmaçlarý hangi sistem söz konusu olursa olsun sýnýrlý sayýdadýr. Bu nedenle birkaç
deðiºkenden fazlasý register belirleyicisi ile tanýmlanmýº olsa bile yazmaçlarda saklanmayabilir.
C derleyicileri yazmaçlarda saklayamayacaklarý deðiºkenler için genel olarak hata veya uyarý
mesajlarý vermezler. Yani derleyiciler, tutabilecekleri yazmaç sayýsýndan fazla register
belirleyicisine sahip deðiºkenlerle karºýlaºtýklarýnda bunlara iliºkin register belirleyicilerini
dikkate almazlar.
register belirleyicileri ancak yerel ya da parametre deðiºkenleri ile kullanýlabilir global
deðiºkenler ile kullanýlamazlar. Örnekler
register int x;
/* hata x deðiºkeni global register belirleyicisi ile kullanýlamaz */
int sample (register int y)
/* hata deðil */
{
register float x;
/* hata deðil */
...
}
Ne kadar deðiºkenin yazmaçlarda saklanabileceði bilgisayar donanýmlarýna ve derleyicilere
baðlýdýr. Ayrýca, uzunluðu tamsayý (int) türünden büyük olan türler genellikle yazmaçlarda
saklanamazlar bu durumlarda da derleyicilerden hata veya uyarý mesajý beklenmemelidir.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
248
Buy RoboPDF
BELÝRLEYÝCÝLER
Sonuç olarak register belirleyicisi hýzýn önemli olduðu çok özel ve kýsa kodlarda ancak birkaç
deðiºken için kullanýlmalýdýr. Modern derleyicilerin çoðu (seçime baðlý) kod optimizasyonu
yaparak bazý deðiºkenleri yazmaçlarda saklayabilirler. Bu durum da çoðu zaman register
anahtar sözcüðünün kullanýlmasýný gereksiz kýlar.
static Belirleyicisi
static belirleyicisine sahip deðiºkenler programýn çalýºma süresince bellekten kaybolmazlar. Bir
bakýma static belirleyicisi auto belirleyicisinin zýt anlamlýsýdýr. static belirleyicisi ancak yerel
ya da global deðiºkenlere birlikte kullanýlabilirler. static belirleyicisi parametre deðiºkenleriyle
kullanýlmazlar.
static anahtar sözcüðünün global ve yerel deðiºkenlerle birlikte kullanýlmasý farklý anlamlara
gelir bu yüzden bu durumlarý ayrý ayrý inceleyeceðiz:
static Anahtar Sözcüðünün Yerel Deðiºkenlerle Kullanýlmasý
static yer belirleyicisine sahip olan yerel deðiºkenler programýn icrasý boyunca bellekte kalýrlar.
Baºka bir deyiºle, static anahtar sözcüðü yerel deðiºkenlerin ömrünü uzatmaktadýr. Statik
yerel deðiºkenler týpký global deðiºkenler gibi programýn çalýºmaya baºlamasýyla yaratýlýrlar ve
programýn icrasý bitene kadar da bellekte tutulurlar.
Statik yerel deðiºkenler programcý tarafýndan ilk deðer verildikten sonra kullanýlýrlar. Ýlk deðer
verme iºlemi programýn çalýºmasý sýrasýnda deðil, derleme zamanýnda derleyici tarafýndan
yapýlýr. (Derleyici bellekten yer ayrýlmasýna yol açacak makine kodunu oluºturur ve statik
deðiºken için bellekte yer programýn yüklenmesi sýrasýnda ayrýlýr. "Derleyici tarafýndan bellekte
yer ayrýlýr." derken bunu kastediyoruz. Derleme zamanýnda gerçekten bellekte yer ayrýlmýyor,
bellekte yer ayýrma iºini yapacak makine kodu yaratýlýyor.) Statik yerel deðiºkenler ilk
deðerleriyle birlikte belleðe yüklenirler. Örnek :
int statfunc(void)
{
static int x = 12;
/* bu kýsým yalnýzca derleme sýrasýnda ve bir kez iºlem görür */
++x;
/* fonksiyonun her çaðýrýlýºýnda yeniden yaratýlmaz ve deðerini korur */
return x;
}
void main()
{
printf(“a = %d\n”, statfunc()); /* a = 13 */
printf(“a = %d\n”, statfunc()); /* a = 14 */
}
Yukarýda verilen örnekte statfunc() fonksiyonunun içerisindeki yerel x deðiºkeninin deðeri
fonksiyonun her çaðýrýlýºýnda bir artýrýlýr. Çünkü x statik yerel deðiºken olduðu için, fonksiyonun
her çaðýrýlýºýnda yeniden yaratýlmayacak, en son aldýðý deðeri koruyacaktýr.
Daha önce söylendiði gibi, bir adres deðerine geri dönen fonksiyonlar yerel deðiºkenlerin
adreslerine geri dönmemelidir. Ancak yerel deðiºkenin statik olarak tanýmlanmasý durumunda,
statik bir yerel deðiºken programýn sonlanmasýna kadar bellekteki yerini koruyacaðýndan,
fonksiyonun statik bir yerel deðiºkenin adresine geri dönmesinde bir sakýnca yoktur:
char * funk(void)
{
static char ch;
...
return &ch;
}
Diziler bir ya da daha fazla nesnenin bir arada tanýmlandýðý veri yapýlarý olduguna göre, yerel
diziler de static anahtar sözcüðüyle tanýmlanabilirler.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
249
Buy RoboPDF
25 . BÖLÜM :
func(void)
{
static aylar[12] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
...
}
Yukarýdaki örnekte, func() fonksiyonu içinde aylar dizisi static anahtar sözcüðüyle tanýmlandýðý
için, bir kez ilk deðer verildikten sonra her çaðýrýldýðý zaman bu deðerleri koruyacak ve varlýðýný
programýn sonlanmasýna kadar devam ettirecektir. Oysa static anahtar sözcüðü
kullanýlmasaydý, bu dizi func() fonksiyonun her çaðýrýlmasýyla yeniden yaratýlacak ve tüm ilk
deðer atamalarý her defasýnda yeniden yapýlacaktý. Bu da fonksiyonun her çaðýrýlmasýnda belirli
bir makine zamanýnýn tekrar harcanmasýna neden olacaktý.
Statik Yerel Deðiºkenler Ýle Global Deðiºkenlerin Karºýlaºtýrýlmasý
Statik yerel deðiºkenler ömür açýsýndan global yerel deðiºkenler ile ayný özellikleri gösterirler.
Yani programýn çalýºmaya baºlamasý ile yaratýlýrlar ve programýn çalýºmasý bitince ömürleri
sona erer. Ama faaliyet alaný (scope) açýsýndan farklýlýk gösterirler. Global deðiºkenler dosya
faaliyet alanýna uyarken statik yerel deðiºkenler blok faaliyet alanýna uyarlar. Statik yerel
deðiºkenlerin faaliyet alanlarýnýn dar olmasý (blok faaliyet alanýna sahip olmasý) soyutlamayý
(abstraction) ve yeniden kullanýlabilirliði (reusability) kuvvetlendirmektedir. Çünkü global
deðiºkenlere baðlý olan fonksiyonlar projeden projeye taºýnamazlar ve kendi içlerinde bir
bütünlük oluºturmazlar.
static Anahtar Sözcüðünün Global Deðiºkenler Ýle Kullanýlmasý
static belirleyicisi global bir deðiºken ile birlikte kullanýlýrsa, global deðiºkenin faaliyet alanýný,
yalnýzca tanýmlandýðý modülü kapsayacak biçimde daraltýr. Yani global deðiºkenleri kendi
modülleri içine hapseder. Statik global deðiºkenler yalnýzca tanýmlandýklarý modül içerisinde
faaliyet gösterebilirler. Statik global deðiºkenleri daha iyi anlayabilmek için modül kavramýnýn
ne olduðunu bilmek zorundayýz:
Bir proje birbirinden baðýmsýz olarak derlenebilen birden fazla kaynak dosyadan oluºabilir.
Projelerin baðýmsýz olarak derlenebilen herbir kaynak dosyasýna modül denir.
Bir projeyi oluºturan farklý kaynak dosyalarý birbirinden baðýmsýz olarak derlendikten sonra,
hepsi birlikte baðlayýcý (linker) ile birleºtirilerek tek bir .exe dosyasý oluºturulur.
Büyük Projelerin Modüllere Ayrýlmasýnýn Ne Gibi Faydalarý Vardýr
Eðer bütün modüller tek bir kaynak kod içerisinde birleºtirilirse en ufak bir deðiºiklikte tüm
proje tekrar derlenmek zorundadýr. Oysa modüllere ayrýlmýº projelerde, yalnýz deðiºikliðin
yapýldýðý modülün derlenmesi yeterlidir. Çünkü diðer modüller zaten derlenmiºtir ve onlar
yalnýzca baðlama aºamasýnda iºlem görürler. Programlarý modüller halinde yazmanýn bir diðer
avantajý da grup çalýºmasý yaparken ortaya çýkar. Bu durumda projelerin baðýmsýz parçalarý
(modülleri) ayrý kiºiler tarafýndan hazýrlanabilir.
Global bir deðiºken normal olarak tüm modüller içerisinde faaliyet gösterebilirken (Bu
durumda, bir sonraki konuda açýklayacaðýmýz gibi diðer, modüllerde extern bildiriminin
yapýlmýº olmasý gerekmektedir.) statik global deðiºkenler yalnýzca tanýmlandýklarý modül
içerisinde faaliyet gösterirler.
Global deðiºkenler için statik tanýmlamasýnýn yalnýzca faaliyet alaný üzerinde etkili olduðuna,
ömür üzerinde etkili olmadýðýna dikkat ediniz.
Farklý modüllerde ayný isimli iki statik global deðiºken tanýmlanabilir. “C’de ayný faaliyet alanýna
sahip ayný isimli birden fazla deðiºken tanýmlanamaz” kuralýný anýmsayalým. Ýki farklý modülde
tanýmlanan ayný isimli iki statik global deðiºkenin faaliyet alaný farklýdýr.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
250
Buy RoboPDF
BELÝRLEYÝCÝLER
extern Belirleyicisi ve Baðlantý Kavramý (Linkage)
extern belirleyicisini açýklamadan önce linkage (baðlantý) kavramý üzerinde durmak istiyoruz.
Ýlk derslerimizde nesnelerin özelliklerinden birinin de baðlantý (linkage) özelliði olduðunu
söylemiºtik. C standartlarý üç ayrý baðlantý sýnýfý tanýmlamýºtýr :
1. Dýº Baðlantý (external linkage)
Bir modülde tanýmlanan bir nesneye programý oluºturan baºka modüllerde de ulaºýlabilmesi
özelliðidir. Eðer bir deðiºkene baºka bir modülde de tanýnabiliyorsa o deðiºkenin dýº baðlantýsý
var denir.
2. iç baðlantý (internal linkage)
Bir modülde tanýmlanan bir nesneye yalnýzca kendi modülü içerisinde ulaºýlabilmesi özelliðidir.
Eðer bir deðiºken ancak kendi modülü içerisinde
tanýnabiliyorsa, diðer modüllerde
tanýnamýyorsa, o deðiºkenin iç baðlantýsý var denir.
3. baðlantýsýz (no linkage)
Bir modülde tanýmlanan bir nesneye, o modül içinde yalnýzca belirli bir blok içinde
ulaºýlabilmesi özelliðidir. Eðer bir deðiºken ancak kendi modülü içerisinde belirli bir blok
dahilinde tanýnabiliyor, bu blok dýºýnda kendi modülü içinde tanýnmýyorsa, o deðiºkenin
baðlantýsý yoktur denir.
Global deðiºkenlerin dýº baðlantýsý varken, statik global deðiºkenlerin iç baðlantýsý vardýr. Yerel
deðiºkenlerin baðlantýsý yoktur.
Bütün belirleyiciler içinde belki de anlaºýlmasý en güç olaný extern belirleyicisidir. extern
belirleyicisi genel olarak, derleyiciye nesnenin baºka bir modülde tanýmlandýðýný bildirmek için
kullanýlýr
Bir proje MOD1.C ve MOD2.C biçiminde iki modülden oluºmuº olsun :
MOD1.C
int a;
float fonk1()
{
...
a = 100;
...
}
MOD2.C
int fonk2()
{
...
a = 300;
}
/* HATA */
main()
{
...
...
}
MOD1.C modülünde tanýmlanmýº olan a deðiºkeni global bir deðiºkendir ve dosya faaliyet
alanýna uyduðu için normal olarak proje içindeki diðer modüllerde de faaliyet gösterebilir.
MOD2.C modülünde de faaliyet gösterebilir. Fakat iki modülün ayrý ayrý derlendiði yukarýdaki
örnekte problemli bir durum söz konusudur. Çünkü MOD2.C modülünün derlenmesi sýrasýnda
derleyici a deðiºkeninin MOD1.C modülü içerisinde global olarak tanýmlandýðýný bilemez.
MOD2.C modülünü derlerken a deðiºkeni hakkýnda bilgi bulamayan derleyici bu durumu hata
(error) olarak belirler. (C dilinde bir deðiºken ancak önceden bildirilmiºse kullanýlabilir.) extern
belirleyicisi derleyiciye, ilgili global deðiºkeninin kendi modülü içerisinde deðil de bir baºka
modül içerisinde tanýmlý olduðunu bildirme amacýyla kullanýlýr.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
251
Buy RoboPDF
25 . BÖLÜM :
MOD2.C modülündeki a deðiºkeninin extern olarak bildirilmesi durumunda söz konusu problem
ortadan kalkar.
MOD2.C
extern int a; /*extern bildirimiyle a deðiºkeninin baºka bir modülde tanýmlanmýº olduðu
belirtiliyor*/
int fonk2()
{
...
a = 300;
...
}
extern bildirimini gören derleyici deðiºkenin projeye ait baºka bir modülde tanýmlandýðýný
varsayarak hata durumunu ortadan kaldýrýr. Ancak derleyici makine kodu üretirken extern
olarak bildirilmiº bir deðiºkenin bellekteki yerini tespit edemeyeceðinden , bu iºlemi bütün
modülleri gözden geçirecek olan baðlayýcý programa býrakýr. Böylece deðiºkenin tanýmlandýðý
modülü bulup, extern olarak bildirilmiº olanlarla iliºkilendirme iºlemi baðlayýcý (linker)
tarafýndan yapýlmaktadýr. Yani extern belirleyicisi ile programcý derleyiciye, derleyici ise
baðlayýcýya bildirimde bulunmaktadýr.
extern belirleyicisini gören derleyici bellekte bir yer ayýrmaz. extern bildirimi bir tanýmlama
deðildir,
bildirimdir.
Aslýnda yalnýz deðiºkenler için deðil fonskiyonlar için de extern belirleyicisinin kullanýlmasý söz
konusudur. C derleyicileri kendi modülleri içerisinde tanýmlanmadýklarý halde çaðýrýlan (standart
C fonksiyonlarý gibi) fonksiyonlarý otomatik olarak extern kabul ederler. Bu nedenle fonksiyon
prototiplerinde ayrýca extern belirleyicisini yazmaya gerek yoktur. Çünkü derleyici tarafýndan
yazýlmýº varsayýlýr.
Örneðin yukarýda verilen örnekte MOD2.c modülünde bulunan y1 fonksiyonu içerisinde bulunan
x1 fonksiyonu çaðýrýlýyor 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 modülünde x1 fonksiyonu için yazýlmýº olan prototip ifadesini inceleyiniz:
extern float x1(void);
Bu örnekte x1 fonksiyonu baºka bir modülde tanýmlý olduðu için prototip ifadesine extern
belirleyicisi konmuºtur. Ancak konulmasaydý derleyici zaten extern varsayacaktý. (Týpký yerel
deðiºkenler için auto belirleyicisini varsaydýðý gibi.)
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
252
Buy RoboPDF
BELÝRLEYÝCÝLER
Bir global deðiºken hiçbir modülde tanýmlanmadan, bütün modüllerde extern olarak bildirilirse,
tüm modüller hatasýz bir ºekilde derlenebilir. Hata baðlama aºamasýnda, baðlayýcýnýn extern
olarak bildirilen nesneyi hiçbir modülde bulamamasý biçiminde ortaya çýkacaktýr.
extern belirleyicisinin tek bir modül söz konusu olduðunda “amaç dýºý” bir kullanýmý vardýr.
Aºaðýdaki örnekte main fonksiyonu içerisindeki global x deðiºkeni, tanýmlanmadan önce
kullanýldýðýndan hataya neden olmaktadýr.
void main()
{
...
x = 100;
}
int x;
/* x global bir deðiºken ama tanýmlanmasýndan önce yukarýda kullanýlmýº */
int fonk()
{
....
x
...
}
=
200;
yukarýdaki kod derlendiðinde , main fonksiyonunun içerisindeki x deðiºkeninin bildiriminin
bulunamadýðýný ifade eden bir hata mesajýyla karºýlaºýlýr. Bu durumda, eðer bir global deðiºken
tanýmlamadan önce kullanýlýyorsa, hata oluºmamasý için daha önce extern bildiriminde
bulunulmalýdýr.
extern int x;
void main()
{
...
x = 100;
}
int x;
int fonk()
{
....
x
...
}
=
200;
extern bildirimini bu ºekilde kullanmak yerine, global deðiºkeni programýn en baºýnda
tanýmlamak daha iyi bir tekniktir.
extern bildirimlerinin yapýlýº yerleri
extern bildirimleri kaynak kodun herhangi bir yerinde yapýlabilir. Global ya da yerel olmasý
sözkonusu deðilldir. Bildirimin yapýldýðý yerden dosya sonuna kadarcolan bölge için geçerlidir.
Ancak extern bildirimlerinin programýn tepesinde ya da programcýya ait bir baºlýk dosyasýnýn
içinde yapýlmasý daha uygun olur.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
253
Buy RoboPDF
25 . BÖLÜM :
const belirleyicisi
const ilk deðer atandýktan sonra nesnenin içeriðinin deðiºtirilemeyeceðini anlatan tür
belirleyici, bir anahtar sözcüktür. Yerel, global ve parametre deðiºkenleriyle birlikte
kullanýlabilir. Örneðin :
const double PI = 3.14159265
/*Geçerli */
main()
{
const int i = 10;
i = 100;
/* hata */
}
Bir deðiºken const belirleyicisi ile tanýmlanacaksa ilk deðer verilmelidir. Aksi halde const
belirleyicisi kullanmanýn bir anlamý kalmaz. Aºaðýdaki örneði inceleyiniz.
void sample (void)
{
const int a; /* anlamsýz */
}
Bu örnekte a yerel bir deðiºkendir, dolayýsýyla rastgele bir deðere sahiptir. Ýçeriðini bir daha
deðiºtiremeyeceðimize göre tanýmlanmasýnýn da bir anlamý olamaz.
const belirleyicisinin kullaným amacý ne olabilir diye düºünebilirsiniz? Sýklýkla ºu merak edilir:
“Eðer const belirleyicisi koruma amaçlý olarak kullanýlýyorsa kim kime karºý korunuyor? const
belirleyicisinin iki yararlý iºlevi vardýr.:
Okunabilirliði artýrýr. Çünkü programý inceleyen bir kiºi const belirleyicisine sahip deðiºkenin
deðerinin bir daha deðiºtirilemeyeceðini düºünerek daha fazla bilgi edinir.
Yanlýºlýkla nesnenin deðerinin deðiºtirilmesi engellenir.
const belirleyicisi deðeri hiç deðiºmeyecek sabitler için kullanýlmalýdýr. const bildirimlerinin
nesne yarattýðýna nesnenin yalnýzca okunabildiðine (read only) dikkat ediniz.
NOT : C++’da const belirleyicisi zorunluluk olmadýkça nesne yaratmaz. (#define öniºlemci
komutu gibidir, ancak derleme aºamasýnda iºlem görür)
const anahtar sözcüðünün gösterici tanýmlamalarýnda kullanýlmasý :
const anahtar sözcüðünün göstericilerle birlikte üç ayrý kullanýlma biçimi vardýr. Kullanýlan her
biçimde tanýmlanan göstericinin özelliði deðiºecektir :
1. const anahtar sözcüðünün gösterici tanýmlamasýnda ilk sözcük olarak kullanýlmasý. Örnekler
:
double dizi[20];
int k;
const char *str;
const int *ptr;
const
double
*dptr;
Bu durumda göstericinin gösterdiði nesne (yani gösterici içindeki adreste yer alan nesne)
deðiºtirilemez ancak göstericinin kendi deðeri deðiºtirilebilir. Bu tür bir tanýmlamadan sonra
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
254
Buy RoboPDF
BELÝRLEYÝCÝLER
göstericinin gösterdiði yerdeki nesnenin deðiºtirilmeye çalýºýlmasý 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 sözcüðünün göstericilerle birlikte kullanýlmasýnda en sýk görülen biçim budur ve
özellikle fonksiyonlarýn parametre deðiºkenleri olan göstericilerle bu biçim kullanýlýr:
void func(const char *s)
{
...
}
Yukarýda func fonksiyonunun parametre deðiºkeni olan s göstericisi deðerini fonksiyonun
çaðýrmasýyla alacaktýr. Fonksiyon çaðýrma ifadesindeki arguman fonksiyonun çaðýrýlmasýyla s
göstericisine kopyalanacaktýr. Ancak fonksiyon içinde *s nesnesine ya da s[x] nesnesine bir
atama yapýlamaz. Yani s göstericisinin gösterdiði yerdeki nesne (fonksiyona adresi gönderilen
nesne) deðiºtirilemez. Yukarýdaki örnekte const anahtar sözcüðünün kullanýlmasý herºeyden
önce okunabilirlik ile ilgilidir. Yukarýdaki kodu okuyan bir C programcýsý func fonksiyonunun
dýºarýdan adresi alýnan nesnenin yalnýzca deðerinden istifade edeceðini, yani bu nesnenin
deðerini deðiºtirmeyeceðini anlar. Geleneksel olarak, const anahtar sözcüðünün, parametre
deðiºkeni olan göstericilerin tanýmlanmasýnda kuallanýlmamasý okunabilirlik açýsýndan bir mesaj
olarak kabul edilir:
void func(char *s)
{
...
}
Yukarýdaki kodu okuyan bir C programcýsý func fonksiyonunun (aslýnda sentaks açýsýndan bir
zorunluluk bulunmasa da) kendisine adresi gönderilen nesneyi deðiºtireceðini anlar. Kodu
okuyan kiºi ºöyle düºünecektir : Eðer func fonksiyonu adresi gönderilen nesneyi
deðiºtirmeyecek olsaydý, s göstericisi const anahtar sözcüðü ile tanýmlanýrdý.
2. const anahtar sözcüðünün gösterici isminden hemen önce kullanýlmasý . Ö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 göstericinin gösterdiði yerdeki nesne deðiºtirilebilir ama göstericinin içeriði
deðiºtirilemez:
str = (char *) 0x1FC0;
/* error */
ptr = &m;
/* error */
fptr = fdizi;
/* error */
*str = 'A';
*ptr = 15;
fptr[2] = 12.3f;
/*legal */
/*legal */
/*legal */
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
255
Buy RoboPDF
25 . BÖLÜM :
const anahtar sözcüðünün bu kullaným biçiminde gösterici tanýmlanýrken ilk deðer verilmelidir,
yoksa const anahtar sözcüðünün kullanýlmasýnýn bir anlamý kalmaz.
3. const anahtar sözcüðünün hem tanýmlama ifadesinden önce hem de gösterici isminden önce
kullanýlmasý. Örnekler :
...
char ch;
int k;
const char *const str = (char *) 0x1AAA;
const char *const ptr = (int *) 0x1FFF;
Bu durumda ne göstericinin içeriði deðiºtirilebilir ne de göstericinin gösterdiði yerdeki nesne
deðiºtirilebilir. Her iki durum da derleme zamanýnda error oluºumuna yol açacaktýr :
str = &ch;
*str = 'A';
ptr = &k;
*ptr = 12;
/*
/*
/*
/*
error
error
error
error
*/
*/
*/
*/
const sözcüðünün bu biçimde kullanýlmasý yine daha çok parametre
tanýmlanmasýnda görülür ise de bu uygulamalarda seyrek olan bir durumdur.
deðiºkenlerinin
volatile belirleyicisi
Derleyiciler optimizasyon amacýyla nesneleri geçici olarak yazmaçlarda tutabilir. Yazmaçlardaki
bu çeºit geçici barýnmalar register belirleyicisi kullanýlmasa da derleyiciler tarafýndan yapýlabilir.
Örneðin:
int kare (int a)
{
int x;
}
x = a * a;
return x;
Yukarýdaki fonksiyonda x geçici bir deðiºkendir, dolayýsýyla derleyici x deðiºkenini bellekte bir
yerde saklayacaðýna, geçici olarak yazmaçlarýndan birinde saklasa da iºlevsel bir farklýlýk ortaya
çýkmaz. Bu çeºit uygulamalarda derleyicinin deðiºkenleri geçici olarak yazmaçlarda saklamasý
iºlemleri hýzlandýrmaktadýr. Aºaðýdaki kodu inceleyiniz:
int a;
int b;
...
a = b;
if (a == b) {
...
}
Bu örnekte doðal olarak ilk adýmda b deðiºkeni a deðiºkenine aktarýlmak üzere yazmaçlardan
birine çekilecektir. Ancak derleyici if içerisindeki ifadede a == b karºýlaºtýrmasýný yapmak için
bellekteki b yerine yazmaçtaki b’yi kullanabilir. Verdiðimiz iki örnekte de derleyici birtakým
optimizasyonlarla programý iºlevi deðiºmeyecek biçimde daha hýzlý çalýºýr hale getirmek
istemiºtir. Ancak kimi uygulamalarda derleyicinin bu biçimde davranmasý hatalara neden
olabilmektedir. Ýkinci örnekte :
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
256
Buy RoboPDF
BELÝRLEYÝCÝLER
a = b;
/* Bir kesme gelerek b’yi deðiºtirebilir! */
if (a == b) {
...
}
Bir donaným kesmesi (örneðin 8h gibi) b’yi deðiºtiriyorsa, bu durum if deyimi tarafýndan
farkedilmeyebilir. ݺte bu tür durumlarda deðiºkenlerin optimizasyon amacýyla geçici olarak
yazmaçlarda tutulmasý arzu edilmeyen sonuçlarýn oluºmasýna yol açabilmektedir. volatile “
Deðiºkenleri optimizasyon amacýyla yazmaçlarda bekletme, onlarý bellekteki gerçek yerlerinde
kullan!” anlamýna gelen bir tür belirleyicisidir. Bu anlamýyla volatile belirleyicisini register
belirleyicisi ile zýt anlamlý olarak düºünebiliriz. Yukarýdaki örnekte b deðiºkenini volatile olarak
bildirerek anlattýðýmýz gibi bir problemin çýkmasý engellenebilir.
int a;
volatile int b;
...
volatile çok özel uygulamalarda kullanýlabilen bir belirleyicidir.
Yerel, parametre ya da global deðiºkenlerle birlikte kullanýlabilen volatile belirleyicisi ancak çok
özel uygulamalarda önemli olabilmektedir. Bu belirleyicinin bilinçsizce kullanýlmasýnýn
performansý kötü yönde etkileyebileceðini unutmayýnýz.
Belirleyicilerin kullanýlýºlarýný gösteren 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;
}
yukarýdaki programda tanýmlanan deðiºkenlerin faaliyet alaný, ömür ve baðlantý açýsýndan
özellikleri aºaðýdaki tabloda belirtilmektedir :
(isim)
name
(ömür)
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)
(baðlantý)
linkage
dýº (external)
dýº (external)
*
dýº (external)
yok (none)
yok (none)
yok (none)
yok (none)
yok (none)
dýº (external)
*
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
257
Buy RoboPDF
25 . BÖLÜM :
k
otomatik (automatic) blok (block)
yok (none)
* b ve j deðiºkenleri kendi modülleri içinde tanýmlanan global deðiºkenler de olabilir. Bu
durumda bu deðiºkenle
static anahtar sözcüðüyle tanýmlanmýº olmalarý durumunda iç
baðlantýya sahip olacak, static anahtar sözcüðü olmadan tanýmlanmýºlar ise dýº baðlantýya
sahip olacaklardýr.
belirleyicilerin hangi tür deðiºkenlerle kullanýlabileceklerini gösteren tablo :
belirleyici
auto
static
register
extern
volatile
const
global
deðiºken




yerel
deðiºken






parametre deðiºkeni



Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
258
Buy RoboPDF
YAPILAR
26 . BÖLÜM : YAPILAR
Yapýlar (structures) da diziler gibi birden fazla nesneyi içlerinde tutabilen bir veri türürdür.
Yapýlarýn da elemanlarý bellekte ardýºýl (contigious) bir biçimde bulunur. Fakat yapýlarýn
dizilerden temel farký ºudur: Diziler ayný türden nesneleri içinde tutabilirken, yapýlar farklý
türlerden nesneleri tutabilirler. Yapýlarýn kullanýlmasýnýn ana nedeni budur. Çoðu zaman, türleri
farklý bir takým nesneler, mantýksal olarak bir bütün oluºturabilirler. Ýsim, yaº, departman,
ücret, öðrenim durumu gibi bilgileri farklý türden nesneler içinde saklayabiliriz ve bunlarýn
tamamý çalýºan bir personele ait bilgiler olabilir. Bu gibi ayný konu ile ilgili farklý türden veriler
yapýlar içinde saklanýr.
Yapý Bildiriminin Genel ªekli
<struct > [yapý ismi] {
<tür> <m1>;
<tür> <m2>;
<tür> <m3>;
...
};
Yukarýdaki gösterimde struct bir anahtar sözcüktür. Bildirimde mutlaka yer almasý
gerekmektedir. Yapý ismi (structure tag) C dilinin isimlendirme kurallarýna uygun olarak
seçilmiº 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 büyük harfle yazýlýr. Bu bir zorunluluk deðildir.
Yapý bildiriminin yapýlmasý bellekte derleyici tarafýndan bir yer ayrýlmasýna neden olmaz. Yani
bir tanýmlama (definition) söz konusu deðildir. Bu bildirimle (declaration) programcýnýn
yarattýðý yeni bir veri türü hakkýnda derleyiciye bilgi verilmektedir.
Yapý bildiriminin yapýlmasýndan sonra artýk bildirimi yapýlmýº yapý türünden nesneler
tanýmlanabilir. Yapý bilidiriminin yapýlmasý ile yeni bir veri türü yaratýlmýºtýr. Derleyici artýk bu
tür hakkýnda bilgi sahibi oldugundan, bu yeni veri türünden, nesneler tanýmlanabilir. Yeni veri
türünden nesnelerin tanýmlanmasý durumunda artýk derleyici bu nesneler için bellekte ne kadar
bir alan ayýrmasý gerektiði bilgisine sahip olacaktýr.
Yapý Türünden Nesne Tanýmlamasý
<struct> <yapý isimi> <nesne ismi>;
Örnekler :
struct DATE x;
/* x DATE yapýsý türünden bir nesnedir. */
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
259
Buy RoboPDF
26 . BÖLÜM :
struct POINT p1, p1; /* p1 ve p2 POINT yapýsý türünden nesnelerdir. */
struct SAMPLE sample;
/* sample SAMPLE yapý türünden bir nesnedir. */
Yapý deðiºkenleri bileºik nesnelerdir. Yani parçalardan oluºurlar. Zaten yapý bildirimlerinin
yapýlmasýnýn amacý da bu parçalarýn isimleri ve türleri hakkýnda derleyiciye bilgi vermektir. Bir
yapý bildirimini gören derleyici, daha sonra bildirimi yapýlan yapý türünden bir deðiºken
tanýmlanmasý durumunda, bu deðiºken için bellekte ne kadar yer ayýracaðýný, ve ayýrdýðý yeri
ne ºekilde organize edeceðini bilir.
Bir yapý deðiºkeni (nesnesi) için, yapý bildiriminde belirtilen elemanlarýn toplam uzunluðu kadar
(byte olarak) yer ayrýlýr.
struct SAMPLE {
int a;
long b;
char ch;
};
void main()
{
struct SAMPLE x;
}
printf("%d\n", sizeof(x));
Yukarýdaki program parçasýnda ekrana (DOS altýnda) 7 sayýsý yazdýrýlacaktýr. Çünkü yapý
nesnesi olan x nesnesinin bellekte kapladýðý yer üç parçasýnýn kapladýðý uzunluðun toplamýdýr.
Bunu aºaðýdaki ºekilde de ifade edebiliriz:
sizeof(x) == sizeof(int) + sizeof(long) + sizeof(char)
(Hizalama [alignment] konusuna geldiðimizde bu durumu daha detaylý olarak inceleyeceðiz.)
Yapý Elemanlarýna Eriºim
Yapýlarýn dizilerden önemli bir farký da elemanlara eriºim konusundadýr. Dizi elemanlarýna
eriºim, dizi ismi (aslýnda bir adres bilgisidir) ve indis operatörü [ ] (index operator - subscript
operator) yoluyla yapýlýrken, yapý elemanlarýna eriºim doðrudan yapý nesnesinin ve elemanýn
isimleriyle olur. Yapý elemanlarýna eriºimde nokta operatörü kullanýlýr.
Nokta operatörü (.) iki operand alan araek konumunda (binary infix) bir operatördür. Bu
operatörün sol tarafýndaki operand bir yapý türünden deðiºken olmalýdýr. Sað tarafýndaki
operand ise ilgili yapý türününün (yani yapý bildiriminde önceden belirlenmiº) bir üyesi olmak
zorundadýr. Nokta operatörü, operatör öncelik tablosunun en yüksek düzeyinde bulunur.
Yapý nesneleri de yerel ya da global olabilir. Diðer nesnelerde olduðu gibi yapý nesneleri içinde
faaliyet alaný (scope) kavramý söz konusudur. Tüm bloklarýn dýºýnda tanýmlanan yapý nesneleri
global iken bloklarýn içlerinde tanýmlanan yapý deðiºkenleri yereldir. Global yapý nesneleri diðer
türden global nesneler gibi statik ömür karakterine sahiptir ve dosya faaliyet alaný kuralýna
uyarlar. Yerel yapý nesneleri ise dinamik ömürlüdür ve blok faaliyet alaný kuralýna uyarlar.
Yapý deðiºkenlerine programcý tarafýndan deðer verilmemiºse, yapý deðiºkeni yerel (local) ise
tüm elemanlarýnda rasgele deðerler (garbage value) bulunur. Yapý nesnesi global ise tüm
elemanlarýnda 0 deðeri bulunur.
Bir yapý nesnesi tanýmlanarak, bu yapý nesnesinin elemanlarýna nokta operatörü ile
ulaºýldýðýnda artýk bu elemanlarýn her biri ayrý bir nesne olarak ele alýnýr. Bu nesnelerin yapý
dýºýnda tanýmlanan nesnelerden herhangi bir farký yoktur, nesnelerin tüm özelliklerine
sahiptirler.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
260
Buy RoboPDF
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;
Yukarýdaki örnekte görüldüðü gibi x.a, x.b ve x.c yapý elemanlarý ayrý birer nesne özelliði
gösterirler. Bu elemanlara ayrý ayrý ulaºabilir ve ayrý ayrý atamalar yapabiliriz. Bu nesneleri ++
ve -- operatörlerine ya da & operatörüne operand yapabiliriz.
Yapý Bildirimlerinin Yapýlýº Yerleri
Yapý bildirimi global ya da yerel olarak yapýlabilir. Eðer yerel olarak yapýlýrsa yalnýzca bildirimin
yapýldýðý blokta o yapý türünden nesne tanýmlanabilir. Bildirim global olarak yapýlýrsa her yerde
o yapý türünden deðiºken tanýmlanabilir.
Uygulamalarda hemen hemen her zaman yapý bildirimleri programýn tepesinde global olarak
yapýlýr. (Yapý bildirimi baºlýk dosyalarýnýn içinde de yapýlabilir. Bu durumu ileride detaylý olarak
inceleyeceðiz.)
Yapý bildiriminde yer alan yapý elemanlarýnýn faaliyet alaný yapý bildirim bloðuyla sýnýrlýdýr. Yani
yapý bildirimi bloðu dýºýnda, yapý elemaný ile ayný isimli bir deðiºken tanýmlanabilir. Yapý ismi
(structure tag) ile ayný isimli deðiºkenler de tanýmlanabilir.
Aºaðýdaki program parçasýnda isimlendirme açýsýndan bir hata yok. Okunabilirlik açýsýndan iyi
bir uygulama deðil.
struct SAMPLE {
int sample;
long x;
};
int main()
{
int sample, SAMPLE;
...
return 0;
}
Yapý Elemanlarýnýn Bellekteki Yerleºimi
Yapý elemanlarý belleðe, bildirimde ilk yazýlan eleman küçük adreste olacak biçimde, ardýºýl
olarak yerleºtirilir.
Örnek:
struct SAMPLE {
int a;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
261
Buy RoboPDF
26 . BÖLÜM :
};
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ý Deðiºkenlerine Ýlk Deðer Verilmesi (initialization)
Yapý deðiºkenlerine küme parantezleri içerisinde ilk deðer verilebilir. Bu durumda verilen ilk
deðerler sýrasý ile yapý elemanlarýna yerleºtirilir. Daha az sayýda yapý elemanýna ilk deðer
verilebilir, bu durumda ilk deðer verilmemiº yapý elemanlarý 0 deðeri alýrlar.
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 olduðu gibi, yapýlarda da yapý elemanlarýndan daha fazla sayýda elemana ilk deðer
vermek derleme zamanýnda hata oluºumuna neden olacaktýr.
Yapý Elemaný Olarak Göstericilerin Kullanýlmasý
Yapýnýn bir elemaný herhangi türden bir gösterici olabilir. Bu durumda bu yapý elemanýna
ulaºýldýdýðýnda, bu gösterici de yapý elemaný olmayan göstericiler gibi deðerlendirilir
Ö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;
Yukarýdaki örnekte yapý elemanlarýna ilk deðer verme sentaksýyla da (initialization) deðer
atanabilirdi:
....
struct PERSON x = {"Necati", 125};
...
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
262
Buy RoboPDF
YAPILAR
Yapý Elemaný Olarak Dizilerin Kullanýlmasý
Yapýnýn bir elemaný herhangi türden bir dizi olabilir. Dizilerde olduðu gibi, bu durumda da
yapýnýn dizi elemanýnýn 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 deðildir. */
return 0;
}
Yapý Nesneleri Üzerinde Yapýlabilecek ݺlemler
Yapý deðiºkenleri bir bütün olarak aritmetik operatörlerle ve karºýlaºtýrma operatörleri ile
iºleme sokulamaz. Yapý nesneleri üzerinde ºu iºlemler yapýlabilir:
1. Bir yapý deðiºkeninin adresi alýnabilir.
2. Ayný türden iki yapý deðiºkeni birbirine atanabilir.
3. sizeof operatörü ile bir yapý nesnesinin bellekte kapladýðý alan bulunabilir.
Ayný türden iki yapý deðiºkeninin birbirine atanmasýnda yapý elemanlarý karºýlýklý olarak
birbirlerine atanýr. Yani bir blok kopyalanmasý söz konusudur. Atama iºlemi için kesinlikle iki
yapý deðiºkeninin de ayný türden olmasý gerekmektedir. Ýki yapý deðiºkeni de ayný türden
deðilse bu durum derleme aºamasýnda hata oluºturur. Ýki yapýnýn ayný türden olmalarý için ayný
yapý ismi ile tanýmlanmýº olmalarý gerekir. Aºaðýdaki iki yapý, elemanlarýnýn türleri ve diziliºleri
ayný olduðu halde birbirleri ile ayný deðildir 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 zamanýnda hata. a ve b yapýlarý ayný türden deðil. */
Yapý Türünden Adresler ve Göstericiler
Bir yapý deðiºkeninin adresi alýnabilir. Bu durumda elde edilen adresin sayýsal bileºeni yapýnýn
bellekteki baºlangýç adresi, tür bileºeni ise yapý ile ayný türden adrestir. Bir yapý türünden
göstericiler de tanýmlanabilir. Yapý türünden göstericilere ayný yapý türünden bir adres
atanmalýdýr.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
263
Buy RoboPDF
26 . BÖLÜM :
Örnek:
struct POINT_1 *p = &a;
Göstericiler Yapý Elemanlarýna Eriºim
p yapý türünden bir gösterici ve elm de o yapýnýn bir elemaný olmak üzere eriºim ºu biçimde
yapýlýr:
(*p).elm
Burada öncelik operatörünün kullanýlmasý zorunludur. Kullanýlmazsa önce p.elm ele alýnýr daha
sonra * operatörü iºleme sokulurdu. Bu durum da derleme zamanýnda hata oluºumuna neden
olurdu.
Yapýlarýn Fonksiyonlara Parametre Olarak Geçirilmesi
Yapýlarý fonksiyonlara geçirebilmek için iki yöntem kullanýlabilir:
1. Yapýnýn kendisinin fonksiyona parametre olarak geçirilmesi.
Ayný türden yapý nesnelerinin birbirlerine atanabilmesi özelliðinden faydalanýlýr. Bu
yöntemde fonksiyonun parametre deðiºkeni bir yapý deðiºkeni olur. Fonksiyon da ayný yapý
türünden bir yapý deðiºkeni ile çaðýrýlýr. Ayný türden iki yapý deðiºkeninin birbirine atanmasý
geçerli olduðuna göre bu iºlem de geçerlidir. Bu iºlem bir blok kopyalamasý gerektirdiði için
hem bellek hem de zaman açýsýndan göreli bir kayýba neden olur. Üstelik bu yöntemle,
fonksiyon kendisine gönderilen argumanlarý deðiºtiremez. Yani fonksiyon deðerle
çaðýrýlmýºtýr. (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ý deðiºkenlerinin adreslerinin geçirilmesi.
Bu yöntemde fonksiyonun parametre deðiºkeni yapý türünden bir gösterici olur. Fonksiyon
da bu türden bir yapý deðiºkeninin adresi ile çaðýrýlýr. Bu yöntem iyi bir tekniktir. Hemen her
zaman bu yöntem kullanýlmalýdýr. Bu yöntemde yapý ne kadar büyük olursa olsun aktarýlan
yalnýzca bir adres bilgisidir. Üstelik bu yöntemde fonksiyon kendisine adresi gönderilen yapý
deðiºkenini deðiºtirebilir. ªüphesiz böyle bir aktarým iºleminin mümkün olabilmesi yapý
elemanlarýnýn bellekteki ardýºýllýk özelliðinden faydalanýlmaktadýr. Örnek :
struct PERSON {
char name[30];
int no;
};
void disp(struct PERSON *p)
{
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
264
Buy RoboPDF
YAPILAR
printf("%s %d\n", (*p).name, (*p).no);
}
int main()
{
struct PERSON x = {"Necati Ergin", 156};
disp(&x);
}
Yapýlarýn Kullaným Yerleri
Yapýlar temel olarak 3 nedenden dolayý kullanýlýrlar.
1. Birbirleri ile iliºkili olan deðiºkenler yapý elemanlarý olarak bir yapý içerisinde toplanýrsa
algýsal kolaylýk saðlanýr. Örneðin düzlemde bir nokta, bir tarih bilgisi, bir depoda bulunan
mamüllere iliºkin özellikler bir yapý ile temsil edilebilir.
2. C dilinde bir fonksiyon en fazla 8 - 10 parametre almalýdýr. Daha fazla parametreye sahip
olmasý kötü bir tekniktir. Bir fonksiyon çok fazla parametrik bilgiye gereksinim duyuyorsa,
bu parametrik bilgiler bir yapý biçiminde ifade edilmelidir. O yapý türünden bir deðiºken
tanýmlanmalý, bu deðiºkenin adresi fonksiyona parametre olarak gönderilmelidir. Örneðin
bir kiºinin nüfus cüzdan bilgilerini parametre olarak alýp bunlarý ekrana yazdýracak bir
fonksiyon tasarlayacak olalým. Nüfus cüzdaný bilgilerinin hepsi bir yapý biçiminde ifade
edilebilir ve yalnýzca bu yapýnýn adresi fonksiyona gönderilebilir.
3. C dilinde fonksiyonlarýn tek bir geri dönüº deðeri vardýr. Oysa fonksiyonlarýn çok deðiºik
bilgileri çaðýran fonksiyona iletmesi istenebilir. Bu iºlem ºöyle yapýlýr: Ýletilecek bilgiler bir
yapý biçiminde ifade edilir. Sonra bu türden bir yapý deðiºkeni tanýmlanarak adresi
fonksiyona gönderilir. Fonksiyon da bu yapý deðiºkeninin içini doldurur. Yani fonksiyon
çýkýºýnda bilgiler yapý deðiºkeninin içinde olur.
4. C dilinin tasarýmýnda belirlenmiº veri türleri yalnýzca temel türleri kapsayacak ºekildedir.
Örneðin tarihler ya da karmaºýk sayýlar için C dilinde belirlenmiº temel bir tür yoktur
(default veri tipi yoktur.) Yapýlarý bu gibi veri türlerini oluºturmak için kullanýyoruz.
Ok Operatörü
OK operatörü - ve > karakterlerinin yanyana getirilmesiyle oluºturulur. Ýki operand alan araek
konumunda bir operatördür. (Binary infix ) Ok operatörü öncelik tablosunun en yüksek öncelik
seviyesindedir. -> operatörünün sol tarafýndaki operand yapý türünden bir adres olmalýdýr. ->
operatörünün sað tarafýndaki operand ise ilgili yapýnýn bir elemaný olmalýdýr. Sol tarfýndaki
operand ile belirtilen yapýnýn (o adresteki yapýnýn) sað tarafýnda belirtilen elemanýna ulaºmak
için kullanýlýr.
p, yapý türünden bir nesnenin adresini tutuyor olsun. Aºaðýdaki iki ifade eºdeðerdir.
(*)p.a
p->a
Yani nokta ve ok operatörlerinin her ikisi de elemana eriºmek için kullanýlýr. Ancak nokta
operatörü yapý deðiºkeninin kendisiyle ok operatörü ise adresiyle eriºim saðlar. Okunabilirlik
açýsýndan ok operatörünün solunda ve saðýnda boºluk býrakýlmamasýný tavsiye ediyoruz.
&p->a ifadesiyle p'nin gösterdiði yapýnýn a elemanýnýn adresi alýnýr. (Ok operatörü adres
operatörüne göre daha önceliklidir.)
Bir Yapý Türüne Geri Dönen Fonksiyonlar
Bir fonksiyonun geri dönüº deðeri bir yapý türünden olabilir.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
265
Buy RoboPDF
26 . BÖLÜM :
Ö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 dönüº deðerinin aktarýldýðý geçici bölge de struct POINT türünden olur. Böyle
bir fonksiyonun geri dönüº deðeri ayný türden bir yapý deðiºkenine atanabilir.
Ancak böyle fonksiyonlar küçük yapýlar için kullanýlmalýdýr. Çünkü return ifadesiyle geçici
bölgeye geçici bölgeden de geri dönüº deðerinin saklanacaðý deðiºkene atamalar yapýlacaktýr.
Bu da kötü bir teknik olmaya adaydýr. Küçük yapýlar için tercih edilebilir. Çünkü algýsal
karmaºýklýðý daha azdýr.
make_point fonksiyonunun parametre deðiºkenleri ile POINT yapýsýnýn üyeleri ayný isimde
olduklarý halde faaliyet alanlarý farklýdýr.
Yapý Türünden Bir Alanýn Dinamik Olarak Tahsis Edilmesi
Nasýl bir dizi için bellek alaný dinamik olarak tahsis edilebiliyorsa bir yapý için de böyle bir
tahsisat yapýlabilir. Aºaðýdaki örnekte DATE türünden bir yapý için dinamik tahsisat yapýlmýºtýr:
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;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
266
Buy RoboPDF
YAPILAR
Bir Yapý Adresine Geri Dönen Fonksiyonlar
Bir fonksiyonun geri dönüº deðeri bir yapý türünden adres de olabilir.
Örneðin:
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 böyle bir fonksiyon yerel bir yapý deðiºkeninin adresine geri dönemez. Global bir yapý
deðiºkeninin adresine de geri dönmesinin bir anlamý yoktur. (Statik bir yerel yapý nesnesinin
adresiyle geri dönülmesinde hiçbir sakýnca yok. Statik yerel deðiºkenler konusundaki
bilgilerinizi hatýrlayýnýz.) En iyi tasarým, içeride dinamik olarak tahsis edilmiº bir yapýnýn
adresine geri dönmektir.
Tahsis edilen alanýn
sorumluluðundadýr.
"heap"
bellek
alanýna
iade
edilmesi,
fonksiyonu
çaðýranýn
Yapý Bildirimi Ýle Deðiºken Tanýmlamasýnýn Birlikte Yapýlmasý
Bir yapý bildirimi noktalý virgül ile kapatýlmayýp, yapý bildiriminin kapanan blok parantezinden
hemen sonra bir deðiºken listesi yazýlýrsa yapý bildirimi ile deðiºken tanýmlamasý bir arada
yapýlmýº olur.
struct DATE {
int day, month, year;
} bdate, edate;
Bu tanýmlamada struct DATE türünden bir yapýnýn bildirimi ile birlikte bu yapý türünden bdate
ve edate deðiºkenleri de tanýmlanmýºtýr. Bu durumda yapý deðiºkenlerinin faaliyet alanlarý yapý
bildiriminin yerleºtirildiði yere baðlý olarak belirlenir. Yani söz konusu yapý deðiºkenleri yerel ya
da global olabilir.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
267
Buy RoboPDF
26 . BÖLÜM :
Yapý nesnelerinin hemen yapý bildiriminden sonra tanýmlanmasý durumunda yapý ismi kullanma
zorunluluðu da bulunmamaktadýr. Örneðin yukarýdaki bildirim aºaðýdaki ºekilde de yapýlabilir.
struct {
int day, month, year;
} bdate, edate;
Burada bdate ve edate yukarýda bildirilen (ama isimlendirilmeyen) yapý türünden
deðiºkenlerdir. Bu yöntemin dezavantajý artýk ayný türden baºka bir yapý deðiºkeninin
tanýmlanmasýnýn mümkün olmayýºýdýr. Örneðin yukarýdaki kod parçasýndan sonra ayný yapý
türünden bir yapý nesnesi daha tanýmlamak istediðimizi düºünelim. Bu tanýmlama
struct {
int day, month, year;
} cdate;
ºeklinde yapýlsa bile artýk derleyici, eleman yapýsý ve elemanlarýn türleri ayný olsa bile bu yapýyý
ayrý bir yapý türü olarak ele alacaktýr. Dolayýsýyla
cdate = bdate;
gibi bir atama yapý türlerinin farklý olmasý nedeniyle geçerli deðildir.
Böyle bir tanýmlamanýn baºka bir dezavantajý da bu yapý türüyle ilgili bir fonksiyon
yazýlamayýºýdýr. Çünkü yapý türünün bir ismi yoktur, ve bir fonksiyonun parametre deðiºkeni
tür bilgisi olmadan tanýmlanamaz.
Ýçiçe Yapýlar (nested structures)
Bir yapýnýn elemaný baºka bir yapý türünden yapý deðiºkeni ise bu duruma içiçe yapýlar denir.
Ýçiçe yapý bildirimi iki biçimde yapýlabilir :
1. Önce eleman olarak kullanýlan yapý bildirilir. Onun aºaðýsýnda diðer yapý bildirimi yapýlýr.
Örnek:
struct DATE {
int day, month, year;
};
struct PERSON {
char name[30];
struct DATE birthdate;
int no;
};
Bu durumda içteki yapýya ulaºmak için 2 tane nokta operatörü 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;
}
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
268
Buy RoboPDF
YAPILAR
2. Bu yöntemde eleman olan yapý deðiºken tanýmlamasý ile birlikte elemana sahip yapýnýn
içerisinde bildirilir.
Örnek:
struct PERSON {
char name[30];
struct DATE {
int day, month, year;
} birthdate;
int no;
};
Burada içte bildirilen yapý da sanki dýºarýda bildirilmiº gibi iºlem görür. yani içeride bildirilen
yapý türünden deðiºkenler tanýmlanabilir. Burada dikkat edilmesi gereken bir noktada içiçe yapý
bildiriminin yapýlmasýna raðmen bir deðiºken tanýmlamasýnýn yapýlmamýº olmasýdýr. Yani
birthdate bir nesne deðildir. Ancak struct PERSON türünden bir deðiºken tanýmlandýðýnda, bu
yapý deðiºkeninin bir alt elemaný olacaktýr:
struct PERSON X;
X.birthdate.day = 20;
Ýçiçe Yapýlara Ýlk Deðer Verilmesi
Normal olarak ilk deðer vermede elemanlar sýrasýyla, içteki yapý da dikkate alýnacak biçimde,
yapý üyelerine atanýr. Ancak içteki yapýnýn ayrýca küme parantezleri içerisine alýnmasý
okunabilirliði artýrdýðý için tavsiye edilir. Örnek:
struct PERSON per = {"Necati Ergin", {10, 10, 1967}, 123};
Eðer içteki yapý ayrýca küme parantezi içine alýnmýºsa içteki yapýnýn daha az sayýda elemanýna
ilk deðer vermek mümkün olabilir. Örnek :
struct PERSON per = {"Necati Ergin", {10, 10}, 123};
Burada doðum tarihinin year elemanýna ilk deðer verilmemiºtir. Derleyici bu elemana otomatik
olarak 0 deðeri yerleºtirecektir. Ancak burada içteki küme parantezleri kullanýlmasaydý 123 ilk
deðeri year elemanýna verilmiº olacak, no elemanýna otomatik olarak 0 deðeri verilmiº olacaktý.
Ayný durum yapý içinde dizi bildirimlerinde de söz konusudur. Örnek :
struct SAMPLE {
int a[3];
long b;
char c;
};
struct SAMPLE x = {{1, 2, 3}, 50000L, 'x'};
Aºaðýdaki gibi bir bildirim de geçerlidir :
struct SAMPLE {
int a[3];
long b;
char c;
} x = {{1, 2, 3}, 50000L, 'A}, *p;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
269
Buy RoboPDF
26 . BÖLÜM :
Ýçiçe Yapý Kullanýmýnýn Avantajlarý
Aºaðýdaki gibi bir yapý bildiriminin yapýldýðýný düºünelim :
struct ISIM {
char ad[ADUZUNLUK + 1];
char soyad[SADUZUNLUK + 1];
};
Ýsim yapýsýný daha büyük bir yapýnýn parçasý olarak kullanabiliriz.
struct OGRENCI {
struct ISIM isim;
int no, yas;
char cinsiyet;
} ogrenci1, ogrenci2;
Bu durumda ogrenci1 degiskeninin ad ve soyad'ýna ulaºmak icin iki kez nokta operatörü
kullanýlacaktýr:
strcpy(ogrenci1.isim.ad, “Hakan”);
Yukarýdaki örnekte OGRENCI yapýsýnýn elemaný olarak ISIM yapýsýný kullanmak yerine,
dogrudan ad[ADUZUNLUK + 1] ve char soyad[SADUZUNLUK + 1] dizilerini OGRENCI yapýsýnýn
elemanlarý yapabilirdik. Ama isim yapýsýný doðrudan bir eleman olarak kullanýrsak bazý iºlemleri
daha kolay yapabiliriz. Örneðin öðrencilerin ad ve soyadýný yazan bir fonksiyon yazacaðýmýzý
düºünelim. Bu durumda yazýlacak fonksiyona 2 arguman göndermek yerine yalnýzca 1
arguman gönderilecektir.
isim_yaz(ogrenci1.isim);
Benzer ºekilde isim türünden bir yapý elemanýndan ögrencinin ad ve soyad bilgilerini OGRENCI
yapýsý türünden bir deðiºkenin alt elemanlarýna kopyalama daha kolay yapýlacaktýr :
struct isim yeni_isim;
...
ogrenci1.isim = yeni_isim;
Yapý Dizileri
Yapýlar da bir tür belirttiðine göre yapý türünden de diziler söz konusu olabilir. Yapý dizilerine de
normal dizilere ilk deðer verilmesine benzer ºekilde ilk deðer verilebilir. Ýlk deðer verme
sýrasýnda kullanýlan, içteki küme parantezleri okunabilirliði artýrýr. Ö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;
}
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
270
Buy RoboPDF
YAPILAR
}
return 0;
Program parçasýný º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);
}
Yapýlara Ýliºkin Karmaºýk Durumlar
Bir yapýnýn elemaný baºka bir yapý türünden yapý göstericisi olabilir. Örneðin:
struct DATE {
int day, month, year;
};
struct PERSON {
char name[30];
struct DATE *bdate;
int no;
};
struct PERSON x; ºeklinde bir tanýmlamanýn yapýldýðýný düºünelim.
1. x.bdate ifadesinin türü struct DATE türünden bir adrestir ve nesne belirtir. (Nesne belirtir
çünkü bdate bir gösterici deðiºkendir.)
2. x.bdate->day ifadesinin türü int dir ve nesne belirtir.
3. &x.bdate->day ifadesinin türü int türden bir adrestir.
Tabi bu örnekte, bir deðer atamasý yapýlmamýºsa, x.bdate ile belirtilen gösterici içerisinde
rasgele bir adres vardýr. (garbage value) Bu göstericinin kullanýlabilmesi için tahsis edilmiº bir
alaný göstermesi gerekir. Örneðin bu alan dinamik olarak tahsis edilebilir.
x.bdate = (struct DATE *) malloc (sizeof(struct DATE));
Yukarýdaki örnekte elimizde yalnýzca struct PERSON türünden bir gösterici olduðunu
düºünelim.
struct PERSON *person;
1. person->bdate ifadesinin türü struct DATE türünden bir adrestir.
2. person->bdate->day ifadesinin türü int dir.
Bu örneklerde henüz hiçbir yer için bilinçli bir tahsisat yapýlmamýºtýr. Hem person göstericisi
için hem de person->date göstericisi için, dinamik bellek fonksiyonlarýyla bellekte yer
tahsisatlarýnýn yapýlmasý gerekir:
person = (struct PERSON *) malloc(sizeof(struct PERSON));
person->bdate = (struct DATE *) malloc(sizeof(struct DATE));
Burada dinamik olarak tahsis edilen alanlar ters sýrada iade (free) edilmelidir.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
271
Buy RoboPDF
26 . BÖLÜM :
free(person->bdate);
free(person);
Bir yapýnýn elemaný kendi türünden bir yapý deðiºkeni olamaz. Örneðin:
struct SAMPLE {
struct SAMPLE a;
};
/* hata */
Çünkü burada SAMPLE yapýsýnýn uzunluðu belirlenemez. Ancak bir yapýnýn elemaný kendi
türünden bir gösterici olabilir. Örneðin:
struct LLIST {
int val;
struct LLIST *next;
};
Bu tür yapýlar özellikle baðlý liste ve aðaç yapýlarýný (algoritmalarýný) gerçekleºtirmek amacýyla
kullanýlabilir. (Bu konu detaylý olarak baðlý listeler dersinde ele alýnacaktýr.
Baðlý Liste Nedir
Bellekte elemanlarý ardýºýl olarak bulunmayan listelere baðlý liste denir. Baðlý listelerde her
eleman kendinden sonraki elemanýn nerede olduðu bilgisini de tutar. Ýlk elemanýn yeri ise yapý
türünden bir göstericide tutulur. Böylece baðlý listenin tüm elemanlarýna ulaºýlabilir. Baðlý liste
dizisinin her elemaný bir yapý nesnesidir. Bu yapý nesnesinin bazý üyeleri baðlý liste
elemanlarýnýn deðerlerini veya taºýyacaklarý diðer bilgileri tutarken, bir üyesi ise kendinden
sonraki baðlý liste elemaný olan yapý nesnesinin adres bilgisini tutar. Örnek:
struct LLIST {
int val;
struct LLIST *next;
};
Baðlý listenin ilk elemanýnýn adresi global bir göstericide tutulabilir. Son elemanýna iliºkin
gösterici ise NULL adresi olarak býraklýlýr. Baðlý liste elemanlarý malloc gibi dinamik bellek
fonksiyonlarý ile oluºturulur.
Baðlý Listelerle Dizilerin Karºýlaºtýrýlmasý
Dizilerde herhangi bir elemana çok hýzlý eriºilebilir. Oysa baðlý listelerde bir elemana
eriºebilmek için, baðlý listede ondan önce yer alan bütün elemanlarý dolaºmak gerekir.
Dizilerde araya eleman ekleme ya da eleman silme iºlemleri için blok kaydýrmasý yapmak
gerekir. Oysa baðlý listelerde bu iºlemler çok kolay yapýlabilir.
Diziler bellekte ardýºýl bulunmak zorundadýr. Bu durum belleðin bölünmüº olduðu durumlarda
belirli uzunlukta dizilerin açýlmasýný engeller. Yani aslýnda istenilen toplam büyüklük kadar boº
bellek vardýr ama ardýºýl deðildir. ݺte bu durumda baðlý liste tercih edilir.
Baðlý liste kullanýmý sýrasýnda eleman ekleme, eleman silme, baðlý listeyi gezme (traverse), vb.
iºlemler yapýlýr.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
272
Buy RoboPDF
C DÝLÝNÝN TARÝH VE ZAMAN ÝLE ÝLGÝLÝ ÝªLEM YAPAN STANDART FONKSÝYONLARI
27 . BÖLÜM : C DÝLÝNÝN TARÝH VE ZAMAN ÝLE ÝLGÝLÝ
ݪLEM YAPAN STANDART FONKSÝYONLARI
time_t time (time_t *timer);
01.01.1970 tarihinden itibaren geçen saniye sayýsýný
bulur. Bu deðer bazý tarih ve zaman fonksiyonlarýnda
girdi olarak kullanýlmaktadýr.
geri dönüº deðeri 01.01.1970 den
çaðýrýldýðý zamana kadar geçen saniye
sayýsýdýr. Bu deðeri ayný zamanda
kendisine
gönderilen
argumandaki
adrese de yazar. Arguman olarak NULL
adresi gönderilirse saniye deðerini
yalnýzca geri dönüº deðeri olarak
üretir.
struct tm localtime(const time_t *timer);
Geri dönüº deðeri struct tm türünden
localtime fonksiyonu çaðýrýldýðý andaki sistem bir yapý adresidir. Bu yapý içinde
tarihinin ve zamanýnýn elde edilmesi amacýyla ayrýºtýrýlmýº tarih ve zaman bilgileri
kullanýlýr. 01.01.1970 tarihinden geçen saniye bulunmaktadýr.
sayýsýný
(yani
time
fonksiyonunun
çýktýsýný)
parametre olarak alýr, bunu o andaki tarih ve zaman
deðerine dönüºtürerek statik olarak tahsis edilmiº bir
yapý içerisinde saklar.
char *ctime(const time_t *time);
fonksiyon kendi içerisnde statik olarak
Bu fonksiyon time fonksiyonunun çýktýsýný parametre tahsis ettiði dizinin adresine geri
olarak alýr, 26 karakterlik NULL ile biten bir diziye döner. (Dolayýsýyla hep ayný adrese
yerleºtirerek dizinin baºlangýç adresiyle geri döner. geri dönmektedir.)
Tarih ve zaman bilgisinin dizi içerisindeki durumu
ºöyledir:
DDD MMM dd hh:mm:ss YYYY
Mon Oct 20 11:31:54 1975\n\0
DDD : Ýngilizce günlerin ilk üç harfinden elde edilen
kýsaltma
MMM : Ýngilizce aylarýn ilk üç harfinden elde edilen
kýsaltma
dd
: Sayýsal olarak ayýn hangi günü olduðu
hh
: Saat
mm
: Dakika
ss
: Saniye
YYYY : Yýl
char *asctime (const struct tm *tblock);
fonksiyon kendi içerisnde statik olarak
ctime fonksiyonuna benzer bir iºlevi yerine tahsis ettiði dizinin adresine geri
getirir.Parametre olarak ctime fonksiyonundan farklý döner. (Dolayýsýyla hep ayný adrese
olarak struct tm türünden bir gösterici alýr. Týpký geri dönmektedir.)
ctime fonksiyonunda olduðu gibi tarihi ve zamaný 26
karakterlik bir diziye yerleºtirir.
clock_t clock(void)
Baºarý
durumunda
programýn
Programýn baºlangýcýndan itibaren geçen saat baºlangýcýndan beri geçen iºlemci
ticklerinin sayýsýný verir.
zamaný deðerine geri döner.
clock fonksiyonu iki olay arasýndaki zamansal farký Baºarýsýzlýk durumunda iºlemci zamaný
bulmak için kullanýlýr. Elde edilen zaman deðerini elde edilemiyorsa, ya da deðeri elde
saniyeye çevirmek için, bu deðeri CLK_TCK sembolik edilemiyorsa) –1 deðerine geri döner.
sabitine bölmek gerekir.
double difftime(time_t time2, time_t time1);
Geri dönüº deðeri time1 ve time2
Ýki zaman arasýndaki farký saniye olarak hesaplar.
zamanlarý arasýndaki saniye olarak
farktýr.
Uygulama
#include <conio.h>
#include <time.h>
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
273
Buy RoboPDF
27 . BÖLÜM :
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;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
274
Buy RoboPDF
C DÝLÝNÝN TARÝH VE ZAMAN ÝLE ÝLGÝLÝ ÝªLEM YAPAN STANDART FONKSÝYONLARI
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);
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
275
Buy RoboPDF
27 . BÖLÜM :
/* 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 */
}
/* Gönderilen argumanýn artýk yýl olup olmadýgýný test eder. Artýk yýl ise 1
degil ise 0 deðerine geri döner. */
BOOL isleap(int year)
{
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)
return TRUE;
return FALSE;
}
/* Gönderilen adresteki DATE türünden yapý nesnesine ilk 3 argumanýndaki ay,
gün, yýl deðerlerini yerleºtirir. */
void setDate(int day, int month, int year, DATE *date)
{
date->day = day;
date->month = month;
date->year = year;
}
/* Gönderilen adresteki yapý nesnesinin elemanlarýný ekrana yazdýrýr. */
void displayDate(const DATE *date)
{
printf("%02d %02d %4d", date->day, date->month, date->year);
}
/* gönderilen 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)]);
}
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
276
Buy RoboPDF
C DÝLÝNÝN TARÝH VE ZAMAN ÝLE ÝLGÝLÝ ÝªLEM YAPAN STANDART FONKSÝYONLARI
/* 01.01.1900 tarihinden adresi verilen tarihe kadar geçen gün sayýsýna geri
döner. */
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;
}
yapý
/*
adresi gönderilen
olduðunu bulur. */
nesnesindeki
tarihin
ilgili
yýlýn
kaçýncý
günü
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 gönderilen
farkýný bulur. */
yapý
nesnelerinde
saklanan
tarihler
arasýndaki
gün
int datedif(const DATE *date1, const DATE *date2)
{
return abs(totaldays(date1) - totaldays(date2));
}
/* Parametre deðiºkenindeki gün sayýsýný DATE türünden bir nesneye dönüºtürerek
geri dönüº deðeri 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;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
277
Buy RoboPDF
27 . BÖLÜM :
}
result.month = i + 1;
result.day = totaldays;
return result;
}
/* Adresi gönderilen yapý nesnesindeki tarihten n gün sonraki ya da önceki
tarihin ne oldugunu hesaplayarak bu tarihe geri döner. */
DATE nDate(const DATE *date, int n)
{
return totaltoDate(totaldays(date) + n);
}
/*
*/
adresi gönderilen yapý nesnesindeki tarihin hangi gün olduðunu 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 gönderilen yapý nesnelerindeki tarihleri karºýlaºtýrýr. */
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 gönderilen yapý adresindeki tarihin gecerli bir tarih olup olmadýðýný
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 olmadýðýný test eder. */
BOOL isweekend(const DATE *date)
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
278
Buy RoboPDF
C DÝLÝNÝN TARÝH VE ZAMAN ÝLE ÝLGÝLÝ ÝªLEM YAPAN STANDART FONKSÝYONLARI
{
DAYS result = Dateday(date);
if (result == SAT || result == SUN)
return TRUE;
return FALSE;
}
/* 01.01. 1900 ve 31.12.2000 tarihleri arasýnda 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 baðlý liste oluºturulmasýna iliºkin 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
3
4
5
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;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
279
Buy RoboPDF
27 . BÖLÜM :
case DELETE_NAME : delete_name(); break;
case DELETE_NO : delete_no(); break;
case DISPLAY
: display_list(); break;
case EXIT_PROG
: goto EXIT;
default
: printf("geçersiz seçenek!..\n");
}
}
EXIT:
exit(EXIT_SUCCESS);
return 0;
}
/************************************************/
int get_option(void)
{
int option;
printf("\n[1] baðlý listenin baºýna ekle.\n");
printf("[2] baðlý listeye sondan ekle.\n");
printf("[3] baðlý listeden isme göre sil.\n");
printf("[4] baðlý listeden no'ya göre sil.\n");
printf("[5] baðlý 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;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
280
Buy RoboPDF
C DÝLÝNÝN TARÝH VE ZAMAN ÝLE ÝLGÝLÝ ÝªLEM YAPAN STANDART FONKSÝYONLARI
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("kayýt 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("kayýt bulunamadý\n");
return;
}
if (prev == NULL)
start = start->next;
else
prev->next = cur->next;
free(cur);
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
281
Buy RoboPDF
27 . BÖLÜM :
printf("kayýt silindi!..\n");
}
Uygulama
Sýralý baðlý liste oluºturulmasýna iliºkin 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;
}
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
282
Buy RoboPDF
C DÝLÝNÝN TARÝH VE ZAMAN ÝLE ÝLGÝLÝ ÝªLEM YAPAN STANDART FONKSÝYONLARI
/************************************************/
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
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
283
Buy RoboPDF
27 . BÖLÜM :
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;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
284
Buy RoboPDF
C DÝLÝNÝN TARÝH VE ZAMAN ÝLE ÝLGÝLÝ ÝªLEM YAPAN STANDART FONKSÝYONLARI
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;
}
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
285
Buy RoboPDF
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
Buy RoboPDF
TÜR TANIMLAMALARI ve typedef ANAHTAR SÖZCÜÐÜ
28 . BÖLÜM : TÜR TANIMLAMALARI ve typedef
ANAHTAR SÖZCÜÐÜ
C dilinde bir türe her bakýmdan onun yerini tutabilen alternatif isimler verilebilir. Bu iºlemler
typedef anahtar sözcüðü ile yapýlýr.
Genel biçimi:
typdef <isim> <yeni isim>;
Örnek :
typedef unsigned int UINT;
Bu bildirimden sonra UINT ismi derleyici tarafýndan unsigned int türünün yeni bir ismi olarak
ele alýnacaktýr. Yani kaynak kod içerisinde UINT sözcüðü kullanýldýðýnda derleyici bunu
unsigned int olarak anlamlandýracaktýr.
UINT x, y, k;
Bildiriminde artýk x, y, k deðiºkenleri unsigned int türünden tanýmlanmýº olurlar.
printf("%d\n", sizeof(UINT));
typedef anahtar sözcüðü ile yeni bir tür ismi yaratýlmasý bu türe iliºkin önceki ismin
kullanýlmasýna engel olmaz. Yani yukarýdaki örnekte gösterilen typedef bildiriminin
yapýlmasýndan sonra
unsigned int result;
gibi bir bildirimin yapýlmasýna engel bir durum söz konusu deðildir.
ªüphesiz #define öniºlemci komutuyla da ayný iº yapýlabilirdi.
#define UINT unsigned int
Ancak typedef anahtar sözcüðü derleyici tarafýndan ele alýnýrken #define ile tanýmlanan
sembolik sabitler öniºlemciyi ilgilendirmektedir.
Karýºýk tür tanýmlamalarýnda
öngelleyecektir.
aºaðýdaki
kural
sentaks
açýsýndan
hata
yapýlmasýný
typedef anahtar sözcüðü, her tür bildirimin önüne gelir. typedef anahtar sözcüðü bir
bildirimin önüne geldiðinde typedef kullanýlmamýº olsaydý nesne olacak isimler, typedef
anahtar sözcüðü eklendiðinde artýk tür ismi olurlar. Örnekler:
char * pstr;
bildirimi ile pstr char türden bir gösteri olur.
typedef char *pstr;
bir tür tanýmlamasýdýr ve artýk pstr bir tür olarak ele alýnýr. pstr char türden bir adres türünün
baºka bir ismi olarak, geçerli bir türdür.
Yani yukarýdaki tür tanýmlamasýndan sonra
pstr p;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
287
Buy RoboPDF
28 . BÖLÜM :
gibi bir bildirim yapýlabilir. Bildirim char *p ile ayný anlama gelir.
Bu örnekte yapýlan tür tanýmlamasý #define öniºlemci komutuyla, yani sembolik sabit
tanýmlamasýyla yapýldýðýnda kodda yanlýºlýk olabilirdi.
#define pstr char *
gibi bir sembolik sabit tanýmlamasý yapýldýðýnda öniºlemci pstr gördüðü yerde bunun yerine
char * yerleºtirecektir.
char *str;
gibi bir bildirimin
pstr str;
olarak yazýlmasýnda bir hata söz konusu olmaz çünkü öniºlemci pstr yerine char *
yerleºtirdiðinde derleyiciye giden kod char *str haline gelir.
char *p1, *p2, *p3;
pstr öniºlemci sabitini kullanarak yukarýdaki gibi bir bildirimin yapýlmak istendiðini düºünelim.
pstr p1, p2, p3;
yazýldýðýnda, öniºlemci yer deðiºtirme iºlemini yaptýktan sonra derleyiciye verilen kod aºaðýdaki
biçime dönüºecektir :
char *p1, p2, p3;
Bu tanýmlama yapýlmak istenen tanýmlamaya eºit deðildir. Yukarýdaki bildirimde yalnýzca p1
char türden bir göstericidir. p2 ve p3 char türden göstericiler deðil char türden nesnelerdir.
Bu örnekte görüldüðü gibi, typdef anahtar sözcüðünün iºlevi #define öniºlemci komutuyla her
zaman yerine getirilemiyor.
Bir diziye iliºkin tür tanýmlamasý da yapýlabilir.
char isimdizi[20];
/* isimdizi char türden 20 elemanlý bir dizidir. */
typedef isimdizi[20]; /* isimdizi 20 elemanlý char türden bir dizi türüdür. */
isimdizi a, b, c;
/* a, b ve c herbiri 20 elemanlý char türden dizilerdir. */
Bir typedef ile birden fazla tür ismi tanýmlanabilir.
typedef unsigned int WORD, UINT;
Bu tür tanýmlamasýyla hem WORD hem de UINT unsigned int türünün yerine geçebilir.
WORD x, y;
...
UINT k, l;
10 elemanlý char türden gösterici dizisi için tür tanýmlamasýný ºöyle yapabiliriz:
typedef char *PSTRARRAY[10];
Bu tür tanýmlamasýndan sonra
PSTRARRAY s;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
288
Buy RoboPDF
TÜR TANIMLAMALARI ve typedef ANAHTAR SÖZCÜÐÜ
ile
char *s[10];
tamamen ayný anlama gelecektir.
Bir tür ismi baºka tür isimlerinin tanýmlanmasýnda da kullanýlabilir.
typedef unsigned int WORD;
typedef WORD UINT;
Tür isimleri geleneksel olarak büyük harfle yazýlýr ama bu C sentaksý açýsýndan bir zorunluluk
deðildir.
typedef Tür Tanýmlamalarýnýn Yapýlarla Birlikte Kullanýmý
C dilinde yapýlar ayrý bir veri türüdür. Bu tür önce derleyiciye tanýtýldýktan sonra, bu türe iliºkin
deðiºkenler (nesneler) tanýmlanabilir. Örneðin:
struct SAMPLE {
int a, b, c;
};
Yukarýdaki örnekte yeni bir veri türü yaratýlmýºtýr. Bu veri türünün ismi struct SAMPLE dýr.
(SAMPLE deðil) Yani bu veri türününden bir nesne tanýmlamak istersek tür ismi olarak struct
SAMPLE yazýlmalýdýr. (Oysa C++ dilinde yapý isimleri (structure tags) ayný zamanda türün de
ismidir ve struct anahtar sözcüðü olmadan kullanýldýðýnda bu türün ismi olarak derleyici
tarafýndan kabul görür.)
Yukarýdaki bildirimden sonra örneðin bir tanýmlama yapýlacak olsa
struct SAMPLE x;
ºeklinde yapýlmalýdýr. C dilinde bu tanýmlamanýn
SAMPLE x;
ºeklinde yapýlmasý derleme zamanýnda hata oluºturacaktýr. (Oysa C++ dilinde bu durum bir
hata oluºturmaz.)
ݺte struct anahtar sözcüðünün, yapý tanýmlamlamalarýnda yapý isminden önce kullanýlma
zorunluluðunu ortadan kaldýrmak için programcýlar, typedef anahtar sözcüðüyle kendi
bildirdikleri yapý (birlik, bit alanlarý, enum türleri ) türlerine iliºkin yeni tür isimleri oluºtururlar.
Bir yapý türüne iliºkin yeni bir tür isminin tanýmlanmasý 2 ayrý ºekilde yapýlabilir.
1. Önce yapý bildirimini yapmak, daha sonra bu yapý türünden bir tür ismi tanýmlamak.
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);
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
289
Buy RoboPDF
28 . BÖLÜM :
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 yapýlabilirdi.
typedef struct {
char name[30];
int no;
} PER;
PER y;
Ancak yukarýdaki son durumda artýk deðiºken bildiriminin yeni tanýmlanan tür ismiyle
yapýlmasý zorunluluk haline gelir.
Programcýlarýn çoðu yapý isimleriyle (tag) tür isimleri için farklý isimler bulmak yerine birkaç
karakter kullanarak aralarýnda iliºki kurarlar. Çok kullanýlan yöntemlerden biri, yapý isminin
baºýna bir alt tire konularak tür isminden ayrýlmasýdýr :
typedef struct _EMPLOYEE {
int no;
char name[30];
double fee;
} EMPLOYEE;
(Yukarýdaki örnekte tamamen ayný isim [mesela EMPLOYEE] hem yapý ismi hem de yeni tür
ismi olarak kullanýlabilir. Bu durum derleme zamanýnda bir hataya yol açmaz. )
typedef struct EMPLOYEE {
int no;
char name[30];
double fee;
} EMPLOYEE;
Çünkü türün eski ismi EMPLOYEE deðil struct EMPLOYEE dir. Yani struct EMPLOYEE türünün
ismi EMPLOYEE olarak typedef edilmiºtir ki bu durum bir sakýnca oluºturmaz.
windows.h içerisinde yapý ismi ile yeni tür isminin, yapý ismine tag sözcüðü eklenerek
birbirinden ayrýldýðýný görüyoruz.
typedef struct tagEMPLOYEE {
int no;
char name[30];
double fee;
} EMPLOYEE;
Baºlýk Dosyalarýnda Standart Olarak Bulunan Bazý typedef Bildirimleri
Temel C Kurdu boyunca bildirimi bizim tarafýmýzdan yapýlmamýº olan bazý tür isimlerini
kullandýk. typedef anahtar sözcüðü ile ilgili öðrendiklerimizden sonra bu tür isimlerinin ne
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
290
Buy RoboPDF
TÜR TANIMLAMALARI ve typedef ANAHTAR SÖZCÜÐÜ
olduklarýný daha iyi anlayabiliriz. size_t tür ismi ile dinamik bellek fonksiyonlarý ile çalýºýrken
karºýlaºmýºtýk. Bu tür isminin bildirimi stdlib.h, alloc.h de diðer bazý baºlýk dosyalarý içinde
aºaðýdaki ºekilde yapýlmýºtýr.
typedef unsigned size_t;
Bu tür aslýnda gerçekte ne olduðu derleyicileri yazanlara býrakýlmýº olan bir türdür. size_t türü
sizeof operatörünün ürettiði deðerin türüdür. ANSI standartlarýnda bir çok fonksiyonun
parametrik yapýsý içerisinde size_t türü geçer. Örneðin malloc fonksiyonunun gerçek prototipi
alloc.h, mem.h baºlýk dosyalarýnýn içinde
void *malloc (size_t size);
biçiminde yazýlmýºtýr.
Yani malloc fonksiyonunun parametresi size_t türdendir ama bu türün gerçekte ne olduðu
derleyicileri yazanlara býrakýlmýºtýr. Ancak hemen hemen bütün derleyicilerde size_t unsigned
int olarak belirlenmiºtir.
size_t türü gibi aslýnda ne olduklarý derleyiciye býrakýlmýº olan (yani derleyici yazanlarýn
typedef bildirimlerini yapacaklarý) baºka tür isimleri de C standartlarý tarafýndan
tanýmlanmýºtýr.
size_t
(sizeof operatörünün ürettiði deðerin türü.) Derleyiciyi yazanlar unsigned int ya da
unsigned long türüne typedef ederler. (Bir zorunluluk olmasa da derleyicilerin hemen hemen
hepsinde unsigned int türü olarak tanýmlanmýºtýr.)
time_t
(time fonksiyonunun geri dönüº deðerinin türü, derleyiciyi yazanlar herhangi bir
scalar (birleºik olmayan) default veri türüne typedef edebilirler. (Bir zorunluluk olmasa da
derleyicilerin hemen hemen hepsinde long türü olarak tanýmlanmýºtýr.)
clock_t (clock fonksiyonunun geri dönüº deðerinin türü, derleyiciyi yazanlar herhangi bir skalar
(bileºik olmayan) default veri türüne typedef edebilirler. (Bir zorunluluk olmasý da
derleyicilerin hemen hemen hepsinde long türü olarak tanýmlanmýºtýr.)
ptrdiff_t (gösterici deðerlerine iliºkin fark deðeri türü, (Bir zorunluluk olmasý da derleyicilerin
hemen hemen hepsinde int türü olarak tanýmlanmýºtýr.)
typedef ile Bildirimi Yapýlan Tür Ýsimlerinin Faaliyet Alanlarý
typedef isimleri için de faaliyet alaný kurallarý geçerlidir. Blok içerisinde tanýmlanan bir
typedef ismi blok dýºýnda tanýnmaz.
func()
{
typedef int WORD;
...
}
int main()
{
WORD x;
...
return 0;
}
/* hata */
Yukarýdaki programda
WORD x;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
291
Buy RoboPDF
28 . BÖLÜM :
tanýmlamasýný gören derleyici bir hata mesajý üretecektir. Zira WORD türü yalnýzca func
fonksiyonunun ana bloðu içinde tanýnan ve anlamlandýrýlan bir veri türüdür. Bu bloðun dýºýnda
tanýnmamaktadýr.
C dilinde blok içinde yapýlan bildirimler, bloklarýn ilk iºlemi olmak zorunda olduðundan typedef
anahtar sözcüðüyle blok içinde yapýlan tür bildirimleri de bloklarýn ilk iºlemi olmak zorundadýr.
Aksi halde derleme zamanýnda hata oluºacaktýr.
Hemen her zaman typedef bildirimleri global olacak yapýlmaktadýr. Uygulamalarda typedef
bildirimleri genellikle, ya kaynak dosyanýn baºýnda ya da baºlýk dosyalarý içinde tanýmlanýr.
Bir typedef isminin ayný faaliyet alaný içinde (örneðin global düzeyde) özdeº olmayacak ºekilde
iki kere tanýmlanmasý derleme zamanýnda hata oluºturacaktýr :
typedef int WORD;
...
typedef long WORD; /* error */
typedef tanýmlamalarý ne amaçla kullanýlýr
1. Okunabilirliði artýrmak için. Bazý türlere onlarýn kullaným amaçlarýna uygun isimler verilirse
kaynak kodu inceleyen kiºiler kodu daha kolay anlamlandýrýr. Örneðin char türü genelde
karakter sabitlerinin atandýðý bir türdür. Yazýlacak bir kodda char türü yalnýzca bir byte’lýk
bir alan olarak kullanýlacaksa, yani karakter iºlemlerinde kullanýlmayacaksa aºaðýdaki gibi
bir tür tanýmlamasý yerinde olacaktýr.
typedef char BYTE;
...
BYTE x;
2. Yazým kolaylýðý saðlar. Karmaºýk pek çok tür ifadesi typedef sayesinde kolay bir biçimde
yazýlabilmektedir. Programý inceleyen kiºi karmaºýk operatörler yerine onu temsil eden yalýn
bir isimle karºýlaºýr.
typedef struct PERSON EMPLOYEE[100];
...
EMPLOYEE manager;
3. Tür tanýmlamalarý taºýnabilirliði artýrmak amacýyla da kullanýlýrlar. Tür tanýmlamalarý
sayesinde kullandýðýmýz fonksiyonlara iliºkin veri yapýlarý deðiºse bile kaynak programýn
deðiºmesi gerekmez. Örneðin, kullandýðýmýz kütüphanede birtakým fonksiyonlarýn geri
dönüº deðerleri unsigned int olsun. Daha sonraki uygulamalarýnda bunun unsigned long
yapýldýðýný düºünelim. Eðer programcý bu bu fonksiyonlara iliºkin kodlarda tür tanýmlamasý
kullanmýºsa daha önce yazdýðý kodlarý deðiºtirmesine gerek kalmaz, yalnýzca tür
tanýmlamasýný deðiºtirmek yeterlidir. Örneðin:
typedef unsigned int HANDLE;
...
HANDLE hnd;
hnd = GetHandle();
Burada GetHandle fonksiyonunun geri dönüº deðerinin türü sonraki uyarlamalarda
deðiºerek unsigned long yapýlmýº olsun. Yalnýzca tür tanýmlamasýnýn deðiºtirilmesi yeterli
olacaktýr:
typedef unsigned long HANDLE;
Baºka bir örnek :
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
292
Buy RoboPDF
TÜR TANIMLAMALARI ve typedef ANAHTAR SÖZCÜÐÜ
Bir C programýnda deðerleri 0 ile 50000 arasýnda deðiºebilecek olan sayaç deðiºkenler
kullanacaðýmýzý düºünelim. Bu amaç için long int türünü seçebiliriz, çünkü long int türü
bilindiði gibi 2.147.483.647 ye kadar deðerleri tutabilir. Ama long türü yerine int türünü
kullanmak, aritmetik iºlemlerin daha hýzlý yapýlabilmesi açýsýndan tercih edilecektir. Ayrýca
int türden olan deðiºkenler bellekte daha az yer kaplayabilecektir.
int türünü kullanmak yerine bu amaç için kendi tür tanýmlamamýzý yapabiliriz :
typedef int SAYAC;
SAYAC a, b, c;
Kaynak kodun int türünün 16 bit uzunluðunda olduðu bir sistemde derlenmesi durumunda
tür tanýmlama ifadesini deðiºtirebiliriz:
typedef long SAYAC;
Bu
teknikle
taºýnabilirliðe
iliºkin
bütün
problemlerimizin
çözülmüº
olacaðýný
düºünmemeliyiz. Örneðin SAYAC türünden bir deðiºken printf ya da scanf fonksiyonu
çaðýrýmlarýnda arguman olarak kullanýlmýº olabilir :
typedef int SAYAC;
...
SAYAC a, b, c;
...
scanf("%d%d%d", &a, &b. &c);
...
printf("%d %d %d", a, b, c);
Yukarýdaki ifadelerde a. b. c deðiºkenleri SAYAC türünden (int türden) tanýmlanmýºlardýr.
printf ve scanf fonksiyonlarýnýn çaðýrma ifadelerinde de bu deðiºkenlere iliºkin format
karakterleri doðal olarak %d seçilmiºtir. Ancak SAYAC türünün long türü olarak
deðiºtirilmesi durumunda printf ve scanf fonkksiyonlarýnda bu türden deðiºkenlerin
yazdýrýlmasýnda kullanýlan format karakterlerinin de %d yerine %ld olarak deðiºtirilmesi
gerekecektir.
typedef Ýle Gösterici Türlerine Ýsim Verilmesi
typedef anahtar sözcüðü ile gösterici türlerine isim verilmesinde dikkat etmemiz gereken bir
nokta var. Belirleyiciler (specifiers) konusunda incelediðimiz gibi C dilinde aºaðýdaki gibi bir
tanýmlama yapýldýðýnda
const int *ptr;
ptr göstericisinin gösterdiði yerdeki nesne deðiºtirilemez. Yani
*ptr = 10;
gibi bir atama yapýlmasý durumunda derleme zamanýnda hata oluºacaktýr.
Ancak tanýmlama
int *const ptr;
ºeklinde yapýlýrsa ptr göstericisinin gösterdiði yerdeki nesnenin deðeri deðiºtirilebilir, ama ptr
göstericisinin içindeki adres deðiºtirilemez, yani
ptr = (int *) 0x1F00;
gibi bir atama yapýlmasý durumunda derleme zamanýnda hata oluºur.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
293
Buy RoboPDF
28 . BÖLÜM :
typedef int * IPTR;
gibi bir tür tanýmlanarak
const IPTR p;
ºeklinde bir tanýmlama yapýldýðýnda, p göstericisinin deðeri deðiºtirilemez, p göstericisinin
gösterdiði yerdeki nesnenin deðeri deðiºtirilebilir. (yani *p nesnesine atama yapýlabilir.) Baºka
bir deyiºle
const IPTR p;
deyimi ile
int *const ptr;
deyimi eºdeðerdir.
Windows iºletim sistemi altýnda çalýºacak C ya da C++ programlarýnýn yazýlmasýnda typedef
sýklýkla kullanýlmaktadýr. windows.h isimli baºlýk dosyasýnda temel veri türlerinin çoðuna
typedef'le yeni isimler verilmiºtir. Windows programlamada Windows.h dosyasý kaynak koda
dahil edilmelidir. Bu dosyanýn içerisinde API fonksiyonlarýnýn prototipleri, çeºitli yapý bildirimleri,
typedef isimleri, önemli sembolik sabitler bulunmaktadýr.
windows.h Ýçerisinde Tanýmlanan Typedef Ýsimleri
typedef int BOOL
Bu türle iliºkili 2 sembolik sabit de tanýmlanmýºtýr.
#define FALSE
#define TRUE
0
1
BOOL türü, özellikle fonksiyonlarýn geri dönüº deðerlerinde karºýmýza çýkar. Bu durum
fonksiyonun baºarýlýysa 0 dýºý bir deðere, baºarýsýzsa 0 deðerine geri döneceði anlamýna gelir.
Baºarý kontrolü, 1 deðeriyle karºýlaºtýrýlarak yapýlmamalýdýr.
Aºaðýdaki typedef isimleri, iºaretsiz 1 byte, 2 byte ve 4 byte tam sayýlarý temsil eder.
typedef
typedef
typedef
typedef
unsigned
unsigned
unsigned
unsigned
char BYTE;
short WORD;
long int DWORD;
int UINT;
Göstericilere iliºkin typedef isimleri P harfiyle baºlar. LP uzak göstericileri belirtmek için ön ek
olarak kullanýlmaktadýr. Win16 sistemlerinde uzak ve yakýn gösterici kavramlarý vardý.
Dolayýsýyla o zamanlar, P ön ekli göstericiler, yakýn göstericileri; LP önekli göstericiler ise uzak
göstericileri temsil ediyordu. Fakat Win32 sistemlerinde yakýn ve uzak gösterici kavramlarý
yoktur. Bu durumda, P önekli göstericilerle LP önekli göstericiler arasýnda hiçbir fark yoktur.
Ancak, Win16’daki alýºkanlýkla hala LP önekli typedef isimleri kullanýlmaktadýr. Windows.h
içerisinde her ihtimale karºý (Win16 programlarý çalýºabilsin diye) near ve far sözcükleri
aºaðýdaki gibi silinmiºtir.
#define far
#define near
typedef char near *PSTR;
typedef char far *LPSTR;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
294
Buy RoboPDF
TÜR TANIMLAMALARI ve typedef ANAHTAR SÖZCÜÐÜ
PSTR ya da LPSTR Win32 sistemlerinde tamamen ayný anlama gelir ve char türden adres
türünü belirtir.
typedef char *PSTR;
typedef char *LPSTR;
Göstericilerde const’luk P ya da LP’den sonra C ekiyle belirtilir. Örneðin;
typedef const char *PCSTR;
typedef const char *LPCSTR;
Klasik typedef isimlerinin hepsinin gösterici karºýlýklarý da vardýr. Bütün gösterici türleri, Win16
uyumlu olmasý için P ve LP önekleriyle ayrýca bildirilmiºtir.
typedef
typedef
typedef
typedef
BYTE *PBYTE;
WORD *PWORD;
const BYTE *PCBYTE;
const DWORD *LPCDWORD;
C’nin doðal türlerinin hepsinin büyük harf normal, adres ve const adres versiyonlarý vardýr.
typedef long
LONG;
typedef int INT;
typedef char CHAR;
Windows programlamada H ile baºlayan, handle olarak kullanýlan pek çok typede ismi vardýr.
Bu typedef isimlerinin hepsi void * türündendir. Örneðin:
typedef void
typedef void
*HWND;
*HICON;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
295
Buy RoboPDF
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
Buy RoboPDF
BÝRLÝKLER
29 . BÖLÜM : BÝRLÝKLER
Programcý tarafýndan tanýmlanan (user defined) ve bileºik bir veri yapýsý olan birlikler yapýlara
çok benzer. Birliklerin de kullanýlabilmesi için, yani bir birlik türünden nesnelerin
tanýmlanabilmesi için önce birliðin bildirimi yapýlmalýdýr. Birlik bildirimleri ayný yapý bildirimleri
gibi yapýlýr. Tek fark struct anahtar sözcüðü yerine union anahtar sözcüðünün kullanýlmasýdýr.
Birlik bildirimlerinin genel ºekli ºöyledir:
union [birlik ismi] {
tür <birlik elemaný>;
tür <birlik elemaný>;
tür <birlik elemaný>;
...
};
Örneðin;
union DWORD {
unsigned char byte;
unsigned int word;
unsigned long dword;
};
Diðer bir örnek:
union DBL_FORM {
double n;
unsigned char s[8];
};
Birlik Deðiºkenlerinin Tanýmlanmasý
Birlik deðiºkenlerinin tanýmlanmasý ayný yapý deðiºkenlerinde olduðu gibidir. Týpký yapýlarda
olduðu gibi birliklerde de bellekte yer ayýrma iºlemi bildirim ile deðil tanýmlama iºlemi ile
yapýlmaktadýr. Birlik deðiºkeni tanýmlamalarýnýn yapý bildirimi tanýmlamalarýndan tek farký
struct anahtar sözcüðü yerine union anahtar sözcüðünün kullanýlmasýdýr. Örnekler :
union DWORD a, b;
ile a ve b union DWORD türünden iki deðiºken olarak tanýmlanmýºlardýr.
union DBL_FORM x, y;
x ve y union DBL_FORM türünden iki deðiºkendir. Yine týpký yapýlarda olduðu gibi birliklerde de
bildirim ile tanýmlama iºlemi birlikte yapýlabilir :
union DBL_FORM {
double n;
unsigned char s[8];
} a, b, c;
Bu durumda a, b ve c deðiºkenlerinin faaliyet alanlarý birlik bildiriminin yapýldýðý yere baðlý
olarak yerel ya da global olabilir.
Birlik elemanlarýna da yapý elemanlarýnda olduðu gibi nokta operatörüyle eriºilir. Örneðin
yukarýdaki tanýmlama dikkate alýnýrsa a.n birliðin double türünden ilk elemanýný belirtmektedir.
Benzer biçimde birlik türünden göstericiler de tanýmlanabilir. Ok operatörü ile yine yapýlarda
olduðu gibi birliklerde de gösterici yoluyla birlik elemanlarýna ulaºýlabilir. Örneðin:
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
297
Buy RoboPDF
29 . BÖLÜM :
union DWORD *p;
...
printf("%d", p->word);
p->word ifadesi ile p adresinde birlik nesnesinin word elemanýna eriºilmektedir.
Genel olarak ºunlarý söyleyebiliriz: Yapýlarla birliklerin bildirilmesi, tanýmlanmasý ve yapý
deðiºkenlerinin kullanýlmasý tamamen ayný biçimde yapýlmaktadýr. Ýkisi arasýnda tek fark yapý
ve birlik elemanlarýnýn bellekteki organizasyonunda ortaya çýkar. Birlik elemanlarýnýn bellekteki
organizasyonu konusuna deðinmeden önce bir
byte’dan daha uzun bilgilerin bellekteki
görünümleri üzerinde duralým.
Sayýlarýn Bellekteki Yerleºimleri
Bir byte’dan daha büyük olan sayýlarýn belleðe yerleºim biçimi kullanýlan mikroiºlemciye göre
deðiºebilir. Bu nedenle sayýlarýn bellekteki görünümleri taºýnabilir bir bilgi deðildir.
Mikroiºlemciler iki tür yerleºim biçimi kullanabilirler:
Düºük anlamlý byte deðerleri belleðin düºük anlamlý adresinde bulunacak
biçimde. (little endian)
80x86 ailesi Intel iºlemcileri bu yerleºim biçimini kullanýr. Bu iºlemcilerin kullanýldýðý sistemlere
örneðin
int x = 0x1234;
biçimindeki bir x deðiºkeninin bellekte 1FC0 adresinden baºlayarak yerleºtiðini varsayalým:
1AOO
1A01
...
34
12
...
düºük anlamlý byte
yüksek anlamlý byte
ªekilden de görüldüðü gibi x deðiºkenini oluºturan sayýlar düºük anlamlý byte deðeri (34H)
düºük anlamlý bellek adresinde (1A00H) olacak biçimde yerleºtirilmiºtir. ªimdi aºaðýdaki kodu
inceleyiniz :
...
unsigned long a = 0x12345678;
unsigned int *b;
b = (unsigned int*) &a;
printf(“%x\n”, *b);
ile eklrana hex sistemde 5678 sayýlarý basýlýr. Aºaðýdaki ºekli inceleyiniz. b deðiºkeninin 1B10
adresinden baºlayarak yerleºtirildiði varsayýlmýºtýr :
1B10
1B11
1B12
1B13
...
...
78
56
34
12
1B10 *b
Düºük anlamlý byte deðerleri, belleðin yüksek anlamlý adresinde bulunacak
ºekilde (big endian)
Motorola iºlemcileri bu yerleºim biçimini kullanýr.
iºlemcilerinin kullanýldýðý bir sistemde yazýlmýº olsaydý :
Örneðin
yukarýdaki
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
kod
Motorola
298
Buy RoboPDF
BÝRLÝKLER
unsigned long a = 0x12345678;
unsigned int *b;
b = (unsigned int*) &a;
printf(“%x\n”, *b);
ekrana 1234 basýlýrdý.
1B10
1B11
1B12
1B13
...
...
12
34
56
78
1B10 *b
Aºaðýdaki kod kullanýlan 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 Elemanlarýnýn Bellekteki Organizasyonu
Birlik deðiºkenleri için birliðin en uzun elemaný kadar yer ayrýlýr. Birlik elemanlarýnýn hepsi ayný
orjinden baºlayacak ºekilde belleðe yerleºirler. Örneðin :
union DWORD {
unsigned char byte;
unsigned int word;
unsigned long dword;
};
...
union DWORD a;
bildirimi ile a deðiºkeni için 4 byte yer ayrýlacaktýr. Çünkü a deðiºkeninin dword elemaný 4 byte
ile birliðin en uzun elemanýdýr.
Birlik bir dizi içeriyorsa dizi tek bir eleman olarak alýnýr. Örneðin
A00
a.byte
1A01
1A02
1A03
a.word
a.dword
union DBL_FORM {
double n;
unsigned char s[8];
};
...
union DBL_FORM x;
tanýmlamasý ile x deðiºkeni için ne kadar yer ayýrýlacaktýr? DBL_FORM birliðinin iki elemaný
vardýr. Birincisi 8 byte uzunluðunda bir karakter dizisi, ikincisi de 8 byte uzunluðunda double
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
299
Buy RoboPDF
29 . BÖLÜM :
türden bir deðiºkendir. Ýki uzunluk da ayný olduguna göre x için 8 byte yer ayýrýlacaðýný
söyleyebiliriz:
x
...
s[0] x.n
s[1]
s[2]
s[3]
s[4]
s[5]
s[6]
s[7]
...
Buna göre DBL_FORM X;
...
X.n = 10.2;
ile x.S[0], x.s[1], x.s[2], ....x.s[7] sýrasýyla double elemanýnýn byte deðerlerini göstermektedir.
Birlik elemanlarýnýn ayný orjinden, yani ayný adresten baºlayarak yerleºtirilmesi bir elemanýný
deðiºtirince diðer elemanlarýnýn da içeriðinin deðiºeceði anlamýna gelir. Zaten birliklerin
kullanýlmasýnýn asýl amacý da budur. Birlik elemaný olarak yapýlarýn kullanýlmasý uygulamada en
sýk karºýlaºýlan durumdur. Örneðin :
struct WORD {
unsigned char low_byte;
unsigned char high_byte;
};
union WORD_FORM {
unsigned int x;
struct WORD y;
};
bildirimlerinden sonra union WORD_FORM türünden bir birlik tanýmlanýrsa :
union WORD_FORM wf;
bu birliðin alçak (low_byte) ve yüksek (high_byte) anlamlý byte deðerlerine ayrý ayrý eriºebiliriz
ya da onu bir bütün olarak kullanabiliriz :
Yani intel iºlemcilerinin bulunduðu 16 bit sistemlerde :
wf.y.low_byte = 0x12;
wf.y.high_byte = 0x34;
iºlemlerinden sonra;
printf(“%x\n”, wf.x);
ile 3412 sayýsýný ekrana yazdýracaktýr. (Motorola iºlemcilerinde belleðin düºük anlamlý
bölgesinde düºük anlamlý byte deðeri olacaðýna göre sayýnýn ters olarak görülmesi gerekir.
Birlik elemanlarýnýn bellekte ayný orjinden baºlanarak yerleºtirildiðini aºaðýdaki kod parçasýndan
da rahatlýkla görebiliriz :
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
300
Buy RoboPDF
BÝRLÝKLER
Birlik Nesnelerine Ýlk Deðer Verilmesi
ANSI ve ISO standartlarýna göre birliknes nelerinin yalnýzca ilk elemanlarýna deðer verilebilir.
Eðer bir birlik nesnesinin birden fazla elemanýna ilk deðer verilmeye çalýºýlýrsa derleme
zamanýnda error oluºacaktýr:
union DWORD {
unsigned char byte;
unsigned int word;
unsigned long dword;
} x = {'m'};
union DWORD y = {'a', 18, 24L}; /* error */
Birlikler Neden Kullanýlýr
Birlikler iki amaçla kullanýlabilir. Birincisi yer kazancý saðlamak içindir. Birlik kullanarak farklý
zamanlarda kullanýlacak birden fazla deðiºken için ayrý ayrý yer ayýrma zorunluluðu ortadan
kaldýrýlýr. Örneðin bir hediyelik eºya kataloð ile 3 deðiºik ürünün satýldýðýný düºünelim: kitap,
tshort ve saat. Her bir ürün için bir stok numarasý, fiyat bilgisi ve tip bilgisinin dýºýnda ürüne
baðlý olarak baºka özelliklerine de sahip olduðunu düºünelim:
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;
};
Yukarýdaki bildirimde urun_tipi elemaný yalnýzca KITAP, TSHORT ya da SAAT olabilecektir.
(Bunlarýn sembolik sabit olarak tanýmlandýðýný düºünelim.) Yukarýda bildirilen yapý ürünlerin
bütün özelliklerini tutabilmekle birlikte ºöyle bir dezavantajý vardýr :
Eðer ürün tipi KITAP deðil ise isim[20], yazar[30] ve sayfa_sayisi elemanlarý hiç
kullanýlmayacaktýr. Yine ürün tipi TSHORT deðil ise desen[20], renk, size elemanlarý hiç
kullanýlmayacaktýr.
Ama katalog yapýsýnýn içine birlikler yerleºtirirsek yer kazancýmýz olacaktýr:
struct katalog {
int stok_no;
float fiyat;
int urun_tipi
union {
struct {
char isim[20];
char yazar[20];
int sayfa_sayisi;
} kitap;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
301
Buy RoboPDF
29 . BÖLÜM :
};
struct {
char desen[20];
int renk;
int size;
} tshort;
struct {
char isim[20];
int model;
} saat;
} cins;
Birlik kulanýmýnýn ikinci nedeni herhangi bir veri türünün parçalarý üzerinde iºlem yapmak ya da
parçalar üzerinde iºlem yaparak bir veri türününden bütününü oluºturmaktýr. Bunun için int
türden bir sayýnýn byte deðerlerini ayrýºtýrma örneðini yineleyebiliriz :
struct WORD {
unsigned char low_byte;
unsigned char high_byte;
};
union WORD_FORM {
unsigned int x;
struct WORD y;
};
union word_form wf;
Tanýmlamalarýndan sonra wf.x elemanýna deðer atadýðýmýzda wf.y.low_byte ve wf.y.high_byte
ile yüksek ve alçak anlamlý byte deðerleri üzerine kolaylýkla iºlem yapabiliriz.
Birliklerin Karýºýk Veri Yapýlarýnda Kullanýlmasý
Birlikleri kullanarak, elemanlarý farklý türden olan diziler oluºturabiliriz.
Belirli deðerleri bir dizi içinde tutmak zorunda olduðumuzu düºünelim. Ancak dizi elemanlarý
int, long, double türlerinden olabilsin. Örneðin dizinin, herhangi bir elemanýna ulaºtýðýmýzda
bu eleman int ise onu int olarak, long ise long olarak ve double ise double olarak (bilgi
kaybý olmaksýzýn) kullanabilelim.
Diziyi double türü ile tanýmlarsak, dizi elemanlarýna atama yaptýðýmýz zaman, otomatik tür
dönüºümü sonucunda bütün elemanlar double türüne çevrileceðinden dizi elemanlarýnýn tür
bilgisini kaybetmiº olurduk.
Ancak aºaðýdaki ºekilde bir birlik oluºturabiliriz :
union DEGER {
int i;
long l;
double d;
};
union DEGER türünden her bir nesne bellekte, en uzun elemaný kadar, yani 8 byte yer
kaplayacak, ve her bir eleman (member) ayný adresten baºlayacaktýr.
ªimdi double türden bir dizi açmaktansa union DEGER türünden bir dizi açabiliriz. Dizinin her
bir elemanýnýn, istediðimiz alt elemanýna deðer atamasý yapabiliriz :
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
302
Buy RoboPDF
BÝRLÝKLER
main()
{
union DEGER s[100];
}
s[0].i = 3;
s[1].d = 6.
s[2].l = 12L
...
/* s[0] int türden bir deðeri tutuyor */
/* s[1] double türden bir deðeri tutuyor */
/* s[2] long türden bir deðeri tutuyor */
Hangi türden bir deðer tutmak istiyorsak, bu deðeri s dizisinin elemaný olan bir union DEGER
nesnesinin ilgili alt elemanýnda tutuyoruz. Ancak hala ºöyle bir eksiðimiz var : Örneðin dizinin
17. elemanýný gerçek türüyle ve deðeriyle kullanmak istiyoruz. 17. eleman nesnesininin hangi
türden olduðunu nereden bileceðiz? Hangi dizi elemanýnýn hangi türden deðer için kullanýldýðý
bilgisini de bir ºekilde saklamalýyýz.
Bunun için en iyi yöntem bir yapý bildirimi yapmak, ve DEGER birliðini de bu yapýnýn alt elemaný
olarak bildirmektir. Yapýnýn baska bir elemaný da birliðin hangi elemanýnýn kullanýlacagý bilgisini
tutacaktýr :
#define INT
0
#define LONG
1
#define DOUBLE 2
...
struct KARTIP {
char type;
union DEGER deger;
};
ªimdi struct KARTIP türünden bir dizi tanýmlayabiliriz:
...
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;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
303
Buy RoboPDF
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
Buy RoboPDF
BÝTSEL OPERATÖRLER
30 . BÖLÜM : BÝTSEL OPERATÖRLER
Bitsel operatörler (Bitwise operators) bir tamsayýnýn bitleri üzerinde iºlem yapan operatörlerdir,
daha çok sistem programlarýnda kullanýlýrlar. Bitsel operatörlerün ortak özellikleri operandlarý
olan tamsayýlarý bir bütün olarak deðil,
bit bit ele alarak iºleme sokmalarýdýr. Bitsel
operatörlerin operandlarý tamsayý türlerinden olmak zorundadýr. Operandlarý tamsayý
türlerinden birinden deðilse derleme zamanýnda hata oluºur.
C dilinde toplam 11 tane bitsel operatör vardýr. Bu operatörler, kendi aralarýndaki öncelik
sýrasýna göre, aºaðýdaki tabloda verilmiºtir:
2
5
8
9
10
14
~
<<
>>
&
^
|
<<=
>>=
&=
^=
|=
bitsel deðil
bitwise not
bitsel sola kaydýrma
bitwise left shift
bitsel saða kaydýrma
bitwise right shift
bitsel ve
bitwise and
bitsel özel veya
bitwise exor
bitsel veya
bitwise or
bitsel
iºlemli
atama bitwise
compound
operatörleri
operators
assignment
Yukarýdaki operatörler içinde yalnýzca bitsel Deðil (bitwise not) operatörü önek konumunda tek
operand alan (unary prefix) bir operatördür. Diðer bütün bitsel operatörler iki operand alýrlar
ve operandlarýnýn arasýnda bulunurlar. (binary infix)
ªimdi bu operatörleri tek tek tanýyalým :
Bitsel Deðil Operatörü
Diðer tüm tek operand alan operatörler gibi operatör öncelik tablosunun ikinci seviyesindedir.
Yan etkisi yoktur. (side effect) Operandý bir nesne ise, bu nesnenin bellekteki deðerini
deðiºtirmez. Ürettiði deðer, operandý olan tamsayýnýn bitleri üzerinde 1'e tümleme iºlemi
yapýlarak elde edilen deðerdir. Yani operandý olan ifade deðerinin 1 olan bitleri 0, 0 olan bitleri
1 yapýlarak deðer ü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 Kaydýrma Operatörleri (bitwise shift operators)
Ýki adet bitsel kaydýrma operatörü vardýr:
Bitsel saða kaydýrma operatörü >> (bitwise right shift)
Bitsel sola kaydýrma operatörü << (bitwise left shift)
Her iki operatör de operatör öncelik tablosunun 5. seviyesinde bulunmaktadýr. (Dolayýsýyla bu
operatörlerin önceliði tüm aritmetik operatörlerden daha aºaðýda fakat karºýlaºtýrma
operatörlerinden daha yukarýdadýr. Bitsel kaydýrma operatörleri binary infix operatörlerdir. (Ýki
operand alan araek konumundaki operatörlerdir.)
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
305
Buy RoboPDF
30 . BÖLÜM :
Bitsel sola kaydýrma operatörünün ürettiði deðer soldaki operandý olan tamsayýnýn saðdaki
operandý olan tamsayý kadar sola kaydýrýlmýº biçimidir. Menzil dýºýna çýkan bitler için sayýnýn
saðýndan 0 biti ile besleme yapýlýr. Ö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 sayýyý sola bitsel olarak 1 kaydýrmakla o sayýnýn ikiyle çarpýlmýº deðeri elde edilir. Bir sayýyý
saða bitsel olarak 1 kaydýrmakla o sayýnýn ikiye bölünmüº deðeri elde edilir.
Bitsel kaydýrma operatörlerinin yan etkileri yoktur. Yani soldaki operandlarý bir nesne ise, bu
nesnenin bellekteki deðerinði deðiºtirmezler. Kaydýrma sonucu soldaki nesnenin deðeri
deðiºtirilmek isteniyorsa daha sonra inceleyeceðimiz bitsel iºlemli atama operatörleri
kullanýlmalýdýr. (>>= ya da <<=)
Bitsel saða kaydýrma operatörünün ürettiði deðer soldaki operandý olan tamsayýnýn saðdaki
operandý olan tamsayý kadar saða kaydýrýlmýº biçimidir. Soldaki operand iºaretsiz (unsigned)
ya da pozitif iºaretli (signed) bir tamsayý ise menzil dýºýna çýkan bitler yerine sayýnýn solundan
besleme 0 biti ile yapýlmasý C standartlarý tarafýndan garanti altýna alýnmýºtýr. Saða kaydýrýlacak
ifadenin negatif deðerli, iºaretli bir tamsayý türünden olmasý durumunda menzil dýºýna çýkan
bitler için soldan yapýlacak beslemenin 0 ya da 1 bitleriyle yapýlmasý uygulama baðýmlýdýr.
(implementation depended). Yani derleyiciyi yazanlar bu durumda sayýnýn iºaretini korumak
için soldan yapýlacak beslemeyi 1 biti ile yapabilecekleri gibi, sayýnýn iºaretini korumayý
düºünmeksizin 0 biti ile de yapabilirler. ݺaretli negatif bir tamsayýnýn bitsel saða kaydýrýlmasý
taºýnabilir bir özellik olmadýðýndan dikkatli olunmalýdýr.
#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 Operatörü (bitwise and)
Operatör öncelik tablosunun 8. seviyesindedir. Öncelik yönü soldan saðadýr. Yan etkisi yoktur,
operandlarý nesne gösteren bir ifade ise bellekteki deðerlerini deðiºtirmez. Deðer üretmek için
operandý olan tamsayýlarýn karºýlýklý bitlerini Ve iºlemine tabi tutar. Ve iºlemine ait doðruluk
tablosu aºaðýda tekrar verilmektedir:
x
y
x&y
1
1
1
1
0
0
0
1
0
0
0
0
Bitsel ve operatörünün ürettiði
sokulmasýyla elde edilen deðerdir.
deðer
operandlarýnýn
karºýlýklý
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
bitlerinin
ve
iºlemine
306
Buy RoboPDF
BÝTSEL OPERATÖRLER
#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 iºleminde etkisiz elemandýr.
0 biti bitsel ve iºleminde yutan elemandýr.
Bitsel Özel Veya Operatörü (bitwise exor)
Operatör öncelik tablosunun 9. seviyesindedir. Öncelik yönü soldan saðadýr. Yan etkisi yoktur,
operandlarý nesne gösteren bir ifadeyse bellekteki deðerlerini deðiºtirmez. Deðer üretmek için
operandý olan tamsayýlarýn karºýlýklý bitlerini özel veya (exclusive or) iºlemine tabi tutar. Bitsel
özel veya iºlemine iliºkin doðruluk tablosu aºaðýda verilmektedir:
x
1
1
0
0
y
1
0
1
0
x^y
0
1
1
0
Yukarýdaki tablo ºöyle özetlenebilir. Operandlardan ikisi de ayný deðere sahip ise üretilen deðer
0 olacak, operandlardan biri diðerinden farklý ise üretilen deðer 1 olacaktýr.
#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 sayýya arka arka arkaya ayný deðerle özel veya iºlemi yapýlýrsa ayný deðer 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;
}
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
307
Buy RoboPDF
30 . BÖLÜM :
Bazý ºifreleme algoritmalarýnda özel veya iºleminin bu özelliðinden faydalanýlmaktadýr.
bitsel exor operatörü tamsayý türlerinden iki deðiºkenin deðerlerinin, geçici bir deðiºken
olmaksýzýn swap edilmesinde (deðerlerinin deðiºtirilmesinde) de kullanýlabilir. Aºaðýdaki
programda x ve y deðiºkenlerini deðerleri bitsel exor operatörünün kullanýlmasýyla 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 Operatörü (bitwise or operator)
Operatör öncelik tablosunun 10. seviyesindedir. Öncelik yönü soldan saðadýr. Yan etkisi
yoktur, operandlarý nesne gösteren bir ifade ise bellekteki deðerlerini deðiºtirmez. Deðer
üretmek için operandý olan tamsayýlarýn karºýlýklý bitlerini veya iºlemine tabi tutar. Veya
iºlemine ait doðruluk tablosu aºaðýda verilmektedir:
x
1
1
0
0
y
1
0
1
0
x|y
1
1
1
0
Bitsel veya operatörünün ürettiði deðer operandlarýnýn karºýlýklý bitlerinin veya iºlemine
sokularak elde edilen deðerdir.
#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 iºleminde etkisiz elemandýr.
1 biti bitsel ve iºleminde yutan elemandýr.
Bitsel Operatörlere Ýliºkin ݺlemli Atama Operatörleri
Bitsel deðil operatörünün dýºýnda tüm bitsel operatörlere iliºkin iºlemli atama operatörleri
vardýr. Daha önce de söylendiði gibi bitsel operatörlerin yan etkileri (side effect) yoktur. Bitsel
operatörler operandlarý olan nesnelerin bellekteki deðerlerini deðiºtirmezler. Eðer operandlarý
olan nesnelerin deðerlerinin deðiºtirilmesi isteniyorsa bu durumda iºlemli atama operatörleri
kullanýlmaktadýr.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
308
Buy RoboPDF
BÝTSEL OPERATÖRLER
x
x
x
x
x
=
=
=
=
=
x
x
x
x
x
<< y yerine
>> y yerine
&y
yerine
^y
yerine
| y yerine
x <<= y
x >>= y
x &= y
x ^= y
x |= y
kullanýlabilir.
Bitsel Operatörlerin Kullanýlmasýna Ýliºkin Bazý Temalar
Bitsel operatörlerin kullanýlmasýna daha çok sistem programlarýnda raslanýr. Sistem
programlarýnda bir sayýnýn bitleri üzerinde bazý iºlemler yapýlmasý sýklýkla gerekli olmaktadýr.
Aºaðýda bitsel düzeyde yapýlan iºlemlerden örnekler verilmektedir.
Bir Sayýnýn Belirli Bir Bitinin 1 Yapýlmasý (birlenmesi ) (set a bit / turn a bit
on)
Buna sayýnýn belirli bir bitinin set edilmesi de denebilir. Bir sayýnýn belirli bir bitini set etmek
için, söz konusu sayý, ilgili biti 1 olan ve diðer bitleri 0 olan bir sayýyla veya iºlemine tabi
tutulmalýdýr. Çünkü bitsel veya iºleminde 1 yutan eleman 0 ise etkisiz elemandýr.
Aºaðýdaki örnekte bir sayýnýn 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 sayýnýn herhangi bir bitini set edecek bir ifadeyi ºu ºekilde
yazabiliriz:
x |=1 << k
Bir Sayýnýn Belirli Bir Bitinin 0 Yapýlmasý (sýfýrlanmasý) (clear a bit / turn the
bit off)
Buna sayýnýn belirli bir bitinin temizlenmesi de denebilir. Bir sayýnýn belirli bir bitini sýfýrlamak
için, söz konusu sayý, ilgili biti 0 olan ve diðer bitleri 1 olan bir sayýyla bitsel ve iºlemine tabi
tutulmalýdýr. Çünkü bitsel ve iºleminde 0 yutan eleman 1 ise etkisiz elemandýr. Bir bitin
sýfýrlanmasý için kullanýlacak bu sayýya maske (mask) denir.
Aºaðýdaki örnekte bir sayýnýn 5. biti sýfýrlanmaktadýr.
#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();
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
309
Buy RoboPDF
30 . BÖLÜM :
}
return 0;
x bir tamsayý olmak üzere, bir sayýnýn herhangi bir bitini set edecek bir ifadeyi ºu ºekilde
yazabiliriz
x &= ~(1 << k);
Bir Sayýnýn Belirli Bir Bitinin Deðerinin Test Edilmesi (0 mý 1 mi)
Bir sayýnýn belirli bir bitinin 0 mý 1 mi oldugunun öðrenilmesi için, söz konusu sayý, if deyiminin
koºul ifadesi olarak (if parantezi içinde) ilgili biti 1 olan ve diðer bitleri 0 olan bir sayýyla bitsel
ve iºlemine tabi tutulmalýdýr. Çünkü bitsel ve iºleminde 0 yutan eleman 1 ise etkisiz elemandýr.
programýn akýºý if deyiminin doðru kýsmýna giderse, ilgili bitin 1, yanlýº kýsmýna gider ise ilgili
bitin 0 oldugu sonucu çýkarýlacaktýr.
x bir tamsayý olmak üzere, bir sayýnýn herhangi bir bitinin 1 ya da 0 olduðunu anlamak için
aºaðýdaki ifadeyi yazabiliriz.
if (x & 1 << k)
/* k. bit 1 */
else
/* k. bit 0 */
Bir Sayýnýn Belirli Bir Bitini Ters Çevirmek (toggle)
Bazý uygulamalarda bir sayýnýn belirli bir bitinin deðerinin deðiºtirilmesi istenebilir. Yani söz
konusu bir 1 ise 0 yapýlacak, söz konusu bit 0 ise 1 yapýlacaktýr. Bu amaçla bitsel özel veya
operatörü kullanýlýr. Bitsel özel veya operatöründe 0 biti etkisiz elemandýr. Bir sayýnýn k.bitinin
deðerini deðiºtirmek için, sayý, k.biti 1 diðer bitleri 0 olan bir sayý ile bitsel özel veya iºlemine
tabi tutulur.
x bir tamsayý olmak üzere, bir sayýnýn herhangi bir bitinin deðerini deðiºtirmek için aºaðýdaki
ifadeyi yazabiliriz.
x ^= 1 << k;
Bir tamsayýnýn belirli bitlerini sýfýrlamak için ne yapabiliriz? Örneðin int türden bir nesnenin 7.,
8. ve 9.bitlerini sýfýrlamak isteyelim (tabi diðer bitlerini deðiºtirmeksizin). 7., 8. ve 9. bitleri 0
olan diðer bitleri 1 olan bir sayý ile bitsel ve iºlemine tabi tutarýz. Örneðin 16 bitlik int sayýlarýn
kullanýldýðý bir sistemde bu sayý aºaðýdaki bit düzenine sahip olacaktýr.
1111 1100 0111 1111
(bu sayý 0xFC7F deðilmidir?)
x &= 0xFC7F;
Bu gibi tamsayýlarýn bitleri üzerinde yapýlan iºleri fonksiyonlara yaptýrmaya ne dersiniz?
void clearbits(int *ptr, int startbit, int endbit);
clearbits fonksiyonu adresi gönderilen ifadenin
startbit ve endbit aralýðýndaki bitlerini
sýfýrlayacaktýr.
Örneðin x isimli int türden bir nesnenin 7. 8. 9. bitlerini sýfýrlamak için fonksiyon aºaðýdaki
ºekilde çaðýrýlacaktýr:
clearbits(&x, 7, 9);
void clearbits(int *ptr, int startbit, int endbit)
{
int k;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
310
Buy RoboPDF
BÝTSEL OPERATÖRLER
}
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 örneðin 16 bitlik bir alanýn içindeki belirli bitleri birden fazla deðeri tutacak ºekilde
kullanabilir miyiz?
Örneðin 4 bitlik bir alan içerinde (negatif sayýlarý kullanmadýðýmýzý düºünürsek 0 – 15
aralýðýndaki deðerleri tutabiliriz. O zaman yalnýzca bu aralýktaki deðerleri kullanmak istiyorsak
ve bellek (ya da dosya) büyüklüðü açýsýndan kýsýtlamalar söz konusu ise 16 bitlik bir alan
içinde aslýnda biz 4 ayrý deðer tutabiliriz deðil mi?
Bir sayýnýn belirli bir bit alanýnda bir tamsayý deðerini tutmak için ne yapabiliriz? Önce sayýnýn
ilgili bitlerini sýfýrlar (örneðin yukarýda yazdýðýmýz clearbits fonksiyonuyla) daha sonra sayýyý,
sýfýrlanmýº bitleri yerleºtireceðimiz sayýnýn bit paternine eºit diðer bitleri 0 olan bir sayý ile bitsel
veya iºlemine tabi tutarýz, deðil mi? Aºaðýdaki fonksiyon prototip bildirimine bakalým:
void putvalue(int *ptr, int startbit, int endbit, int value);
putvlaue fonksiyonu adresi gönderilen nesnenin startbit – endbit deðerleri arasýndaki bitlerine
value sayýsýný yerleºtirecektir. Fonksiyon aºaðýdaki gibi çaðýrýlabilir :
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 yukarýdaki fonksiyonlar ile örneðin 16 bitlik bir sayýnýn belirli bit alanlarý içinde saklanmýº
deðerleri nasýl okuyacaðýz. Bu iºi de bir fonksiyona yaptýralým :
int getvalue(int x, int startbit, int endbit);
getvalue fonksiyonu startbit ve endbit ile belirlenen bit alanýna yerleºtirilmiº deðer ile geri
dönecektir.
int getvalue(int number, int startbit, int endbit)
{
int temp = number >>= startbit;
}
clearbits(&temp, endbit + 1, sizeof(int) * 8 - 1);
return temp;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
311
Buy RoboPDF
30 . BÖLÜM :
Uygulama
int türden bir sayýnýn bit bit ekrana yazdýrýlmasý
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 aºaðýdaki º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 türden bir sayýnýn bitlerini ters çeviren reverse_bits fonksiyonunun yazýlmasý:
#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 türden bir deðerin kaç adet bitinin set edilmiº olduðu bilgisine geri dönen no_of_setbits
fonksiyonunun yazýlmasý :
#include <stdio.h>
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
312
Buy RoboPDF
BÝTSEL OPERATÖRLER
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("sayýnýzýn %d biti 1n", no_of_setbits(number));
return 0;
Daha hýzlý çalýºacak 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;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
313
Buy RoboPDF
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
Buy RoboPDF
BÝT ALANLARI
31 . BÖLÜM : BÝT ALANLARI
konu eklenecek
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
315
Buy RoboPDF
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
Buy RoboPDF
KOMUT SATIRI ARGUMANLARI
32 . BÖLÜM : KOMUT SATIRI ARGUMANLARI
Bir programý çalýºtýrdýðýmýz zaman, programýn çalýºmasýný yönlendirecek ya da deðiºtirecek
birtakým parametre(leri) çalýºacak programa göndermek isteyebiliriz. Bu parametreler bir
dosya ismi olabileceði gibi, programýn deðiºik biçimlerde çalýºmasýný saðlayacak bir seçenek de
olabilir. UNIX iºletim sistemindeki ls komutunu düºünelim. Eðer ls programýný
ls
yazarak çalýºtýrýrsak, bulunulan dizin içindeki dosyalarýn isimleri listelenir. (DOS'daki dir komutu
gibi). Ama ls yerine
ls -l
yazýlarak program çalýºtýrýlýrsa bu kez yalnýzca dosya isimleri deðil, dizindeki dosyalarýn
büyüklüðünü , dosyalarýn sahiplerini, yaratýlma tarih ve zamanlarýný vs. gösteren daha ayrýntýlý
bir liste ekranda görüntülenir. ls programýný yine
ls -l sample.c
yazarak çalýºtýrýrsak, yalnýzca sample.c dosyasýna iliºkin bilgiler görüntülenecektir. ݺte bir
programý çalýºtýrýrken program isminin yanýna yazýlan diðer parametrelere komut satýrý
argumanlarý (command line arguments) denilmektedir.
Komut satýrý argumanlarý yalnýzca iºletim sistemi komutlarý için geçerli deðildir. Tüm
programlar için komut satýrý argumanlarý kullanýlabilir. Komut satýrý argumanlarýna C dili
standartlarýnda program parametreleri (program parameters) denmektedir.
C programlarýnýn çalýºmaya baºladýðý main fonksiyonu da isteðe baðlý olarak iki parametre
alabilir. Bu parametreler geleneksel olarak argc ve argv olarak isimlendirilirler.
int main(int argc, char *argv[])
{
...
}
argc (argument count) komut satýrý argumanlarýnýn sayýsýný gösterir. Bu sayýya programýn ismi
de dahildir. argv ise , stringler ºeklinde saklanan komut satýrý argumanlarýný gösteren, char
türden bir gösterici dizisidir. Bu durumda arg[0] göstericisini programýn ismini tutan stringi,
argv[1] den argv[argc - 1] e kadar olan göstericiler ise program ismini izleyen diðer
argumanlarýn tutulduklarý stringleri gösterirler. argv[argc] ise her zaman bir NULL göstericiyi
göstermektedir.
Yukarýdaki örnekte kullanýcý ls programýný
ls -l sample.c ºeklinde çalýºtýrdýðýnda
argc 3 deðerini alýr.
argv[0] program ismini gösterir. argv[1] = "ls";
argv[1] program ismini izleyen 1. argumaný gösterir. argv[1] = "-1";
argv[2] program ismini izleyen 2. argumaný gösterir. argv[2] = "sample.c";
argv[argc] yani argv[3] ise NULL adresini gösterecektir.
komut satýrý argumanlarý boºluklarla birbirinden ayrýlmýº olmalýdýr. Yukarýdaki örnekte program
ls -lsample.c ºeklinde çalýºtýrýlýrsa
argc = 2 olurdu.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
317
Buy RoboPDF
32 . BÖLÜM :
Komut satýrý argumanlarýnýn ikincisi karakter türünden bir göstericiyi gösteren göstericidir. Yani
argv[0], argv[1], argv[2]... herbiri char türden bir göstericidir. Komut satýrý argümalarý NULL
ile sonlandýrýlmýº bir biçimde bu adreslerde bulunurlar. argv[0] sürücü ve dizin dahil olmak
üzere (full path name) programýn ismini vermektedir. Diðer argümanlar sýrasýyla argv[1],
argv[2], argv[3], ... adreslerindedir.
Komut satýrý argumanlarý iºletim sistemi tarafýndan komut satýrýndan alýnýr ve derleyicinin
ürettiði giriº kodu yardýmýyla main fonksiyonuna parametre olarak kopyalanýr.
Aºaðýda komut satýrý argümanlarýný basan örnek bir program görüyorsunuz:
#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 aºaðýdaki º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 satýrý argumanlarýnýn isimleri argc ve argv olmak zorunda deðildir. Bunlar yerine
herhangi iki isim de kullanýlabilir. Ancak argc ve argv isimleri "argument counter" ve "argument
vector" sözcüklerinden kýsaltýlmýºtýr. Bu isimler programcýlar tarafýndan geleneksel olarak
kullanýlmaktadýr.
Komut satýrý argümanlarýný alan programlar genellikle, önce girilen argumanlarý yorumlar ve
test ederler. Örneðin :
int main(int argc, char *argv[])
{
if (argc == 1) {
printf("lütfen bir argumanla çalýºtýrýnýz!..\n");
exit(1);
}
if (argc == 2) {
printf("lütfen bir argumanla çalýºtýrýnýz!..\n");
exit(1);
}
return 0;
}
Yukarýdaki örnekte program bir komut satýrý argumaný verilerek çalýºtýrýlmadýysa (yani eksik
argumanla çalýºtýrýldýysa) bir hata mesajýyla sonlandýrýlýyor. Benzer biçimde fazla sayýda
argüman için de böyle bir kontrol yapýlmýºtýr.
DOS'ta olduðu gibi bazý sistemlerde main fonksiyonu üçüncü bir parametre alabilir. Üçüncü
parametre sistemin çevre deðiºkenlerine iliºkin bir karakter türünden göstericiyi gösteren
göstericidir.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
318
Buy RoboPDF
KOMUT SATIRI ARGUMANLARI
int main(int argc, char *argv[], char *env[])
{
...
return 0;
}
main fonksiyonuna tüm parametrelerÝ geçilmek zorunda deðildir. Örneðin :
int main(int argc)
{
...
return 0;
}
gibi yalnýzca birinci parametrenin kullanýldýðý bir tanýmlama geçerlidir. Ancak yalnýzca ikinci
parametre kullanýlamaz. Örneðin:
int main(char *argv[])
{
...
return 0;
}
Komut Satýrý Argumanlarýnýn Kullanýlmasýna Bir Örnek
Komut satýrýndan çalýºan 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ý operatör\n");
}
return 0;
}
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
319
Buy RoboPDF
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
Buy RoboPDF
DOSYALAR
33 . BÖLÜM : DOSYALAR
Ýkincil bellekte tanýmlanmýº bölgelere dosya denir. Her dosyanýn bir ismi vardýr. Ancak
dosyalarýn isimlendirme kurallarý sistemden sisteme göre deðiºebilmektedir. Dosya iºlemleri
tamamen iºletim sisteminin kontrolü altýndadýr.
ݺletim sistemi de ayrý ayrý yazýlmýº fonksiyonlarýn birbirlerini çaðýrmasý biçiminde çalýºýr.
Örneðin komut satýrýnda ismi yazýlmýº olan bir programýn çalýºtýrýlmasý birkaç sistem
fonksiyonunun çaðýrýlmasý ile yapýlmaktadýr. Komut satýrýndan yazýyý alan, diskte bir dosyayý
arayan, bir dosyayý RAM’e yükleyen, RAM’deki programý çalýºtýran fonksiyonlar düzenli olarak
çaðýrýlmaktadýr.
ݺletim sisteminin çalýºmasý sýrasýnda kendisinin de çaðýrdýðý, sistem programcýsýnýn da
dýºarýdan çaðýrabildiði iºletim sistemine ait fonksiyonlara sistem fonksiyonlarý denir. Bu tür
fonksiyonlara Windows sisteminde API (Application Proggramming Interface) fonksiyonlarý,
UNIX iºletim sisteminde ise sistem çaðýrmalarý (system calls) denir.
Aslýnda bütün dosya iºlemleri, hangi programlama dili ile çalýºýlýrsa çalýºýlsýn, iºletim sisteminin
sistem fonksiyonlarý tarafýndan yapýlýr. Sistem fonksiyonlarýnýn isimleri ve parametrik yapýlarý
sistemden sisteme deðiºebilmektedir.
Dosyalara Ýliºkin Temel Kavramlar
Dosyanýn Açýlmasý
Bir dosya üzerinde iºlem yapmadan önce dosya açýlmalýdýr. Dosya açabilmek için iºletim
sisteminin “dosya aç” isimli bir sistem fonksiyonu kullanýlýr. Dosyanýn açýlmasý sýrasýnda dosya
ile ilgili çeºitli ilk iºlemler iºletim sistemi tarafýndan yapýlýr.
Bir dosya açýldýðýnda, dosya bilgileri, ismine “Dosya Tablosu” (File table) denilen ve iºletim
sisteminin içerisinde bulunan bir tabloya yazýlýr. Dosya tablosunun biçimi sistemden siteme
deðiºebilir. Örneðin tipik bir dosya tablosu ºaðýdaki gibi olabilir :
Dosya tablosu (File table)
Sýra No Dosya ismi
0
1
...
12
...
AUTOEXEC.BAT
Dosyanýn
Diskteki Yeri
Dosyanýn
Özellikleri
Diðerleri
...
...
...
Sistem fonksiyonlarýnýn da parametreleri ve geri dönüº deðerleri vardýr. "Dosya aç" sistem
fonksiyonunun parametresi açýlacak dosyanýn ismidir.Fonksiyon, dosya bilgilerinin yazýldýðý sýra
numarasý ile geri döner ki bu deðere "file handle" denir. Bu handle deðeri diðer dosya
fonksiyonlarýna parametre olarak geçirilir. Dosyanýn açýlmasý sýrasýnda buna ek olarak baºka
önemli iºlemler de yapýlmaktadýr.
Dosyanýn Kapatýlmasý
Dosyanýn kapatýlmasý açýlmasý sýrasýnda yapýlan iºlemlerin geri alýnmasýný saðlar. Örneðin
dosyanýn kapatýlmasý sýrasýnda, iºletim sisteminin dosya tablosunda bulunan bu dosyaya iliºkin
bilgiler silinir. Açýlan her dosya kapatýlmalýdýr. Kapatýlmamasý çeºitli problemlere yol açabilir.
Dosyaya Bilgi Yazýlmasý ve Okunmasý
ݺletim sistemlerinin dosyaya n byte veri yazan ve dosyadan n byte veri okuyan sistem
fonksiyonlarý vardýr. Yazma ve okuma iºlemleri bu fonksiyonlar kullanýlarak yapýlýr.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
321
Buy RoboPDF
33 . BÖLÜM :
Dosya pozisyon göstericisi (file pointer)
Bir dosya byte’lardan oluºur. Dosyadaki her bir byte’a 0’dan baºlayarak artan sýrada bir sayý
karºýlýk getirilmiºtir. Bu sayýya ilgili byte’ýn ofset numarasý denir. Dosya pozisyon göstericisi
long türden bir sayýdýr ve bir ofset deðeri belirtir. Dosyaya yazan ve dosyadan okuma yapan
fonksiyonlar bu yazma ve okuma iºlemlerini her zaman dosya pozisyon göstericisinin gösterdiði
yerden yaparlar. Örneðin dosya göstericisinin gösterdiði yer 100 olsun. Dosyadan 10 byte bilgi
okumak için sistem fonksiyonu çaðýrýldýðýnda, 100. ofsetden itibaren 10 byte bilgi okunur.
ݺletim sisteminin dosya göstericisini konumlandýran bir sistem fonksiyonu vardýr. Dosya ilk
açýldýðýnda dosya göstericisi 0. ofsetdedir. Örneðin bir dosyanýn 100. Ofsetinden itibaren 10
byte okunmak istenirse sýrasý ile ºu iºlemlerin yapýlmasý gerekir:
Ýlgili dosya açýlýr.
Dosya pozisyon göstericisi 100. Offsete konumlandýrýlýr.
Dosyadan 10 byte okunur.
Dosya kapatýlýr.
C dilinde dosya iºlemleri 2 biçimde yapýlabilir :
1. ݺletim sisteminin sistem fonksiyonlarý doðrudan çaðýrýlarak.
2. Standart C fonksiyonlarý kullanýlarak.
Prototipleri stdio.h içerisinde olan standart dosya fonksiyonlarýnýn hepsinin ismi f ile baºlar.Tabi
standart C fonksiyonlarý da iºlemlerini yapabilmek için aslýnda iºletim sisteminin sistem
fonksiyonlarýný çaðýrmaktadýr. ݺletim sisteminin sistem fonksiyonlarý taºýnabilir deðildir.
Ýsimleri ve parametrik yapýlarý sistemden sisteme deðiºebilir. Bu yüzden standart C
fonksiyonlarýnýn kullanýlmasý tavsiye edilir.
fopen fonksiyonu
FILE *fopen (const char *fname, const char *mode)
Fonksiyonun 1. Parametresi açýlacak dosyanýn ismidir. 2. Parametre açýº modudur. Dosya ismi
path içerebilir. Dizin geçiºleri için / de konulabilir. Açýº modu ºunlar olabilir :
Mode
"w"
"w+"
"r"
"r+"
"a"
"a+"
Anlamý
Dosyayý yazmak için açar. Dosyadan okuma yapýlamaz. Dosyanýn mevcut olamasý
zorunlu deðildir. Dosya mevcut deðilse yaratýlýr. Dosya mevcut ise sýfýrlanýr.
Dosyayý yazma ve okuma için açar. Dosyanýn mevcut olamasý zorunlu deðildir.
Dosya mevcut deðilse yaratýlýr. Dosya mevcut ise sýfýrlanýr.
Dosyayý okuma için açar. Dosyaya yazma yapýlamaz. Dosya mevcut deðilse
açýlamaz.
Dosyayý okuma ve yazma için açar. (Dosyanýn pozisyon göstericisi dosyanýn
baºýndadýr). Dosya mevcut deðilse açýlamaz.
Dosyayý sonuna ekleme için açar. Dosyadan okuma yapýlamaz. Dosyanýn mevcut
olamasý zorunlu deðildir. Dosya mevcut deðilse yaratýlýr.
Dosyayý sonuna ekleme ve dosyadan okuma için açar. Dosyanýn mevcut olamasý
zorunlu deðildir. Dosya mevcut deðilse yaratýlýr.
Fonksiyonun geri dönüº deðerine iliºkin FILE yapýsý stdio.h içerisinde bildirilmiºtir. Fonskiyonun
geri dönüº deðeri FILE yapýsý türünden bir adrestir. Bu yapýnýn elemanlarý standart deðildir.
Sistemden sisteme deðiºiklik gösterebilir. Zaten programcý bu yapýnýn elemanlarýna gereksinim
duymaz. fopen fonksiyonu iºletim sisteminin dosya aç sistem fonksiyonunu çaðýrarak dosyayý
açar ve dosyaya iliºkin bazý bilgileri bu FILE yapýsý içerisine yazarak bu yapýnýn baºlangýç
adresini geri döndürür. Örneðin "file handle" deðeri de bu yapýnýn içerisindedir. Tabi fopen
fonksiyonunun geri verdiði FILE türünden adres güvenli bir adrestir. Dosya çeºitli sebeplerden
dolayý açýlamayabilir. Bu durumda fopen NULL gösterici döndürür. Fonksiyonun geri dönüº
deðeri kesinlikle kontrol edilmelidir. Tipik bir kontrol iºlemi aºaðýdaki gibi yapýlabilir:
if ((f = fopen(“data”, “r”)) == NULL) {
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
322
Buy RoboPDF
DOSYALAR
}
printf(“cannot open file”...\n);
exit(1);
Dosya ismi dosyanýn yeri hakkýnda bilgi (sürücü, path gibi) içerebilir. Dosya ismi string ile
veriliyorsa path bilgisi verirken dikkatli olmak gerekecektir. path bilgisi \ karakteri içerebilir.
string içinde \ karakterinin kullanýlmasý, \ karakterininin onu izleyen karakterle birlikte önceden
belirlenmiº ters bölü karakter sabiti olarak yorunlanmasýna yol açabilecektir. Örneðin :
fopen("C:\source\new.dat", "r");
fonksiyon çaðýrýmýnda derleyici \n karakterini "newline" karakteri olarak yorumlayacak \s
karakterini ise "undefined" kabul edecektir. Bu problemden sakýnmak \ yerine \\
kullanýlmasýyla mümkün olur:
fopen("C:\\source\\new.dat", "r");
Append modlarý ("a", "a+") çok kullanýlan modlar deðildir. Dosyaya yazma durumunda "w"
modu ile "a" modu arasýnda farklýlýk vardýr. "w" modunda dosyada olan ofsetin üzerine
yazýlabilir. "a" modunda ise dosya içeriði korunarak sadece dosyanýn sonuna yazma iºlemi
yapýlabilir. Bir dosyanýn hem okuma hem de yazma amacýyla açýlmasý durumunda (yani açýº
modunu belirten stringde '+' karakterinin kullanýlmasý durumunda dikkatli olmak gerekir.
Okuma ve yazma iºlemleri arasýnda mutlaka ya dosya pozisyon göstericisinin
konumlandýrýlmasý (mesela fseek fonksiyonu ile) ya da dosyaya iliºken tampon bellek alanýnýn
(buffer) tazelenmesi gerekecektir.
Bir dosyanýn açýlýp açýlamayacaðýný aºaðýdaki ºekilde test edebiliri:
Program komut satýrýndan
canopen dosya.dat
ºeklinde çalýºtýrýldýðýnda ekrana "xxxxx dosyasý açýlabilir" ya da "xxxxx dosyasý açýlamaz"
yazacaktýr.
#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ý açýlamaz\n", argv[1]);
return 1;
}
printf("%s dosyasý açýlabilir\n", argv[1]);
fclose(fp);
return 0;
fclose fonksiyonu
int fclose(FILE *stream);
Bu fonksiyon açýlmýº olan bir dosyayý kapatýr. Fonksiyon fopen ya da fropen fonksiyonundan
elde edilen FILE yapýsý türünden adresi parametre olarak alýr ve açýk olan dosyayý kapatýr.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
323
Buy RoboPDF
33 . BÖLÜM :
Fonksiyonun geri dönüº deðeri 0 ise dosya baºarýlý olarak kapatýlmýºtýr. Fonksiyonun geri dönüº
deðeri EOF ise dosya kapatýlamamýºtýr. EOF stdio.h içinde tanýmlanan bir sembolik sabittir ve
derleyicilerin çoðunda (-1) olarak tanýmlanmýºtýr. Fonksiyonun baºarýsý ancak ºüphe altýnda
test edilmelidir. Normal ºartlar altýnda dosyanýn kapatýlmamasý için 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 dolayýsýyla C’nin yazma ve okuma yapan fonksiyonlarý yazýlan ve okunan
miktar kadar dosya göstericisini ilerletirler. fgetc fonksiyonu dosya göstericisinin gösterdiði
yerdeki byte’ý okur ve geri dönüº deðeri olarak verir. Fonksiyon baºarýsýz olursa , stdio.h
dosyasý içerisinde sembolik sabit olarak tanýmlanmýº EOF deðerine geri döner. Pek çok derleyici
de EOF sembolik sabiti aºaðýdaki gibi tanýmlanmýºtýr.
#define EOF (-1)
fgetc fonksiyonunun geri dönüº deðerini char türden bir deðiºkene atamak yanlýº sonuç
verebilir, bu konuda dikkatli olunmalý ve fonksiyonun geri dönüº deðeri int türden bir
deðiºkende saklanmalýdýr.
char ch;
...
ch = fgetc(fp);
Yukarýda dosyadan okunan karakterin 255 numaralý ASCII karakteri (0x00FF) olduðunu
düºünelim. Bu sayý char türden bir deðiºkene atandýðýnda yüksek anlamlý byte'ý kaybedilecek
ve ch deðiºkenine 0xFF deðeri atanacaktýr. Bu durumda ch deðiºkeni iºaretli char türden
olduðundan ch deðiºkeni içinde negatif bir sayýnýn tutulduðu anlamý çýkar.
if (ch == EOF)
gibi bir karºýlaºtýrma deyiminde, if parantezi içerisindeki karºýlatýrma iºleminin yapýlabilmesi
için otomatik tür dönüºümü yapýlýr. Bu otomatik tür dönüºümünde iºaretli int türüne çevrilecek
ch deðiºkeni FF byte'ý ile beslenecektir. (negatif olduðu için). Bu durumda eºitlik karºýlaºtýrmasý
doðru netice verecek, yani dosyanýn sonuna gelindiði (ya da baºka nedenden dolayý okumanýn
yapýlamadýðý) yorumu yapýlacaktýr.
Oysa ch deðiºkeni int türden olsaydý, ch deðiºkenine atanan deðer 0x00FF olacak ve bu
durumda karºýlaºtýrma yapýldýðýnda ch deðiºkeni ile EOF deðerinin (0xFFFF) eºit olmadýðý
sonucuna varýlacaktýr.
Bir dosyanýn içeriðini ekrana yazdýran örnek program:
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
324
Buy RoboPDF
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 uzunluðu DOS’da 80 UNIX ve WINDOWS’da 256 karakteri geçemez.
fputc Fonksiyonu
int fputc(int ch, FILE *p);
Bu fonksiyon dosya göstericisinin bulunduðu yere 1 byte bilgiyi yazar. Fonksiyonun 1.
parametresi yazýlacak karakter, 2. parametresi ise yazýlacak dosyaya iliºkin FILE yapýsý
adresidir. Fonksiyonun geri dönüº deðeri EOF ise iºlem baºarýsýzdýr. Deðilse fonksiyon yazýlan
karakter ile geri döner.
fgetc ve fputc fonksiyonlarý kullanýlarak 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;
}
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
325
Buy RoboPDF
33 . BÖLÜM :
fprintf Fonksiyonu
Bu fonksiyon týpký printf fonksiyonu gibidir. Ancak ilk parametresi yazma iºleminin hangi
dosyaya yapýlacaðýný belirtir. Diðer parametreleri printf fonksiyonun da olduðu gibidir. Özetle
printf fonksiyonu ekrana yazar ancak fprint fonksiyonu 1. parametre deðiºkeninde 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 göstericisinin gösterdiði yerden 1 satýrlýk bilgiyi okur. Fonksiyon dosyadan
'\n' karakterini okuyunca onu da birinci parametresinde verilen adrese yazarak iºlemini
sonlandýrýr.
Fonksiyonun 1. parametresi okunacak bilginin RAM'de yerleºtirileceði yerin adresidir. 2.
parametresi ise okunacak maksimum karakter sayýsýdýr. fgets en fazla n –1 karakteri okur.
Okuduðu karakterlerin soonuna null karakteri ekler ve iºlemini sonlandýrýr. Eðer satýr
üzerindeki karakter sayýsý n- 1'den az ise tüm satýrý okur ve iºlemini sonlandýrýr. Örneðin bu
parametreyi 10 olarak girdiðimizi düºünelim. Satýr üzerinde 20 karakter olsun. Fonksiyon 9
karakteri okur, sonuna NULL karakteri ekler. Ancak satýr üzerinde \n dahil olmak üzere 5
karakter olsaydý fonksiyon bu 5 karakteri de okuyarak sonuna da NULL karakter ekleyerek
iºlemini sonlandýracaktý. Bir döngü içerisinde fgets fonksiyonu sürekli olarak çaðýrýlarak bütün
dosya okunabilir.
Fonksiyonun geri dönüº deðeri, en az 1 karakter okunmuº ise 1. parametresi ile belirtilen
adresin aynýsý, hiç okunmamýºsa NULL adresidir.
Örnek : Bir dosyayý fgets fonksiyonu ile satýr satýr 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);
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
326
Buy RoboPDF
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 iºletim sistemlerinde bir dosya text ve binary modda açýlabilir. Varsayýlan
açýº modu textdir. Yani dosyanýn hangi modda açýldýðý açýk bir ºekilde belirtilmezse dosyanýn
text modda açýldýðý varsayýlacaktýr. Dosyayý binary modda açabilmek için açýº modunun
sonuna b eklemek gerekir. Örneðin :
f = fopen(“data”, “r”) text modda
f = fopen(“data, “rb”) binary modda
DOS’da bir dosya type edildiðinde bir karakter aºaðý satýrýn baºýnda görünüyorsa bunu
saðlamak için o karakterden önce CR (carriage return) ve LF (line feed) karakterlerinin
bulunmasý gerekir. CR karakteri C’de ‘\r’ ile belirtilir. 13 numaralý ASCII karakteridir. LF
karakteri C’de \n ile belirtilir. 10 numaralý ASCII karakteridir. Örneðin bir dosya type
edildiðinde görüntü
a
b
ºeklinde olsun. Dosyadaki durum a\r\nb ºeklindedir. Oysa UNIX sistemlerinde aºaðý satýrýn
baºýna geçebilmek için sadece LF karakteri kullanýlmaktadýr. UNIX de
a
b
görüntüsünün dosya karºýlýðý
a\nb biçimindedir.
DOS’da LF karakteri bulunulan satýrýn aºaðýsýna geç CR karakteri ise bulunulan satýrýn baºýna
geç anlamýndadýr. Örneðin DOS da bir bir dosyanýn içeriði a\nb biçiminde ise dosya type
edildiðinde
a
b
görüntüsü elde edilir. Eðer dosyanýn içeriði a\rb biçiminde ise dosya type edildiðinde
b
görüntüsü elde edilir.
printf fonksiyonunda \n ekranda aºaðý satýrýn baºýna geçme amacýyla kullanýlýr. Aslýnda biz
printf fonksiyonunun 1. parametresi olan stringin içine \n yerleºtirdiðimizde UNIX'de yalnýzca
\ni DOS'da ise \r ve\n ile bu geçiº saðlanýr.
Text dosyalarý ile rahat çalýºabilmek için dosyalar text ve binary olarak ikiye ayrýlmýºtýr. Bir
dosya text modunda açýldýðýnda dosyaya \n karakteri yazýlmak istendiðinde dosya fonksiyonlarý
otomatik olarak \r ve \n karakterlerini dosyaya yazarlar. Benze r bir biçimde dosya text modda
açýlmýºsa dosya göstericisi \r\n çiftini gösteriyorsa dosyadan yalnýzca /n karakteri okunur. DOS
iºletim sisteminde text ve binary dosyalar arasýndaki baºka bir fark da, CTRL Z (26 numaralý
ASCII karakterinin) dosyayý sonlandýrdýðýnýn varsayýlmasýdýr. Oysa dosya binary modda
açýldýðýnda böyle bir varsayým yapýlmaz.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
327
Buy RoboPDF
33 . BÖLÜM :
UNIX iºletim sisteminde text modu ile binary mod arasýnda hiçbir fark yoktur. Yani UNIX iºletim
sisteminde dosyanýn binary mod yerine text modunda açýlmasýnýn bir sakýncasý olmayacaktýr.
Ancak DOS altýnda text dosyasý olmayan bir dosyanýn binary mod yerine text modunda
açýlmasýnýn sakýncalarý olabilir. Örneðin DOS altýnda bir exe dosyanýn binary mod yerine text
modda açýldýðýný düºünelim. Bu dosyada 10 numaralý ve 13 numaralý ASCII karakterleri
yanyana bulunduðunda dosyadan yalnýzca 1 byte okunacaktýr. Ayný ºekilde dosyadan 26
numaralý ASCII karakteri okunduðunda dosyadan artýk baºka bir okuma yapýlamayacaktýr.
(Dosyanýn sonuna gelindiði varsayýlacaktýr.)
/*
textmode.c programý
DOS altýnda text modu ile binary mod arasýndaki
farký gösteren 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 açýlamýyor\n");
exit(EXIT_FAILURE);
}
/* dosyaya 5 tane \n karakteri yazdýrýlýyor */
for (k = 0; k < 5; ++k)
fputc('\n', fp);
fclose(fp);
printf("\ndosya binary modda açýlarak yazdýrýlýyor\n");
fp = fopen("deneme", "rb");
if (fp == NULL) {
printf("dosya açýlamýyor\n");
exit(EXIT_FAILURE);
}
while ((ch = fgetc(fp)) != EOF)
printf("%d ", ch);
/* ekran çýktýsý
13 10 13 10 13 10 13 10 13 10
*/
fclose(fp);
printf("\ndosya kapatýldý. ªimdi dosya text modunda açýlarak yazdýrýlýyor
.\n");
fp = fopen("deneme", "r");
if (fp == NULL) {
printf("dosya açýlamýyor\n");
exit(EXIT_FAILURE);
}
while ((ch = fgetc(fp)) != EOF)
printf("%d ", ch);
/* ekran çýktýsý
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
328
Buy RoboPDF
DOSYALAR
10
*/
10
10
10
10
fclose(fp);
/* simdi '\x1A' karakterinin text modunda dosyayý sonlandýrmasý özelliði
test ediliyor */
fp = fopen("deneme", "w");
if (fp == NULL) {
printf("dosya açýlamýyor\n");
exit(EXIT_FAILURE);
}
/* dosyaya 5 tane 'A' karakteri yazdýrýlýyor */
for (k = 0; k < 5; ++k)
fputc('A', fp);
/* dosyaya '\x1A' karakteri yazdýrýlýyor */
fputc('\x1a', fp);
/* dosyaya 10 tane 'A' karakteri yazdýrýlýyor. */
for (k = 0; k < 5; ++k)
fputc('A', fp);
fclose(fp);
printf("\ndosya binary modda açýlarak yazdýrýlýyor :\n");
fp = fopen("deneme", "rb");
if (fp == NULL) {
printf("dosya açýlamýyor\n");
exit(EXIT_FAILURE);
}
while ((ch = fgetc(fp)) != EOF)
printf("%d ", ch);
/* ekran çýktýsý
65 65 65 65 65 26 65 65 65 65 65
*/
printf("\ndosya
kapatýldý,
ªimdi
yazdýrýlýyor\n");
fp = fopen("deneme", "r");
if (fp == NULL) {
printf("dosya açýlamýyor\n");
exit(EXIT_FAILURE);
}
while ((ch = fgetc(fp)) != EOF)
printf("%d ", ch);
dosya
text
modunda
açýlarak
/* ekran çýktýsý
65 65 65 65 65 26 65 65 65 65 65
*/
fclose(fp);
return 0;
}
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
329
Buy RoboPDF
33 . BÖLÜM :
EOF (END OF FILE) DURUMU
Dosyanýn sonunda hiçbir özel karakter yoktur. ݺletim sistemi dosyanýn sonuna gelinip
gelinmediðini dosyanýn uzunluðuna bakarak anlayabilir. EOF durumu dosya pozisyon
göstericisinin dosyada olmayan son karakteri göstermesi durumudur. EOF durumunda dosya
pozisyon göstericisinin offset deðeri dosya uzunluðu ile ayný deðerdedir. EOF durumunda
dosyadan okuma yapýlmak istenirse dosya fonksiyonlarý baºarýsýz olur. Ancak açýº modu
uygunsa dosyaya yazma yapýlabilir ve bu durumda dosyaya ekleme yapýlýr.
Daha önce söylendiði gibi C dilinde açýlan bir dosya ile ilgili bilgiler FILE türünden bir yapý
nesnesi içinde tutulur. Bu yapýnýn her bir elemaný dosyanýn bir özelliði hakkýnda bilgi
vermektedir. C programcýsý bu yapýnýn elemanlarýnýn deðerleri ile doðrudan ilgilenmez, zira
fopen fonksiyonunun geri dönüº deðeri bu yapý nesnesini gösteren FILE yapýsý türünden bir
göstericidir ve C dilinin dosyalarla ilgili iºlem yapan fonksiyonlarý çoðunlukla bu adresi
parametre olarak alarak, istenilen dosyaya ulaºýrlar.
Söz konusu FILE yapýsýnýn elemanlarýndan biri de flag olarak kullanýlan EOF indikatörüdür.
(aslýnda int türden bir flag'in yalnýzca belirli bir bitidir.) C dilinin dosyalarla ilgili iºlem yapan
bazý fonksiyonlarý EOF indikatörünün deðerini deðiºtirirler. (set ya da clear ederler. Set
edilmesi bu indikatöre 1 deðerinin atanmasý clear edilmesi ise 0 deðerinin atanmasýdýr. Bu
indikatörün set edilmesi demek dosya pozisyon göstericisinin dosyanýn sonunu göstermesi
demektir.
Dosya açan fonksiyonlar FILE yapýsýndaki EOF indikatörünü sýfýrlarlar. Bu fonksiyonlar dýºýnda
fseek fonksiyonu ve clearerr fonksiyonlarý da EOF indikatörünü sýfýrlarlar. (clear ederler).
fseek fonksiyonu :
Bu fonksiyon dosya pozisyon göstericisini istenilen bir offsete konumlandýrmak amacýyla
kullanýlýr. Bu fonksiyonun kullanýlmasýyla, açýlmýº bir dosyanýn istenilen bir yerinden okuma
yapmak ya da istenilen bir yerine yazmak mümkün hale gelir. Prototipi :
int fseek(FILE *f, long offset, int origin);
Fonksiyonun ikinci parametresi konumlandýrma iºleminin yapýlacaðý offset deðeridir.
Fonksiyonun 3. parametresi 0, 1, veya 2 olabilir. Bu deðerler stdio.h dosyasýnda
#define SEEK_SET
#define SEEK_CUR
#define SEEK_END
0
1
2
biçiminde sembolik sabitlerle tanýmlanmýºtýr ve fseek fonksiyonun çaðýrýlmasýnda daha çok bu
sembolik sabitler kullanýlmaktadýr.
son parametre 0 ise, konumlandýrma dosya baºýndan itibaren yapýlýr. Bu durumda 2.
parametre >= 0 olmalýdýr. Örneðin:
fseek(f, 10L, 0);
ile dosya göstericisi 10. offsete konumlandýrýlýr. Ya da
fseek(f, 0, 0);
ile dosya göstericisi dosyanýn baºýna konumlandýrýlýr. Dosya pozisyon göstericisinin dosyanýn
baºýna konumlandýrýlmasý için rewind fonksiyonu da kullanýlabilir:
void rewind(FILE *fp);
rewind(f);
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
330
Buy RoboPDF
DOSYALAR
fonksiyonun 3. parametre deðiºkenine geçilen deðer 1 ise (SEEK_CUR) , konumlandýrma dosya
göstericisinin en son bulunduðu yere göre yapýlýr. Bu durumda ikinci parametre pozitif ya da
negatif deðere sahip olabilir. Pozitif bir deðer ileri, negatif bir deðer geri anlamýna gelecektir.
Örneðin dosya göstericisi 10. offsette olsun.
fseek(f, -1, SEEK_CUR);
çaðýrmasý ile dosya göstericisi 9. offset'e konumlandýrýlýr.
fonksiyonun 3. parametre deðiºkenine geçilen deðer 2 ise (SEEK_END), konumlandýrma EOF
durumundan itibaren yani dosya sonunu referans alýnarak yapýlýr. Bu durumda ikinci parametre
<= 0 olmalýdýr. Örneðin dosya göstericisini EOF durumuna çekmek için :
fseek(f, 0, SEEK_END);
çaðýrmasýný yapmak gerekir. Ya da baºka bir örnek:
fseek(f, -1, SEEK_END);
çaðýrmasý ile dosya göstericisi son karakterin offsetine çekilir. Fonksiyonun geri dönüº deðeri
iºlemin baºarýsý hakkýnda bilgi verir. Geri dönüº deðeri 0 ise iºlem baºarýlýdýr. Geri dönüº deðeri
0 dýºý bir deðer ise iºlem baºarýsýzdýr. Ancak problemli durumlarda geri dönüº deðrinin test
edilmesi tavsiye edilir.
Yazma ve okuma iºlemleri arasýnda dosya göstericisinin fseek fonksiyonu ile konumlandýrýlmasý
gerekir.Konumlandýrma gerekirse boº bir fseek çaðýrmasý ile yapýlabilir. Örneðin dosyadan bir
karakter okunup , bir sonraki karaktere bu karakterin 1 fazlasýný yazacak olalým.
ch = fgetc(f);
fputc(ch + 1, f);
iºlemi hatalýdýr. Yazmadan
konumlandýrýlmalýdýr.
okumaya,
okumadan
yazmaya
geçiºte
dosya
göstericisi
feof fonskiyonu :
bu fonksiyon dosya göstericisinin EOF durumunda olup olmadýðýný (EOF indikatörünün set edilip
edilmediðini) test etmek amacýyla kullanýlýr. Prototipi:
int feof(FILE *f);
Eðer dosya göstericisi dosya sonunda ise (EOF indikatörü set edilmiºse) fonksiyon 0 dýºý bir
deðere , deðilse (EOF indikatörü set edilmemiºse) 0 deðeri ile geri döner.
Ancak feof fonksiyonunun 0 dýºý bir deðere geri dönebilmesi için dosya göstericisinin dosyanýn
sonunda olmasýnýn yaný sýra en son yapýlan okuma iºleminin de baºarýsýz olmasý gerekir. daha
önce söylendiði gibi bazý fonksiyonlar (fopen, fseek, rewind, clearerr) EOF indikatorünü clear
ederler, yani EOF indikatörünün 0 deðerinde olmasý (clear edilmiº olmasý) dosyanýn sonunda
olunmadýðýnýn bir garantisi deðildir.
fread ve fwrite fonksiyonlarý
Bu iki fonksiyon C dilinde en çok kullanýlan dosya fonksiyonlarýdýr. Genel olarak dosya ile RAM
arasýnda transfer yaparlar. Her iki fonskiyonun da prototipleri aynýdýr.
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 *);
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
331
Buy RoboPDF
33 . BÖLÜM :
size_t türünün derleyiciyi yazanlar tarafýndan unsigned int ya da unsigned long türünün
typedef edilmiº yeni ismi olduðunu hatýrlayalým.
fread fonskiyonu dosya pozisyon göstericisinin gösterdiði yerden, 2. ve 3. parametresine
kopyalanan deðerlerin çarpýmý kadar byte'ý , RAM'de 1. parametresinin gösterdiði adresten
baºlayarak kopyalar. Geleneksel olarak fonksiyonun 2. parametresi veri yapýsýnýn bir
elemanýnýn uzunluðunu, 3. parametresi ile parça sayýsý biçiminde girilir.
Bu fonksiyonlar sayesinde diziler ve yapýlar tek hamlede dosyaya transfer edilebilirler. Örneðin
10 elemanlý bir dizi aºaðýdaki gibi tek hamlede dosyaya yazýlabilir.
int a[5] = {3, 4, 5, 7, 8};
fwrite (a, sizeof(int), 5, f);
Yukarýdaki örnekte, dizi ismi olan a int türden bir adres bilgisi olduðu için, fwrite fonksiyonuna
1. arguman olarak gönderilebilir. FILE türünden f göstericisi ile iliºkilendirilen dosyaya RAM'deki
a adresinden toplam sizeof(int) * 5 byte yazýlmaktadýr.
Ancak tabi fwrite fonskiyonu sayýlarý bellekteki görüntüsü ile dosyaya yazar. (yani fprintf
fonksiyonu gibi formatlý yazmaz.) Örneðin:
int i = 1535;
fwrite(&i, sizeof(int), 1, f);
Burada dosya type edilirse 2 byte uzunluðunda rasgele karakterler görünür. Çünkü DOS'da int
türü 2 byte uzunluðundadýr. Bizim gördüðümüz ise 1525'in rasgele olan bytelarýdýr. Bilgileri
ASCII karºýlýklarý ile dosyaya yazmak için fprintf fonksiyonu kullanýlabilir..
fread ve fwrite fonksiyonlarý bellekteki bilgileri transfer ettiðine göre dosyalarýn da binary
modda açýlmýº olmasý uygun olacaktýr.
#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 fonksiyonlarýnýn geri dönüº deðerleri 3. parametresi ile belirtilen okunan ya da
yazýlan parça sayýsýdýr. Örneðin
n = fread(a, sizeof(int), 10, f);
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
332
Buy RoboPDF
DOSYALAR
ifadesinde fonksiyon bütün sayýlarý okuyabildiyse 10 sayýsýna geri döner. Eðer dosyadaki kalan
byte sayýsý okunmak istenen sayýdan az ise fonksiyon bütün byte'larý okur ve geri dönüº deðeri
okunan byte sayýsý 2. parametresi ile belirtilen sayý olur. Örneðin DOS altýnda çalýºýyor olalým.
Dosyada 10 byte bilgi kalmýº olsun.
n = fread(a, sizeof(int), 10, f);
ile fonksiyon 5 sayýsýna geri dönecektir.
Aºaðýdaki iki ifadeyi inceleyelim:
fread(str, 100, 1, f);
fread(str, 1, 100, f);
her iki fonksiyon çaðýrma ifadesi de RAM'deki str adresine FILE türünden f göstericisi ile
iliºkilendirilen dosyadan 100 byte okumak amacýyla kullanýlabilir. Ancak birinci çaðýrmada geri
dönüº deðeri ya 0 ya 1 olabilecekken, ikinci fonksiyon çaðýrmasýnda geri dönüº deðeri 0
100(dahil) herhangi bir deðer olabilecektir.
Blok blok kopyalama iºlemi
Aºaðýdaki örnekte bir grup byte fread fonskiyonu ile bir dosyadan okunmuº ve fwrite
fonksiyonu ile diðer bir dosyaya yazýlmýºtýr.
#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 için kullanýlýr. Fonksiyonun prototipi :
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
333
Buy RoboPDF
33 . BÖLÜM :
int remove (const char *filename);
ºeklindedir. Fonksiyona arguman olarak silinecek dosyanýn ismi gönderilir. Fonksiyonun geri
dönüº deðeri, dosyanýn baºarýlý bir ºekilde silinebilmesi durumunda 0 aksi halde (yani dosya
silinememiºse) 0 dýºý bir deðerdir. Açýk olan bir dosyanýn silinmesi "implementation depended"
(derleyiciye baðlý) olduðundan, yazýlan kodun taºýnabilirliði açýsýndan, silinecek bir dosya açýk
ise önce kapatýlmalýdýr.
rename fonksiyonu
Bu fonksiyon bir dosyanýn ismini deðiºtirmek için kullanýlýr. Fonksiyonun prototipi :
int rename (const char *old, const char *new);
ºeklindedir.
Fonksiyona 1. arguman olarak dosyanýn eski ismi ikinci arguman olarak ise dosyanýn yeni ismi
gönderilmelidir. Fonksiyonun geri dönüº deðeri, isim deðiºtirmen iºleminin baºarýlý olmasý
durumunda 0, aksi halde (dosyanýn ismi deðiºtirilemiyorsa 0 dýºý bir deðerdir. (Örneðin açýk
olan bir dosyanýn isminin deðiºtirilmeye çalýºýlmasý baºarýlý olamayacaðýndan fonksiyon bu
durumda 0 dýºý bir deðere geri dönecektir.)
tmpfile fonksiyonu
Fonksiyon geçici bir dosya açmak amacýyla kullanýlýr. Fonksiyonun prototipi :
FILE * tmpfile(void);
tmpfile fonksiyonu açtýðý geçici dosyayý "wb" modunda açar. Açýlan dosya fclose fonksiyonu ile
kapatýldýðýnda ya da (kapatýlmazsa), program sona erdiðinde otomatik olarak silinecektir.
Fonksiyonu geri dönüº deðeri, açýlan geçici dosya ile iliºki kurulmasýna yarayacak, FILE yapýsý
türünden bir adrestir. Herhangi bir nedenle dosya geçici dosya açýlamýyorsa fonksiyon NULL
adresine geri dönecektir.
tmpnam fonksiyonu
Geçici olarak kullanýlacak bir dosya için bir isim üretilmesi amacýyla kullanýlýr. Fonksiyonun
prototipi :
char *tmpnam(char *s);
ºeklindedir. Fonksiyon ürettiði dosya ismini kendisine gönderilen char türden adrese yerleºtirir.
Eðer fonksiyona arguman olarak NULL adresi gönderilirse, fonksiyon üretilen dosya ismini
statik bir dizi içinde tutarak bu dizinin adresiyle geri dönecektir. Fonksiyona char türden bir
dizinin adresi gönderildiðinde bu dizinin boyutu ne kadar olmalýdýr. Baºka bir deyiºle tmpnam
fonksiyonu kaç karakter uzunluðunda bir dosya ismi üretecektir. ݺte bu deðer stdio.h dosyasý
içinde tanýmlanan L_tmpnam sembolik sabitiyle belirtilmektedir.
tmpnam fonksiyonunun ürettiði dosya isminin daha önce kullanýlmayan bir dosya ismi olmasý
garanti altýna alýnmýºtýr. Yani üretilen dosya ismi tektir. (unique file name) Bir programda daha
sonra silmek üzere bir dosya açacaðýmýzý ve bu dosyaya birtakým bilgileri yazacaðýmýz
düºünelim. Bu durumda dosyayý yazma modunda açacaðýmýza göre, açacaðýmýz dosyaya olan
bir dosyanýn ismini veremeyiz. Eðer verirsek , var olan dosya sýfýrlanacaðý için bu dosyayý
kaybederiz. Bu riske girmemek için, geçici olarak kullanýlacak dosya tmpfiel fonksiyonu
kullanýlarak açýlmalýdýr. Ancak tmpfile fonksiyonunun kullanýlmasý durumunda, açýlan dosya
kalýcý hale getirilemez. Yani herhangi bir nedenden dolayý geçici dosyanýn silinmemesini
istersek, (dosyayý kalýcý hale getirmek istersek) dosyayý fopen fonksiyonuyla açmalýyýz. ݺte bu
durumda geçici dosyayý baºka bir dosyayý riske etmemek için tmpnam fonksiyonunun ürettiði
isim ile açmalýyýz. Peki tmpnam fonksiyonuyla en fazla kaç tane "unique file name " üretebiliriz.
ݺte bu sayý stdio.h içinde tanýmlanan TMP_MAX sembolik sabiti ile belirlenmiºtir.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
334
Buy RoboPDF
DOSYALAR
C dilinde bazý giriº ve çýkýº birimleri(klavye, ekran gibi) doðrudan bir dosya gibi ele alýnýrlar. C
standartlarý herhangi bir giriº çýkýº birimini "stream" olarak isimlendirmektedir. Bir stream bir
dosya olabileceði gibi, dosya olarak ele alýnan bir giriº çýkýº birimi de olabilir. Örneðin küçük
programlar genellikle girdilerini genellikle tek bir stream,den alýp (mesela klavye) çýktýlarýný da
tek bir streame (mesela ekran) iletirler.
freopen fonksiyonu
freopen fonksiyonu daha önce açýlmýº bir dosyayý, fropen fonksiyonu ile açýlan dosyaya
yönlendirir. Fonksiyonun prototipi :
FILE *freopen(const char *filename, const char *mode, FILE *stream);
ºeklindedir.
Uygulamalarda daha çok standart dosyalarýn (stdin, stdout, stderr) baºka dosyalara
yönlendirilmesinde kullanýlýr. Örneðin bir programýn çýktýlarýnýn data.dat isimli dosyaya
yazýlmasýný istersek :
if (freopen("data.dat", "w", stdout) == NULL) {
printf("data.dat dosyasý açýlamýyor\n");
exit(EXIT_FAILURE);
}
yukarýdaki fonksiyon çaðýrýmýyla stdout dosyasýnýn yönlendirildiði dosya kapatýlarak (bu
yönlendirme iºlemi komut satýrýndan yapýlmýº olabileceði gibi, freopen fonksiyonunun daha
önceki çaðýrýmý ile de yapýlmýº olabilir.) stdout dosyasýnýn data.dat dosyasýna yönlendirilmesi
saðlanýr.
freopen fonksiyonunun geri dönüº deðeri fonksiyona gönderilen üçüncü arguman olan FILE
yapýsý türünden göstericidir. freopen dosyasý yönlendirmenin yapýlacaðý dosyayý açamazsa
NULL adresine geri döner. Eðer yönlendirmenin yapýldýðý eski dosya kapatýlamýyorsa, freopen
fonksiyonu bu durumda bir iºaret vermez.
dosya buffer fonksiyonlarý
Ýkincil belleklerle (disket, hard disk vs.) yapýlan iºlemler RAM'de yapýlan iºlemlere göre çok
yavaºtýr. Bu yüzden bir dosyadan bir karakterin okunmasý ya da bir dosyaya bir karakterin
yazýlmasý durumunda her defasýnda dosyaya doðrudan ulaºmak verimli bir yöntem deðildir.
ݺlemin performansý bufferlama yoluyla artýrýlmaktadýr. Bir dosyaya yazýlacak data ilk önce
bellekteki bir buffer alanýnda saklanýr. Bu buffer alaný dolduðunda ya da yazýlmanýn yapýlacaðý
dosya kapatýldýðýnda bufferdaki data alanýnda ne varsa dosyaya yazýlýr. Buna bufferin
boºaltýlmasý (to flush the buffer) denir.
Giriº dosyalarý da benzer ºekilde bufferlanabilir. Giriº biriminden alýnan data (örneðin
klavyeden) önce buffera yazýlýr.
dosyalarýn bufferlamasý erimlilikte çok büyük bir artýºa neden olur. Çünkü bufferdan (RAM'den)
bir karakter okunmasý ya da buffera bir karakter yazýlmasý ihmal edilecek kadar küçük bir
zaman içinde yapýlýr. Buffer ile dosya arasýndaki transfer ºüphesiz yine vakit alacaktýr ama bir
defalýk blok transferi, küçük küçük transferlerin toplamýndan çok daha kýsa zaman alacaktýr.
stdio.h baºlýk dosyasý içinde prototipi bildirimi yapýlan ve dosyalarla ilgili iºlem yapan
fonksiyonlar tamponlamayý otomatik olarak gerçekleºtirirler. Yani dosyalarýn tamponlanmasý
için bizim birºey yapmamýza gerek kalmadan bu iº geri planda bize sezdirilmeden
yapýlmaktadýr. Ama bazý durumlarda tamponlama konusunda programcý belirleyici durumda
olmak isteyebilir. ݺte bu durumlarda programcý dosya tamponlama fonksiyonlarýný (fflush,
setbuf, setvbuf) kullanacaktýr:
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
335
Buy RoboPDF
33 . BÖLÜM :
fflush fonksiyonu
Bir program çýktýsýný bir dosyaya yazarken (örneðin stdout dosyasýna) yazýlan dosya ilk önce
RAM'deki tamponlama alanýna gider. Dosya kapatýldýðýnda ya da tamponlama alaný
dolduðunda, tamponlama alaný boºaltýlarak dosyaya yazýlýr. fflush fonksiyonunun
kullanýlmasýyla, dosyanýn kapatýlmasý ya da tamponlama alanýnýn dolmasý beklenmeksizin,
tamponlama alaný boºatýlarak dosyaya yazýlýr. Bu iºlem istenilen sýklýkta yapýlabilir.
Fonksiyonun prototipi :
int fflush (FILE *stream);
ºeklindedir.
fflush(fp);
çaðýrýmý ile FILE yapýsý türünden fp göstericisi ile iliºkilendirilen dosyanýn tamponlama alaný
(buffer) boºaltýlýr. Eðer fflush fonksiyonuna NULL adresi gönderilirse, açýk olan bütün dosyalarýn
tamponlama alanlarý boºaltýlacaktýr.
Tamponlama alanýnýn boºaltýlmasý iºlemi baºarýlý olursa fflush fonksiyonu 0 deðerine geri
dönecek aksi halde EOF deðerine geri dönecektir.
setvbuf fonksiyonu
setvbuf fonksiyonu bir dosyanýn tamponlanma ºeklinin deðiºtirilmesi ve tampon alanýnýn
yerinin ve boyutunun deðiºtirilmesi amacýyla kullanýlýr. Fonksiyonun prototipi aºaðýdaki
ºekildedir :
int setvbuf(FILE *stream, char *buf, int mode, size_t size);
Fonksiyona gönderilen üçüncü arguman tamponlama ºeklini belirler. Üçüncü argumanýn deðeri
stdio.h baºlýk dosyasý içinde tanýmlanan sembolik sabitlerle belirlenir.
_IOFBF (full buffering - tam tamponlama)
data dosyaya tamponlama alaný dolduðunda yazýlýr. Ya da giriº tamponlamasý söz konusu ise
dosyadan okuma tamponlama alaný boº olduðu zaman yapýlýr.
_IOLBF (line buffering - satýr tamponlamasý)
Tamponlama alaný ile dosya arasýndaki okuma ya da yazma iºlemi satýr satýr yapýlýr.
_IONBF (no buffering - tamponlama yok)
Dosyadan okuma ya da soyaya yazma tamponlama olmadan doðrudan yapýlýr.
setvbuf fonksiyonuna gönderilen ikinci arguman RAM'de tamponlamanýn yapýlacaðý bloðun
baºlangýç adresidir. Tamponlamanýn yapýlacaðý alan statik ya da dinamik ömürlü olabileceði
gibi, dinamik bellek fonksiyonlarýyla da tahsis edilebilir.
Fonksiyona gönderilen son arguman tamponlama alanýnda tutulacak bytelarýn sayýsýdýr.
setvbuf fonksiyonu dosya açýldýktan sonra, fakat dosya üzerinde herhangi biri iºlem yapýlmadan
önce çaðýrýlmalýdýr. Fonksiyonun baºarýlý olmasý durumunda fonksiyon 0 deðerine geri
dönecektir. Fonksiyona gönderilen üçüncü argumanýn geçersiz olmasý durumunda ya da
fonksiyonun ilgili tamponlamayý yapamamasý durumunda, geri dönüº deðeri 0 dýºý bir deðer
olacaktýr.
Fonksiyona
gönderilen
buffer
alanýnýn
geçerliliðinin
bitmesinden
önce
(ömrünün
tamamlanmasýndan önce) dosya kapatýlmamalýdýr.
dosya iºlemleri ile ilgili örnek uygulamalar:
Uygulama 1 : Dosya üzerinde sýralý veri tabaný tutulmasý
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
336
Buy RoboPDF
DOSYALAR
#include
#include
#include
#include
<stdio.h>
<stdlib.h>
<conio.h>
<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);
}
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
337
Buy RoboPDF
33 . BÖLÜM :
void FindRec(void)
{
PERSON per;
char name[30];
printf("lütfen kayýt 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("\nKayýt 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 kayýtýn 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 kayýt bulunamadý");
}
void EditRec(void)
{
char name[30];
PERSON per;
printf("Deðiºtirilecek kayýtýn adý ve soyadý : ");
fflush(stdin);
gets(name);
fseek(f, 0, SEEK_SET);
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
338
Buy RoboPDF
DOSYALAR
while (fread(&per, sizeof(PERSON), 1, f) > 0) {
if (per.delflag == NORMALREC && !stricmp(per.name, name)) {
printf("Adý soyadý : ");
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("deðiºtirilecek kayýt bulunamadý\n");
}
int GetOption(void)
{
int option;
printf("\n1) Kayýt Ekle\n");
printf("2) Kayýt Listele\n");
printf("3) Kayýt Bul\n");
printf("4) Kayýt Sil\n");
printf("5) Kayýt deðiºtir\n");
printf("6) Pack\n");
printf("7) Sýrala\n");
printf("8) Çýk\n");
printf("\nSeçiminiz :");
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);
}
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
339
Buy RoboPDF
33 . BÖLÜM :
}
}
} while (chgFlag);
}
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("Geçersiz Seçenek!..\n");
}
}
EXIT:
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
340
Buy RoboPDF
DOSYALAR
fclose(f);
}
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;
}
}
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
341
Buy RoboPDF
33 . BÖLÜM :
return GOOD;
}
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);
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
342
Buy RoboPDF
DOSYALAR
}
printf("File being copied: %s ---> %s\n", argv[1], OutFile);
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 dosyanýn belirkli byte büyüklüðünde n kadar sayýda dosyaya bölünmesi ve daha sonra baºka bir
programla bu dosyalarýn tekrar birleºtirilmesi.
/*******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);
}
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
343
Buy RoboPDF
33 . BÖLÜM :
fd = NULL;
while ((ch
if (fd
fd
if
= fgetc(fs)) != EOF) {
== NULL) {
= fopen(fdname, "wb");
(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);
%d
adet
dosyaya
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);
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
344
Buy RoboPDF
DOSYALAR
exit(EXIT_FAILURE);
}
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);
dosya
altinda\
for (k = 1; k <= no_of_files; ++k) {
sprintf(fsname, "dos%04d.xxx", k);
remove(fsname);
printf("%s dosyasi silindi!\n", fsname);
}
return 0;
}
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
345
Buy RoboPDF
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
Buy RoboPDF
enum TÜRÜ VE enum SABÝTLERÝ
34 . BÖLÜM : enum TÜRÜ VE enum SABÝTLERÝ
Yazýlan bir çok programda, yalnýzca belirli anlamlý deðerler alabilen deðiºkenler kullanma
ihtiyacý duyulur. Örneðin bir "Boolean" deðiºkeni, yalnýzca iki deðere sahip olabilmektedir
(doðru ve yanlýº deðerleri) C dilinde Boolean diye bir veri tipinin olmadýðýný hatýrlayalým. Baºka
bir örnek olarak bir oyun kaðýdýnýn rengini tutacak bir deðiºkeni verebiliriz. Böyle bir deðiºken
yalnýzca 4 deðiºik deðer alabilecektir : Sinek, Karo, Kupa, Maça. Uygulamalarda yapýlacak olan,
deðiºkene tamsayý deðerleri vermek ve her tamsayýyý deðiºkenin alacaðý deðerle
iliºkilendirmektir. örneðin:
int renk;
/* renk deðiºkeni iskambil kaðýdýnýn renk bilgisini tutacak */
renk = 1;
/* 1 tamsayý sabitinin karoyu temsil ettiðini varsayalým */
Böyle bir teknik uygulamalarda pekala kullanýlabilir. Ancak bu tekniðin
algýlanabilmesinin ve okunabilmesinin zor olmasýdýr. Programý okuyacak kiºi
dezavantajý,
int renk;
tanýmlama ifadesini gördüðü zaman, renk deðiºkeninin yalnýzca 4 farklý deðer alabileceðini
bilemediði gibi,
renk = 1;
ºeklinde bir atama yapýldýðýný gördüðünde de renk deðiºkenine "karo" deðerinin atanmýº
olduðunu anlayamaz.
Sembolik sabitlerin kullanýlmasý ile okunabilirlik büyük ölçüde artýrýlabilir. Yukarýdaki örneðimiz
için aºaðýdaki sembolik sabitlerin tanýmlanmýº olduðunu düºünelim:
#define
#define
#define
#define
#define
KARTRENK
SINEK
KARO
KUPA
MACA
int
1
2
3
4
KARTRENK renk;
renk = KARO;
Artýk ifade daha okunabilir bir hale getirilmiºtir. Bu yöntem ilk kullanýlan teknikten ºüphesiz
daha iyidir, ama yine de en iyi çözüm olduðu söylenemez. Yukarýdaki sembolik sabit
tanýmlamalarýnýn ayný türe ait olduðunu programý okuyan kiºiye gösterecek bir ibare yoktur.
Türün alabileceði deðer sayýsý daha fazla sayýda ise her biri için bir sembolik sabit tanýmlamak
zahmetli olacaktýr. KARO, KUPA vs. olarak isimlendirdiðimiz sembolik sabitler programýn
derlenmesinden önce, öniºlemci aºamasýnda tamsayý sabitlerle yer deðiºtireceðinden, hata
ayýklama (debug) aºamasýnda artýk bu sabitlere ulaºýlamayacaktýr.
C dili, tasarýmý yapýlan tür için yalnýzca belirli deðerlerin alýnabilmesini saðlayan bir türe
sahiptir. Bu tür enum anahtar sözcüðüyle belirtilir. Türün alabileceði belirli deðerleri gösteren
isimlere ise enum sabitleri (enumeration constants) denir.
enum Türünün ve enum Türüne Ýliºkin enum Sabitlerinin Bildirimi
enum [türün ismi] {esabit1, esabit2, ......};
enum bir anahtar sözcüktür. Derleyici küme parantezleri arasýnda isimlendirilmiº sembolik
sabitlere 0 deðerinden baºlayarak artan sýrada bir tamsayý karºýlýk getirir. Örnek:
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
347
Buy RoboPDF
34 . BÖLÜM :
enum RENK {Sinek, Karo, Kupa, Maca};
gibi bir bildirim yapýldýðýnda Sinek enum sabiti 0, Karo enum sabiti 1, Kupa enum sabiti 2,
Maca enum sabiti ise 3 deðerini alýr.
enum BOOL {FALSE, TRUE};
burada TRUE enum sabiti 1 FALSE enum sabiti ise 0 deðerini alacaktýr.
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 deðerinden baºlatarak ardýºýl olarak deðer verilir.
Eðer enum sabitlerine atama operatörü ile küme parantezleri içinde deðerler verilirse, bu
ºekilde deðer verilmiº enum sabitinden sonraki sabitlerin deðerleri birer artarak otomatik
olarak verilmiº olur:
enum MONTHS {January = 1, February, March, April, May, June, July, August,
September, Oktober, November, December};
Artýk ayný örnek için enum sabitlerinin deðerleri January = 1, February = 2, ... December = 12
olmuºtur.
enum sabitlerine int türü sayý sýnýrlarý içerisinde pozitif ya da negatif deðerler verilebilir :
enum Sample {
RT1 = -127,
RT2,
RT3,
RT4 = 12,
RT5,
RT6,
RT7 = 0,
RT8,
RT9 = 90
};
Yukarýdaki tanýmlamada sabitlerin alacaðý deðerler aºaðýdaki gibi olacaktýr :
RT1 = -127, RT2 = -126, RT3 = -125, RT4 = 12, RT5 = 13, RT6 = 14, RT7 = 0, RT8 = 1, RT9
= 90
Görüldüðü gibi bir enum sabitine atama operatörü ile atama yapýldýðý zaman onu izleyen
enum sabitlerinin alacaðý deðerler, bir sonraki atamaya kadar, ardýºýl olarak deðerleri 1'er
artarak biçimde oluºturulur.
Yukarýdaki ifadelerin hepsi bildirim ifadeleridir, tanýmlama iºlemi deðildir. Bir baºka deyiºle
derleyici bir nesne yaratmamakta ve dolayýsýyla bellekte bir yer ayýrmamaktadýr.
enum bildirimi tür bildirmektedir. Bildirilen tür enum türünün yaratýlmasýnda kullanýlan enum
tür ismidir. (enumeration tag). Týpký yapýlarda ve birliklerde olduðu gibi bu türden bir nesne de
tanýmlanabilir:
enum
enum
enum
enum
Sample rst;
MONTHS this_month;
RENK kart1, kart2, kart3;
BOOL flag1, openflag, endflag, flag2;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
348
Buy RoboPDF
enum TÜRÜ VE enum SABÝTLERÝ
Bildirimlerde enum tür ismi (enumeration tag) hiç belirtilmeyebilir. Bu durumda genellikle
küme parantezinin kapanmasýndan sonra o enum türünden nesne(ler) tanýmlanarak ifade
noktalý virgül ile sonlandýrýlýr.
enum {Sunday = 1, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday} day1, day2,
day3;
Yukarýdaki örnekte day1, day2, day3 bildirimi yapýlmýº enum türünden (belirli bir enum tür
ismi yok) yaratýlmýº deðiºkenlerdir. Böyle bir tanýmlama iºleminin dezavantajý, artýk bir daha
ayný enum türünden baºka bir deðiºkenin yaratýlmamasýdýr.
enum türünden bir nesne için derleyici, kullanýlan sistemde int türünün uzunluðu ne kadar ise,
o uzunlukta bir yer ayýrýr. Derleyici için enum türden bir nesne ile int türden bir nesne
arasýnda herhangi bir fark bulunmamaktadýr.
örneðin DOS altýnda:
sizeof(rst) == sizeod(rst) == sizeof(this_month) == sizeof(kart1) == sizeof(flag1) == 2
olacaktýr.
enum ile bir tür tanýmlandýðýna göre, bu türden nesne yaratýlabileceði gibi fonksiyonlarýn geri
dönüº deðerleri ve / veya parametre deðiºkenleri de enum ile yaratýlmýº türden olabilirler.
Örneðin :
RENK kartbul (RENK kart1, RENK kartt2);
Kartbul fonksiyonu enum RENK türünden iki parametre almakta ve enum RENK türünden bir
deðere ger dönmektedir.
Aºaðýdaki program parçasýný 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 deðiºkenleri enum RENK türündendir. Prototipini gördüðümüz kartbul
fonksiyonu da enum RENK türünden iki parametre almakta ve enum KART türünden bir
deðere geri dönmektedir. Dolayýsýyla program parçasý içinde kartx deðiºkenine enum RENK
türünden bir deðer atanmýº olacaktýr.
enum sabitleri ve #define öniºlemci komutuyla tanýmlanmýº sembolik sabitler nesne
belirtmezler. Örneðin:
enum METAL {Demir, Bakir, Kalay, Cinko, Kursun};
...
Bakir = 3;
/* hata oluºturur. Çünkü enum sabitleri sol taraf deðeri deðillerdir. */
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
349
Buy RoboPDF
34 . BÖLÜM :
#define komutu öniºlemciye iliºkindir fakat enum sabitlerini ele alarak iºleme sokmak derleme
modülüne iliºkindir. Yani #define ve enum farklý aºamalarda ele alýnýrlar. enum sabitleri çok
sayýda ve ardýºýl tanýmlamalar için tercih edilirler ve bir tür ismi olarak da okunabilirliði
artýrýrlar. Örneðin:
BOOL isprime(int x);
gibi bir prototipi gören programcý isprime fonksiyonunun yalnýzca doðru ya da yanlýº
deðerlerinden birini ürettiðini, böylelikle fonksiyonun test amacýyla yazýldýðýný anlar.
enum sabitleri C dilinin faaliyet alaný kurallarýna uyarlar. Eðer bir enum türü bir fonksiyon
içinde bildirilmiºse bu türe iliºkin enum sabitleri sözkonusu fonksiyonun dýºýnda tanýnmazlar.
Derleyicilerin standart baºlýk dosyalarýnda bir çok enum türü ve bu türlere iliºkin sembolik
sabitler tanýmlanmýºtýr. Örneðin aºaðýdaki enum bildirimi 80x86 sistemlerinde çalýºan bir
Borland derleyicisinin GRAPHICS.H dosyasýndan alýnmýºtýr.
enum COLORS {
BLACK,
BLUE,
GREEN,
CYAN,
RED,
MAGENTA,
BROWN,
LIGHTGRAY,
DARKGRAY,
LIGHTBLUE,
LIGHTGREEN,
LIGHTCYAN,
LIGHTRED,
LIGHTMAGENTA,
YELLOW,
WHITE
};
enum tür isimleri de yapý ve birliklerde olduðu gibi, typedef anahtar sözcüðü yardýmýyla tip
isimlerine dönüºtürülebilirler. Örneðin:
typedef enum {Sinek, Karo, Kupa, Maca} renk;
bildiriminden sonra artýk enum anahtar sözcüðü kullanýlmadan
renk kart1, kart2, kart3, kart4;
gibi bir tanýmlama yapýlabilir. artýk renk bir tip ismi belirtmektedir. enum türü için çok
kullanýlan bir typedef örneði de:
typedef enum {FALSE, TRUE} BOOL;
(C++ dilinde struct, union ve enum türüne iliºkin isimler ayný zamanda türün genel ismi
olarak kullanýlabileceði için yukarýdaki gibi bir typedef bildirimine gerek kalmayacaktýr. )
enum Türünün ve enum Sabitlerinin Kullanýmýna Ýliºkin Uyarýlar
enum türü ile bildirilen tür ismi kapsamýnda bildirimi yapýlan sembolik sabitlerin tamsayý olarak
derleme aºamasýnda deðerlendirildiði söylenmiºti. enum türünden tanýmlanan bir deðiºkene
enum ºablonunda belirtilen sembolik sabitler yerine tamsayýlar ile atama yapýlabilir.
enum BOOL {TRUE, FALSE} flag1;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
350
Buy RoboPDF
enum TÜRÜ VE enum SABÝTLERÝ
tanýmlamasýnda
flag1 = FALSE;
yerine
flag1 = 1; ºeklinde atama yapabiliriz?
Verilen örnekte flag1 enum BOOL türünden bir deðiºkendir, ve derleyici enum türünden bir
deðiºken ile int türden bir deðiºken aarsýnda fark gözetmez. Ancak derleyicilerin çoðu,
programcýnýn bunu bilinçsizce ya da yanlýºlýkla yaptýðýný düºünerek bir uyarý mesajý verirler.
Yukarýda verilen örnek için verilebilecek tipik bir uyarý mesajý :"assigning int to BOOL" ºeklinde
olacaktýr.
enum türden bir deðiºkene ºablonda belirtilen sýnýrlar dýºýnda kalan deðerleri de atayabiliriz.
Yukarýdaki örnek için:
flag1 = 10;
ºeklinde atama yapabiliriz. (Bu durumda doðal olarak yine ayný uyarý mesajýný alýrýz.)
Dahasý enum türden bir deðiºkene baºka türden bir deðiºken ya da sabit de atayabiliriz. Bu
durumda tür dönüºümü kurallarý gereði atamadan önce otomatik tür dönüºümü yapýlarak sað
taraf ifadesi int türüne dönüºtürülecektir.
double x = 5.6;
flag1 = x;
Bu durumda x deðiºkenine 5 deðeri atancaktýr.
Unutulmamasý gereken ºudur: enum türünün kullanýlmasýnýn nedeni öncelikle okunabilirliði
artýrmaktýr. Yukarýdaki atamalarý yapmamýz teknik olarak mümkün olmakla birlikte, bu örnekler
okunabilirliði kötü yönde etkilediklerinden ancak bilinçsiz kullanýma örnek olabilir. Ýdeal durum,
enum türden nesnelere ilgili enum türü için önceden belirlenmiº enum sabitlerini atamaktýr.
Bir enum nesnesini operatörler iºleme sokabiliriz. Örneðin:
Derleyici enum türünden nesneleri ayný int türü gibi ele alacaðýndan enum türünden nesneler
de int türden nesneler gibi operatörler yardýmýyla yeni ifadelerin oluºturulmasýnda
kullanýlabilirler.
enum sabitlerinin kendisi sol taraf deðeri gerektiren durumlarda
kullanýlamazlar.
enum {Sunday = 1, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday} day1, day2,
day3;
Yukarýdaki tanýmlamadan sonra
++Sunday;
gibi bir ifade geçersiz olacaktýr. Çünkü enum sabitleri bir soltaraf deðeri deðildir.
++day1;
ifadesi ise geçerlidir. ++day1 ifadesi day1 + 1 anlamýna geleceðinden, sonuçta day1'e (enum
türünden deðiºken) int türden bir sayý atanmýº olacaðýndan bazý derleyiciler bu durum için bir
uyarý verebilirler.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
351
Buy RoboPDF
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
Buy RoboPDF
MAKROLAR
35 . BÖLÜM : MAKROLAR
Öniºlemci komutlarýndan, #define öniºlemci komutunun sembolik sabit tanýmlamalarýnda
kullanýlýºýný daha önce görmüºtük. Makrolar #define öniºlemci komutunun paremetreli
kullanýmý ile elde edilen yapýlardýr.
#define öniºlemci anahtar sözcüðünü izleyen isim parametreli olarak kullanýlabilir. Bu durum
sentaks olarak isime bitiºik olarak yazýlan açýlan parantez ile belirtilir. Bu parantezin içinde
tanýmlanan makroya iliºkin parametre(ler) yer alýr. Kapanan parantezi izleyen yazý ise makroya
iliºkin deðiºtirme listesidir. Öniºlemci makro parametrelerine iliºkin deðiºtirme listesini bir
ºablon olarak kabul eder ve kaynak kod içinde makronun çaðýrýldýðýný tespit ettiðinde makro
çaðýrýmýnda kullanýlan argumanlarý, ºablona uygun olarak açar.
Basit bir örnekle baºlayalým:
#define Alan(x, y)
((x) * (y))
Yukarýdaki makro tanýmlamasýnda x ve y makroya iliºkin parametrelerdir. Öniºlemci yukarýdaki
satýrý gördükten sonra kaynak kod içinde bu makronun çaðýrýldýðýný tespit ederse, makroyu
yukarýdaki ºablona göre açacaktýr. Örneðin kaynak kod içerisinde
a = Alan(b, c);
ºeklinde bir deyimin yer aldýðýný düºünelim. Bu durumda öniºlemci Alan makrosunun
çaðýrýldýðýný anlar. Ve ifadeyi aºaðýdaki ºekilde açar :
a = ((b) * (c));
Makro açýlýmýnýn sadece metinsel bir yer deðiºtirme oldugunu bilmeliyiz. Yani yukarýdaki deyim
örneðin :
a = Alan(7 + 3, 8 + 1);
ºeklinde olsaydý, öniºlemci bunu
a = ((7 + 3) * (8 + 1));
ºeklinde açacaktý. Yer deðiºtirme iºlemcinin derlemenin ön modülü olan öniºlemci tarafýndan
derleme öncesi yapýldýðýný ve derleyicinin object kod oluºturmak için ele aldýðý kaynak kodun
öniºlemci modülünün çýktýsý olduðunu hatýrlatalým. Yani derleyicinin ele aldýðý kodda artýk
makro çaðýrýmlarý deðil makrolarýn öniºlemci tarafýndan açýlmýº biçimleri bulunacaktýr.
Baºka 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;
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
353
Buy RoboPDF
35 . BÖLÜM :
Yukarýdaki kaynak kodu alan öniºlemci iºini bitirdikten sonra derleyicinin ele alacaðý kaynak
kod aºaðýdaki ºekilde olacaktýr :
stdio.h dosyasýnýn içeriði
int main()
{
int a = 10;
int b = 5;
int c;
}
c = (((a) - (b)) * ((a) + (b)));
printf("c = %d\n", c);
return 0;
Bir yýlýn artýkyýl olup olmadýðýný test etmek için kullanýlacak baºka bir makro:
#define is_leap(y)
((y) % 4 == 0 && (y) % 100 != 0 || (y) % 400 == 0)
Makrolar Ne Amaçla Tanýmlanýr
Makrolar fonksiyonlara bir alternatif olarak kullanýlmaktadýr. Yukarýdaki ö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ý tanýmlanabilirdi.
Baºka bir örnek olarak da toupper fonksiyonunun makro biçiminde tanýmlanmýº olmasý
verilebilir. (toupper derleyicilerin çoðunda fonksiyon olarak deðil makro biçiminde
tanýmlanmýºtýr.)
#define TOUPPER(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
Aºaðýda fonksiyon tanýmlamalarýna alternatif olacak bazý basit makrolar tanýmlanmaktadýr:
#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. Örneðin:
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
354
Buy RoboPDF
MAKROLAR
#define getchar()
getc(stdin)
Yukarýdaki makro yerine sembolik sabit de kullanýlabilirdi. Ancak fonksiyon yapýsýna benzetmek
amacýyla parametresi olmayan bir makro olarak tanýmlanmýºtýr.
Makrolarla Fonksiyonlar Arasýndaki Farklýlýklar Nelerdir
Makrolar fonksiyonlara alternatif olarak kullanuýlmalarýna karºýlýk, makrolar ile fonksiyonlar
arasýnda çok önemli farklar bulunmaktadýr:
1. Makrolar kaynak kodu dolayýsýyla da çalýºabilir (exe) kodu büyütürler. Makrolar öniºlemci
aºamasýnda deðerlendirilir. Örneðin is_leap makrosunun #define öniºlemci komutuyla
tanýmlandýktan sonra kaynak kod içinde yüz kere çaðýrýldýðýný düºünelim. Öniºlemci kaynak
kodu ele aldýðýnda yüz tane çaðýrýlma ifadesinin her biri için makroyu açacaktýr. Derleyici
modülü kaynak kodu ele aldýðýnda artýk makrolarý deðil makrolarýn açýlmýº ºeklini
görecektir. Makro açýlýmlarý kaynak kodu büyütecektir. Kaynak kodun büyümesinden dolayý
çalýºabilen dosyanýn boyutu da büyüyecektir. Oysa makro yerine bir fonksiyon
tanýmlansaydý, Fonksiyon çaðýrýlmasý durumunda yalnýzca çaðýrýlma bilgisi kayanak koda
yazýlmaktadýr.
2. Makrolarýn en büyük avantajý, fonksiyon çaðýrma iºlemindeki göreli yavaºlýktan kaynaklanýr.
Fonkiyon çaðýrmasý sembolik makine dili (assembler) düzeyinde ele alýndýðýnda, bazý ilave
makine komutlarý da icra edilmekte ve bu makine komutlarýnýn icrasý ve yapýlan bazý ilave
iºlemler icra süresini uzatacaktýr.
Fonksiyon çaðýrýlýrken CALL ve geri dönüºte RET makine komutlarý icra edilmektedir.
Fonksiyon çaðýrýmý için ayrýca parametre aktarýmý ve stack düzenlemesi iºlemleri
yapýlmaktadýr. Makrolarýn açýlmasý metinsel bir yer deðiºtirme olduðu için, yukarýda
anlatýlan ilave iºlemler yapýlmaz. Böyºece programýn hýzý görece olarak artacaktýr.
3. Makrolar türden baðýmsýzdýr. (generic). Makrolar metinsel bir yer deðiºtirme olduðundan
fonksiyonlar gibi belirli bir türe baðlý deðildirler. Örneðin iki sayýdan büyüðüne geri dönen
bir fonksiyon yazmak istersek bu fonksiyonun parametre deðiºkenleri belirli bir türden
olmak zorundadýr:
int max_of_two(int number1, int number2)
{
return (number1 > number2 ? number1 : number2);
}
Yukarýdaki fonksiyon int türden deðerler için yazIlmýºtýr. Baºka türden deðerler fonlksiyona
arguman olarak gönderildiðnde tür dönüºümü kurallarý iºleyecek ve argumanlarýn türü
parametre deðiºkenlerinin türlerine dönüºtürülecektir. Oysa yukarýdaki fonksiyon yerine bir
makro tanýmlanmýº olmasý durumunda bu makro türden baðýmsdýz olacaktýr :
#define max_of_two(a, b) ((a) > (b) ? (a) : (b))
Yukarýdaki makro aºaðýdaki ºekillerde çaðýrýlabilir:
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 gönderilen argumanlarý bir kez ele alýrlar ancak makrolar
argumanlarýný birden fazla ele alabilirler:
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
355
Buy RoboPDF
35 . BÖLÜM :
Aºaðýdaki makrolarý göz önüne alalým:
#define KARE(a)
((a) * (a))
int x = 10, y;
y = KARE(x++)
ifadesi makro tanýmlamasýna uygun olarak açýldýðýnda
y = ((x++) * (x++))
ifadesi oluºacaktýr ki bu ifade de, operatörler konusunda gördüðümüz gibi "undefined behavior"
özelliði gösterecektir. Oysa KARE bir fonksiyon olsaydý bu fonksiyonun
KARE(x++);
ºeklinde çaðýrýlmasý bir probleme neden olmayacaktý. x++ ifadesi x deðiºkeninin (artmayan)
deðerini üreteceðinden, KARE fonksiyonu 10 deðeri ile çaðýrýlmýº olacaktý.
5. Makrolarda makrolarýn argumanlarý ile parametreleri arasýnda tür dönüºtürülmesi söz
konusu deðildir.
Bir fonksiyon çaðýrýlma ifadesini gördüðünde derleyici fonksiyona gönderilen arguman ile
fonksiyonun ilgili parametre deðiºkeni arasýndaki tür uyumunu kontrol eder. Eðer bu türler
arasýnda bir farklýlýk varsa, mümkünse, tür dönüºtürme kurallarý gereði arguman olan ifdadenin
türünü parametre deðiºkeninin türüne çevirir. Makro argumanlarýnýn öniºlemci tarafýndan
makronun parametrelerine göre tür uyumunun kontrol edilmesi ya da tür dönüºtürme iºlemine
tabi tutulmasý söz konusu deðildir.
C++ dilinde makrolarýn kullanýmý C diline göre çok daha azalmýºtýr. Zira C++ dilinde bir çok
durumda makrolar yerine inline fonksiyonlar kullanýlmaktadýr.
6. Bir gösterici bir makroyu gösteremez.
Ýleride göreceðimiz gibi C dilinde bir fonksiyonu gösteren gösterici tanýmlanabilir. Ve bu
göstericilerden C programcýlýðýnda çeºitli biçimlerde faydalanmak mümkündür. Ancak makrolar
öniºlemci aºamasýnda ele alýndýðýndan bir göstericini bir makroyu göstermesi söz konusu
deðildir.
# ve ## öniºlemci operatörleri
Makro tanýmlamalarý iki özel operatör içerebilirler. Bu operatörler derleyiciyi deðil öniºlemciyi
ilgilendirmektedir. Yani öniºlemcinin çýktýsý derleyici modülüne verildiðinde artýk kaynak kod bu
operatör atomlarýndan arýndýrýlmýº olacaktýr.
# atomu makronun yer deðiºtirme listesinde (replacement list) yer alabilecek bir operatördür.
Operandý makro parametresidir. Makronun açýlýmý sýrasýnda #operandýna alýnan arguman string
haline getirilir. Yani çift týrnak içine alýnýr. Bu yüzden bu atoma stringe dönüºtürme operatörü
de denir. (stringizing operator)
#atomunun kullanýlabileceði
inceleyelim :
#define PRINT_INT(x)
bir
kaç
tema
aºaðýda
verilmektedir.
Aºaðýdaki
makroyu
printf(#x " = %d\n", x)
örneðin kaynak kod içerisinde
int result = 5;
PRINT_INT(result);
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
356
Buy RoboPDF
MAKROLAR
ºeklinde makronun çaðýrýldýðýný düºünelim. Makro açýldýðýnda derleyiciye giden kaynak kod
aºaðýdaki ºekilde olacaktýr :
int result = 5;
printf("result" " = %d\n", result);
Aralarýnda boºluk karakterleri dýºýnda baºka bir karakter bulunmayan stringlerin derleyici
tarafýndan tek bir string olarak birleºtirildiklerini anýmsarsak, yukarýdaki ifadenin derleyici
açýsýndan aºaðýdaki ºekilde yorumlanacaðýný görebiliriz :
printf("result = %d\n", result);
Böylece yukardaki deyimin icra edilmesiyle ekrana aºaðýdaki ºekilde bir yazý yazdýrýlabilecektir
:
result = 5;
## öniºlemci operatörü iki operand alan araek konumunda bir operatördür. Makronun açýlmasý
sýrasýnda Operandý olan atomlarý birleºtirerek tek bir atom haline getirir. Bu yüzden atom
birleºtirme operatörü diye de isimlendirilir. (Token pasting operator),
Atom birleºtirme operatörünün operandlarýndan biri eðer bir makro parametresi ise, birleºtirme
iºlemi parametre ilgili argumanla yer deðiºtirdikten sonra yapýlacaktýr. Atom birleºtirme
operatörü ##, string yapma atomu kadar sýk kullanýlan bir operatör deðildir. Sadece çok özel
durumlarda kullanýlmaktadýr.
Makro tanýmlamalarýnda nelere dikkat edilmelidir?
Makro tanýmlamalarýnda en sýk yapýlan hatalar makro açýlýmý neticesinde, operatör öncelikleri
yüzünden açýlmýº kodun beklenilmeyen ºekilde deðer üretmesidir. Örneklerle açýklayalým :
#define ALAN(a)
a*a
Yularýdaki makro
x = ALAN(y);
ºeklinde çaðýrýlýrsa öniºlemci kodu
x = y * y;
ºeklinde açacaðýndan bir problem oluºmayacaktýr. Ancak makronun
int y = 1;
x = ALAN(y + 5)
ºeklinde çaðýrýldýðýný düºünelim. Bu durumda derleyici kodu
x = y + 5 * y + 5;
ºeklinde açacaktýr. Ve bu durumda y deðiºkenine 36 yerine 11 deðeri atanacaktýr.
Bu tür problemlerin önlenebilmesi için makro tanýmlamalarýnda makro açýlým ifadesinde yer
alan makro parametreleri parantez içine alýnmalýdýr.
Yukarýdaki makro
#define ALAN(a)
(a) * (a)
ºeklinde tanýmlansaydý makro çaðýrýmý öniºlemci tarafýndan açýldýðýnda
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
357
Buy RoboPDF
35 . BÖLÜM :
x = (y + 5) * (y + 5);
ifadesi oluºacaktýr ki, deyimin icrasý sonucunda x deðiºkenine 36 deðeri atanacaktýr.
Peki ya makro aºaðýdaki ºekilde çaðýrýlýrsa
x = 72 / ALAN(y + 5);
x deðiºkenine 2 deðerinin atanmasý gerekireken, makro aºaðýdaki gibi açýlacaðýndan
x = 72 / (y + 5) * (y + 5) ;
x deðiºkenine 72 deðeri atanacaktýr.
Makro tanýmlamalarýnda makro açýlým ifadeleri en dýºarýdan parantez içerisine alýnmalýdýr.
Söz konusu makro
#define ALAN(a)
((a) * (a))
ºeklinde tanýmlanmýº olsaydý
x = 72 / ((y + 5) * (y + 5) );
makro öniºlemci tarafýndan yukarýdaki gibi açýlacaktý ve bu kodun icrasý ile x deðiºkenine
gerçekten 2 deðeri atanacaktý.
Makrolarla ilgili olarak sýk yapýlan baºka bir hata da makro tanýmlamasýnda makro ismi ile
makro parametre parantezi arasýnda boºluk býrakmaktýr. ALAN makrosunun yanlýºlýkla
aºaðýdaki gibi tanýmlandýðýný düºünelim.
#define ALAN (a)
((a) * (a))
Öniºlemci artýk yukarýdaki tanýmlamayý bir makro deðil bir sembolik sabit olarak ele alacaktýr.
Öniºlemci kaynak kodun geri kalan kýsmýnda gördüðü ALAN yazýlarýný (a)
((a) * (a)) ile
yer deðiºtirecektir. Örneðin :
ALAN(x + 3);
gibi bir ifadenin var olduðunu düºünelim. Öniºlemci bu kodu aºaðýdaki ºekilde açacaktýr :
(a)
((a) * (a))(x + 3);
ayný isimli makro ve fonksiyonlar
Bir makro ile ayný isimli bir fonksiyon kaynak kod içinde yer alabilir. Bu durumda bu isimle bir
çaðýrým yapýldýðýnda ne olacaktýr. makro mu fonksiyon mu çaðýrýlmýº olacaktýr?
#define max(x, y)
((x )> (y) ? (x) : (y))
gibi bir makronun tanýmlandýðýný ve kaynak kod içerisinde aºaðýdaki fonksiyon tanýmýnýn da yer
aldýðýný düºünelim.
int max(int number1, int number2)
{
return x > y ? x : y;
}
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
358
Buy RoboPDF
MAKROLAR
Kaynak kod içerisinde örneðin
c = max(a, b);
ºeklinde bir deyimin yer aldýðýný düºünelim. Bu durumda ne olacaktýr?
Tabi ki öniºlemci makroyu açacaktýr. Zira makrolarýn açýlmasý, yani metinsel yer deðiºtirme
iºleminin yapýlmasý,
daha derleyici kaynak kodu ele almadan öniºlemci tarafýndan
yapýlacaðýndan, derleyici modülüne sýra geldiðinde derleyici artýk yukarýdaki çaðýrým ifadesi
yerinde
c = a > b ? a : b;
ifadesini görecektir.
Ayný isimli makro ve fonksiyon tanýmlamalarýnýn var olmasý durumunda, makro açýlýmýn
yapýlmasý yerine fonksiyonunu çaðýrýlmasý isteniyorsa ne yapýlabilir?
Bu durumda fonksiyon çaðýrma ifadesinde fonksiyon ismi parantez içine alýnýrsa, öniºlemci artýk
bir yer deðiºtirme yapmaz ve derleyici fonksiyon çaðýrma kodu üretir.
uzun makrolarýn yazýlmasý
Daha iºlevsel makrolarýn yazýlmasýnda virgül operatörü kullanýlabilir. Aºaðýdaki makroyu
düºünelim:
#define ECHO(s)
(gets(s), puts(s))
Fonksiyon çaðýrýmlarý da birer ifade olduðundan, fonksiyon çaðýrýmý ifadelerinin virgül
operatörüyle birleºtirilmesi tamamen legaldir. Yukarýdaki makroyu bir fonksiyonmuº gibi
çaðýrabiliriz:
char *ptr = "Ahmet";
ECHO(str);
Öniºlemci makroyu aºaðýdaki ºekilde açacaktýr :
char *ptr = "Ahmet";
(gets(str), puts(str));
Ancak bir makronun bir seri deyimi içerdiðini düºünelim. Ýfade yerine belirli sayýda deyimin
olmasý, bazý durumlarda virgül operatörünün kullanýlmasýna izin vermeyebilir. Çünkü virgül
operatörünün operandlarý deyim deðil ifadelerdir.
Uzun ve iºlemsel makrolarýn yazýlmasýnda virgül operatörünün kullanýlmasý yerine makro
deðiºtirme listesini en dýºtan küme parantezleri içine de alabilirdik :
#define ECHO(s)
{ gets(s); puts(s); }
Makro yukarýdaki gibi tanýmlandýðýnda bazý problemler oluºabilir. Örneðin makronun aºaðýdaki
gibi bir if deyimi içinde çaðýrýldýðýný düºünelim :
if (echo_flag)
ECHO(str);
else
gets(str);
Öniºlemci makroyu aºaðýdaki gibi açacaktýr :
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
359
Buy RoboPDF
35 . BÖLÜM :
if (echo_flag)
{ gets(str); puts(str); };
else
gets(str);
Kod derleyici modülüne geldiðinde aºaðýdaki gibi yorumlanacaðýndan
if (echo_flag)
{ gets(str); puts(str); }
;
else
gets(str);
if kýsmý olmayan bir else olmasý gerekçesiyle derleme zamanýnda bir error oluºacaktýr. Oluºan
problemi nasýl çözebiliriz? Makronun çaðýrýlmasý durumunda sonlandýrýcý ";" at0munu
koymayarak? Bu çirkin bir tarz olurdu...
Bu durumda iki yöntem kullanabiliriz :
1. Makro açýlýmýnda do while döngü yapýsýný kullanmak:
#define ECHO(s)
do {
gets(s);
puts(s);
} while (0)
\
\
\
\
(#define öniºlemci komutunun kullanýlmasýnda satýr sonunda yer alan "\"
komutun bir sonraki satýrda devam edeceðini gösterdiðini hatýrlayalým)
karakterinin
artýk yukarýdaki makro
ECHO(str);
ºeklinde çaðýrýldýðýnda, makro öniºlemci tarafýndan açýldýktan sonra,
çaðýrma ifadesinin
sonundaki sonlandýrýcý (;) do while deyiminin sentaksýnda bulunan while parantezini izleyen
sonlandýrýcý olacaktýr.
2. Makro açýlýmýnda if deyimi kullanmak:
#define ECHO(s)
if (1)
{
gets(s);
puts(s);
}
else
\
\
\
\
\
yukarýdaki makro
ECHO(str);
ºeklinde çaðýrýlýp öniºlemci tarafýndan açýldýðýnda makro çaðýrma ifadesinin sonundaki
sonlandýrýcý (;) if deyiminin yanlýº kýsmýna iliºkin (else kýsmýna iliºkin) boº deyim olacaktýr.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
360
Buy RoboPDF
DÝÐER ÖNݪLEMCÝ KOMUTLARI
36 . BÖLÜM : DÝÐER ÖNݪLEMCÝ KOMUTLARI
Daha önceki derslerimizde öniºlemci kavramýný incelemiº ve öniºlemciye iliºkin iki komutu
incelemiºtik. Bu komutlar #include ve #define öniºlemci komutlarýydý. Öniºlemciye iliºkin
diðer komutlarý da bu desimizde ele alacaðýz.
Koºullu derlemeye iliºkin öniºlemci komutlarý
Koºullu derlemeye iliºkin komutlar #if #ifdef ve #ifndef olmak üzere üç tanedir. Koºullu
derleme komutuyla karºýlaºan öniºlemci, koºulun saðlanmasý durumunda belirlenmiº program
bloðunu derleme iºlemine dahil eder, koºul saðlanmýyorsa ilgili program bloðunu çýkartarak
derleme iºlemine dahil etmez.
#if Öniºlemci Komutu
Genel biçimi ºöyledir:
#if <sabit ifadesi>
...
...
#else
...
..
#endif
Sabit ifadesinin sayýsal deðeri sýfýr dýºý bir deðer ise (sabit ifadesi doðru olarak deðerlendirilerek
) #else anahtar sözcüðüne kadar olan kýsým, eðer sabit ifadesinin sayýsal deðeri 0 ise (sabit
ifadesi yanlýº olarak deðerlendirilerek) #else ile #endif arasýndaki kýsým derleme iºlemine
dahil edilir. Örnek :
#include <stdio.h>
int main()
{
#if 1
printf("bu bölüm derleme iºlemine sokulacak\n");
#else
printf("bu bölüm derleme iºlemine sokulmayacak\n");
#endif
}
Öniºlemci, programý # içeren satýrlardan arýndýrarak aºaðýdaki biçimde derleme modülüne
verecektir:
[stdio.h dosyasýnkýn içeriði ]
void main()
{
printf("bu bölüm derleme iºlemine sokulacak\n");
}
#if komutunun saðýndaki sabit ifadesi operatör içerebilir ancak deðiºken içeremez. Örneðin:
#define MAX
100
...
#if MAX > 50
...
#else
...
#endif
Týpký C dilinde olduðu gibi öniºlemci komutlarýnda da #else - #if merdivenlerine sýk raslanýr.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
361
Buy RoboPDF
36 . BÖLÜM :
#define MAX
100
...
#if MAX > 50
...
#else
#if MAX < 1
...
#endif
#endif
yerine
#elif öniºlemci komutu da kullanýlabilir. Ancak bu durumda #elif öniºlemci komutuna iliºkin
#endif ile dýºarýdaki #if komutuna iliºkin #endif ortak olacaktýr.
#define MAX 100
...
#if max > 50
...
#elif MAX > 30
...
#else
...
#endif
Koºullu derleme iºlemi kaynak kodun belirli bölümlerini belli durumlarda derleme iºlemine
sokmak için kullanýlýr.ªüphesiz bu durum programcý tarafýndan da kodun eklenip silinmesiyle
saðlanabilirdi. Ancak #if komutu buna daha kolay olanak saðlamaktadýr.
#ifdef ve #ifndef Öniºlemci Komutlarý
Belli bir sembolik sabitin tanýmlandýðý durumda #else anahtar sözcüðüne kadar olan kýsým,
tanýmlanmadýðý durumda #else ve #endif arasýndaki kýsým derleme iºlemine dahil edilir. Genel
biçimi aºaðýdaki gibidir :
#ifdef <sembolik sabit>
...
#else
...
#endif
Örneðin:
#include <stdio.h>
#define SAMPLE
void main()
{
#ifdef SAMPLE
printf("SAMPLE tanýmlanmýº");
#else
printf("SAMPLE tanýmlanmamýº");
#endif
}
Burada SAMPLE #define ile tanýmlandýðý için #ifdef doðru olarak ele alýnýr ve derleme
iºlemine ilk printf() dahil edilir. #ifdef ile sorgulama yapýlýrken sembolik sabitin ne olarak
tanýmlandýðýnýn bir önemi yoktur.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
362
Buy RoboPDF
DÝÐER ÖNݪLEMCÝ KOMUTLARI
#ifdef öniºlemci komutu ayný baºlýk dosyasýný kullanan ve birkaç modülden oluºan
programlarda yaygýn olarak kullanýlýr. Örneðin dosya1.c, dosya2.c ve dosya3.c modüllerinden
oluºan bir projede project.h isimli bir baºlýk dosyasý ortak olarak kullanýlýyor olsun. Bu durumda
global deðiºkenlerin yalnýzca bir modülde global diðerlerinde extern olarak kullanýlmasý
gerekecektir. Bu aºaðýdaki gibi saðlanabilir.
/*
project.h */
#ifdef
GLBVAR
#define EXTRN
#else
#define EXTRN extern
#endif
/* Global deðiºkenler */
EXTRN int x;
EXTRN int y;
...
ªimdi modüllerin birinde, bu baºlýk dosyasýnýn include edilmesinden önce, GLBVAR adlý bir
sembolik sabit tanýmlanýrsa, öniºlemci EXTRN sözcüðünü sileceðinden (onun yerine boºluk
karakteri kopyalayacaðýndan) o modül için global tanýmlama yapýlmýº olur. Deðilse EXTRN
yerine extern anahtar sözcüðü öniºlemci tarafýndan yerleºtirilecektir. #ifdef önceden
tanýmlanmýº sembolik sabitlerle taºýnabilirliði saðlamak amacýyla da sýklýkla kullanýlmaktadýr.
#ifndef komutu #ifdef komutunun tam tersidir. Yani sembolik sabit tanýmlanmamýºsa #else
kýsmýna kadar olan bölüm, tanýmlanmýºsa #else ile #endif arasýndaki kýsým derleme iºlemine
dahil edilir. Örneðin :
#ifndef BLINK
#define
BLINK
#endif
0x80
Burada BLINK sembolik sabiti ancak daha önce tanýmlanmamýºsa tanýmlanmasý yapýlmýºtýr.
Daha önce tanýmlanmýºsa tanýmlanma iºlemi yapýlmamýºtýr.
defined() Öniºlemci Operatörü
defined bir sembolik sabitin tanýmlanýp tanýmlanmadýðýný anlamak için kullanýlan bir öniºlemci
operatörüdür. Parantez içerisindeki sembolik sabit tanýmlanmýºsa 1 deðerini tanýmlanmamýºsa
0 deðerini üretir. Örneðin
#if defined(MAX)
...
#endif
Burada MAX tanýmlanmýºsa defined öniºlemci operatörü 1 deðerini üretecektir. Bu deðer de
#if tarafýndan doðru olarak kabul edilecektir. Burada yapýlmak istenen #ifdef ile aºaðýdaki gibi
de elde edilebilirdi:
#ifdef MAX
...
#endif
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
363
Buy RoboPDF
36 . BÖLÜM :
Koºullu Derlemeye Ýliºkin Öniºlemci Komutlarý Nerelerde Kullanýlýr
1. Debug Amacýyla
Bir programý yazarken, programýn doðru çalýºýp çalýºmadýðýný test etmek amacýyla birtakým
ilave kodlar yazabiliriz. Bu tür test kodlarýnýn biz programý test ettiðimiz sürece çalýºmasýný
ançak programýnýzý yazýp bitirdikten sonra, yapacaðýmýz son derlemede, bu test kodlarýnýn
derleme iºlemine sokulmamasýný isteriz. Test amacý ile yazýlan kod parçacýklarý derleme
iºlemine DEBUG adlý bir sembolik sabitin deðerine baðlý olarak aºaðýdaki ºekilde derleme
iºlemine katýlýr ya da katýlmaz.
#if DEBUG
...
#endif
Eðer DEBUG öniºlemci sabitinin deðeri 0 ise #if ile #endif arasýndaki kod parçalý derlemeye
iºlemine katýlmaz.
2. Birden Fazla Makinede ya da ݺletim Sisteminde Çalýºacak Programlarýn
Yazýlmasýnda
#if defined(WINDOWS)
...
#elif defined(DOS)
...
#elif defined(OS2)
...
#endif
3. Bir Programýn Farklý Derleyicilerde Derlenmesi Durumunda
#ifdef
...
#else
...
#endif
__STDC__
Yukarýda öniºlemci komutlarý ile derleyicinin standart C derleyicisi olup olmadýðýna bakýlarak
belirli kaynak kod parçalarý derlemeye dahil ediliyor.
4. Bir Baºlýk Dosyasýnýn Bir Kereden Daha Fazla Kaynak Koda Dahil
Edilmesini Önlemek Amacýyla. (multiple inclusion)
Ayný baºlýk dosyasý kaynak koda #include öniºlemci komutuyla iki kez eklenmemelidir. Bir
baºlýk dosyasý bir kaynak koda birden fazla eklenirse ne olur? Baºlýk dosyalarý içinde ne
oldugunu hatýrlayalým :
1. Fonksiyon prototip bildirimleri
Hatýrlayacaðýmýz gibi fonksiyon prototip bildirimlerinin özdeº olarak birden fazla
yapýlmasý bir error oluºumuna neden olmaz.
2. Sembolik sabit ve makro tanýmlamalarý
Özdeº sembolik sabit ve makro tanýmlamalarý kaynak kodun öniºlemci tarafýndan ele
alýnmasý sýrasýnda bir hataya neden olmaz.
3. typedef bildirimleri (tür tanýmlamalarý)
typedef anahtar sözcüðü ile yapýlan tür tanýmlamalarý özdeº olmalarý durumunda yine
derleme zamanýnda bir hata oluºumuna neden olmazlar.
4. Yapý, birlik, bit alaný, enum türü bildirimleri
Bir özdeº olarak bile birden fazla yapýlýrsa derleme zamanýnda hata oluºumuna neden
olur. Bu yüzden bir baºlýk dosyasý kaynak koda birden fazla dahil edilirse ve o baºlýk
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
364
Buy RoboPDF
DÝÐER ÖNݪLEMCÝ KOMUTLARI
dosyasý içinde bir yapýnýn, birliðin, bit alanýnýn ya da enum trünün bildirimi yapýlmýº ise
derleme zamanýnda error olulºacaktýr. Dolayýsýyla baºlýk dosyasýnýn ikinci kez kaynak
koda eklenmesi engellenmelidir.
Bir baºlýk dosyasýnýn kaynak koda birden fazla eklenmesi aºaðýdaki gibi engellenebilir:
/* GENERAL. H
BÝR BAªLIK DOSYASI ÖRNEÐÝ */
#ifndef GENERAL_H
...
#define GENERAL_h
...
#endif
Yukarýdaki kod parçasýnda baºlýk dosyasý #ifndef ve #endif öniºlemci komutlarýnýn
arasýna alýnmýºtýr. Eðer GENERAL_H sembolik sabiti tanýmlanmýºsa, bu general.h baºlýk
dosyasýnýn kaynak koda daha önce dahil edildiði anlamýna gelecek ve #ifndef ile #endif
arasýndaki kaynak kod parçasý kaynak koda eklenmeyecektir. Eðer GENERAL_H sembolik
sabiti tanýmlanmýº ise, #ifndef ile #endif arasýndaki kaynak kod parçasý kaynak koda
eklenecektir. Eklenen kod parçasý içinde #define GENERAL_h öniºlemci komutu da
bulunmaktadýr.
Bu standart yöntemle, yani baºlýk dosyalarýnýn bir sembolik sabitin tanýmlanmasýna baðlý
olarak kaynak koda eklenip eklenmemesi saðlanýr böylece bir kaynak kodun birden fazla
kaynak koda eklenmesi engellenmiº olur.
Koºullu derlemeye iliºkin öniºlemci komutlarýnýn kullanýlmasýna iliºkin bir program parçasý
örneði aºaðýda verilmiºtir :
#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
Yukarýdaki örnekte birinci #if bloðunun altýnda iki ayrý #if #else yapýsý bulunmaktadýr. DLEVEL
sembolik sabitinin 5'den büyük olup olmamasýna göre deðerine göre öniºlemci tarafýndan doðru
kýsým ya da yanlýº kýsým ele aýacaktýr.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
365
Buy RoboPDF
36 . BÖLÜM :
#elif öniºlemci komutunun da yer aldýðý ikinci #if bloðunda ise DLEVEL sembolik sabitinin
deðerine göre 4 seçenekten biri ele alýnacaktýr. DLEVEL sembolik sabitinin deðerine baðlý olarak
STACK sembolik sabiti 0, 100 ya da 200 olarak tanýmlanmaktadýr. DLEVEL sembolik sabitinini
deðerinin 5'den büyük olmasý durumunda ise
display(debugptr);
deyimi derleyiciye verilmekte ve bu durumda STACK sembolik sabiti tanýmlanmamaktadýr.
Genel Öniºlemci Komutlarý
#undef öniºlemci komutu
Bir sembolik sabitin ilki ile özdeº olmayan bir biçimde ikinci kez tanýmlanmasý C öniºlemcisi
tarafýndan "uyarý " olarak deðerlendirilir. Bu durumda ilk tanýmlananýn mý ikinci tanýmlananýn
mý geçerli olacaðý taºýnabilir bir özellik deðildir. (Derleyiciler genellikle ikinci tanýmlanma
noktasýna kadar ilkinin, ikinci tanýmlanma noktasýndan sonra ise ikincinin geçerliliðini kabul
ederler.)
Örneðin aºaðýdaki gibi bir tanýmlama iºlemi uyarý gerektirir.
#define MAX 100
...
#define MAX 200
Bir sembolik sabitin ilki ile özdeº olarak tanýmlanmasýnda herhangi bir problem çýkmayacaktýr.
Bir sembolik sabit ikinci kez tanýmlanmak isteniyorsa önce eski tanýmlamayý ortadan kaldýrmak
gerekmektedir. Bu iºlem #undef öniºlemci komutu ile yapýlýr. #undef öniºlemci komutunun
yanýna geçerliliði ortadan kaldýrýlacak sembolik sabitin ya da makronun ismi yazýlmalýdýr.
Örneðin :
#undef MAX
#define
MAX 200
Önce
MAX sembolik sabitinin tanýmlanmasý iptal edilmiº, sonra 200 olarak yeniden
tanýmlanmýºtýr. #undef ile tanýmlanmasý kaldýrýlmak istenen sembolik sabit, daha önce
tanýmlanmýº olmasa bile bu durum bir probleme yol açmaz. Örneðin yukarýdaki örnekte MAX
tanýmlanmamýº olsaydý bile bir uyarý ya da hataya yol açmazdý.
#error öniºlemci komutu
Öniºlemci #error komutunu görünce bu komutu izleyen mesajý basarak derleme iºlemibne son
verir. Örneðin:
#ifdef
#error
#endif
__TINY__
Bu program tiny modelde derlenmez!..
#error direktifi
error öniºlemci komutunun yanýnda (boºluk karakteri ile ayrýlmýº) bir hata mesajý yer alýr.
Derleyici error direktifini görünce bu hata mesajýný yazarak deleme iºlemine son verecektir.
#ifdef __TINY__
#error bu program tiny modelde derlenemez
#endif
ÖNCEDEN TANIMLANMIª SEMBOLÝK SABÝTLER
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
366
Buy RoboPDF
DÝÐER ÖNݪLEMCÝ KOMUTLARI
Öniºlemci bu sabit yerine kaynak koddaki o anda bulunan satýr numaralarýný yerleºtirir. Bu özel
durumlar test edilerek çeºitli seçenekler deðerlendirilmektedir. Bu kýsýmda önceden
tanýmlanmýº sembolik sabitlerin standart olanlarýndan bir kýsmýný inceleyeceðiz.
__LINE__
Öniºlemci bu sabit yerine kaynak koddaki o anda bulunulan satýr numarasýný yerleºtirir.
#include dosyalarýnýn içi bu iºleme dahil edilmez. Aºaðýdaki kodu inceleyiniz:
#include <stdio.h>
int main()
{
printf("satýr no . %d\n", __LINE__)
return 0;
}
__FILE__
Öniºlemci bu sabit yerine iki týrnak içerisinde kaynak dosyanýn ismini yazar. Aºaðýdaki örnekte
kaynak dosyanýn ismi ekrana yazdýrýlýyor. string ifadelerinin karakteri gösteren birer adres
olduðunu anýmsayýnýz.
#include <stdio.h>
int main()
{
printf("dosya ismi : %s\n", __FILE__);
return 0;
}
__DATE__ ve __TIME__ : Öniºlemci bu sabitlerin yerine derlemenin yapýldýðý tarih ve zamaný
yazar. __DATE__ "aaa gg yyyy", __TIME __ ise ss:dd:ss biçiminde yazýlmaktadýr.
Taºýnabilirliðe iliºkin sembolik sabitler
__STDC__
C'de kullandýðýmýz kimi anahtar sözcükler tam anlamýyla standart deðildir. Bu anahtar
sözcükler sistemler arasý farklýlýklara karºýlýk verebilmek için kullanýlmaktadýr.
Örneðin 8086 sistemlerinde kullandýðýmýz far ve near standart olarak her sistemde bulunmayan
iki anahtar sözcüktür. Derleyiciniz eger yalnýzca C'nin anahtar sözcüklerini destekliyorsa
__STDC__
sembolik sabiti tanýmlanmýº varsayýlýr.
Ýçerisinde standart olmayan anahtar sözcükler geçen programlar bu sembolik sabit kullanýlarak
daha taºýnabilir bir hale getirilebilir :
#ifdef
#define
#endif
__STDC__
far
Yukarýdaki örnekte eðer yalnýzca standart C'nin anahtar sözcüklerini kullanan bir derleyici ile
çalýºýyorsanýz __STDC__ tanýmlanmýº olacaðýndan far anahtar sözcüðü silinecektir.
__TINY__
__SMALL__
__MEDIUM__
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
367
Buy RoboPDF
36 . BÖLÜM :
__COMPACT__
__LARGE__
__HUGE__
Borland derleyicilerinde aktif olarak kullanýlan bellek modeline göre bu sembolik sabitlerden bir
tanesi tanýmlanmýº sayýlýr. Örneðin o anda LARGE modelde çalýºýlýyorsa yalnýzca __LARGE__
SEMBOLÝK SABÝTÝ TANIMLANMIª SAYILIR.
__MSDOS__
DOS Ýile UNIX arasýndaki taºýnabilirlik problemlerini çözmek için kullanýlýr. Eðer MSDOS
altýndaki bir derleyici ile çalýºýyorsanýz __MSDOS__ sembolik sabiti tanýmlanmýº kabul
edilmektedir.
#ifndef
#define
#endif
__MSDOS__
far
Yukarýdaki örnekte eðer MSDOS ile çalýºýlmýyorsa far anahtar sözcüðü silinmektedir.
__TURBOC__
Borland firmasýnýn turbo C uyarlamalaerýndan bir tanesinde çalýºýyorsanýz bu sembolik sabit
derleyiciniz tarafýndan tanýmlanmýº varsayýlýr. Sembolik sabitin tanýmlanan deðeri (test için
önemli olamaz) uyarlamadan uyarlamaya deðiºebilmektedir.
__BORLANDC__
Borland firmasýnýn BORLAND C uyarlamalaerýndan bir tanesinde çalýºýyorsanýz bu sembolik
sabit derleyiciniz tarafýndan tanýmlanmýº varsayýlýr. Sembolik sabitin tanýmlanan deðeri (test
için önemli olamaz) uyarlamadan uyarlamaya deðiºebilmektedir.
__cplusplus
C++ ismiyle piyasaya çýkan derleyiciler standart C yi de destekler. Bu durumda derleyicilerin
hangi C uyarlamasýnda çalýºtýklarý bu sembolik sabit yardýmýyla öðrenilebilir.
Trial
This PDF was created using the Free RoboPDF Trial (for evaluation purposes only!)
Version
Get RoboPDF: An Easy, Affordable Alternative for Creating PDFs - www.robopdf.com
368
Buy RoboPDF

Benzer belgeler

PROGRAMLAMA VE C

PROGRAMLAMA VE C yazıldığı diller ise 4. kuşak diller olarak isimlendirilirler. Genellikle 4GL olarak kısaltılırlar. (fourth generation language). İnsan algısına en yakın dillerdir. RPG dili 4. kuşak dillerin ilki ...

Detaylı