PDA

Tüm Versiyonu Göster : Programlama dilleri-C dili


CuTai
21-03-08, 00:41
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.

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.

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 (CII-Honeywell 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 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.

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)
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 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 gelmişken, Nesne Yönelimli Programlama Tekniği 1980'li yıllarda popüler olmuştur.

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.


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



Java
Modula-2 Ada Delphi



Oberon


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.

CuTai
21-03-08, 00:42
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 210 byte)
1 mega byte 1 MB = 1024 Kilo byte dır. (yani 220 byte)
1 gigabyte 1 GB = 1024 MB dır. (yani 230 byte)
1 terabyte 1 TB = 1024 GB dır. (yani 240 byte)
1 petabyte 1PB = 1024 TB dır. (yani 250 byte)
1 exabyte 1EB = 1024 PB dır. (yani 260 byte)
1 zettabyte 1ZB = 1024 EB dir.( yani 270 byte)
1 yottabyte 1YB = 1024 ZB dır.( yani 280 byte)

Kilo büyüklük olarak 1000 kat anlamına gelmektedir, ancak bilgisayar alanında Kilo 2'nin 1000'e en yakın kuvveti olan 210 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 :

1 0 1 1 = 1 * 20 + 1 * 21 + 0 * 22 + 1 * 23 = 11
0010 1001 = (1 * 1) + (1 * + (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
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:
87'den çıkarılabilecek, yani 87'den büyük olmayan ikinin en büyük kuvveti nedir? Cevap 64. O zaman 64 = 26 olduğuna göre 6.bit 1 değerini alacak.
87 - 64 = 23. Şimdi 23'den çıkarılabilecek ikinin en büyük kuvvetini bulalım. Bu say1 16'dır. Yani 24 'dür. O zaman sayımızın 4. biti de 1 olacak.
23 - 16 = 7. 7'den çıkarılabilecek ikinin en büyük kuvveti 4'dür ve 4 = 22 'dir. Sayımızınj 2. biti de 1 olacak.
7 - 4 = 3.
3 - 2 = 1 (2 = 21 ) Sayımızın 1. biti 1 olacak.
1 - 1 = 0 (1 = 20 ) 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?

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. 0001 0001
bu sayının 2'ye tümleyeni alınırsa 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.

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 = 10
B = 11
C = 12
D = 13
E = 14
F = 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 1
0010 2
0011 3
0100 4
0101 5
0110 6
0111 7
1000 8
1001 9
1010 A
1011 B
1100 C
1101 D
1110 E
1111 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 = 0010
A = 1010
D = 1101
F = 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 = AEB1H
0010 1101 0011 1110 = 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 1
010 2
011 3
100 4
101 5
110 6
111 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)
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 EEEEEEEE FFFFFFFFFFFFFFFFFFFFFFF
31 30-----------23 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 = Sayı değil
1 11111111 00010101010001001010101 = 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

V = (-1)S * 2(E -127) * (1.F)

Önce sayının fraction kısmının başına 1. eklenir. Daha sonra bu sayı 2(E-127) ile çarpılarak noktanın yeri ayarlanır. Noktadan sonraki kısım 2'nin artan negatif kuvvetleriyle çarpılarak elde edilecektir. Örnekler :

0 10000000 00000000000000000000000 = +1 * 2 (128 - 127) * 1.0
= 2 * 1.0
= 10.00
= 2



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


1 10000001 10100000000000000000000 = -1 * 2 (129 - 127) * 1.101
= -22 * 1.101
= 110.100000
= -6.5

0 00000001 00000000000000000000000 = +1 * 2 (1 - 127) * 1.0
= 2-126

E = 0 ve F sıfır dışı bir değer ise

V = (-1)S * 2(-126) * (0.F)

Örnekler :

0 00000000 10000000000000000000000 = +1 * 2-126 * 0.1
=

0 00000000 00000000000000000000001 = +1 * 2-126 0. 00000000000000000000001
= 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

V = (-1)S * 2(E -1023) * (1.F)

Önce sayının fraction kısmının başına 1. eklenir. Daha sonra bu sayı 2(E-1023) ile çarpılarak noktanın yeri ayarlanır. Noktadan sonraki kısım 2'nin artan negatif kuvvetleriyle çarpılarak elde edilecektir.

E = 0 ve F sıfır dışı bir değer ise

V = (-1)S * 2(-126) * (0.F)

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

E = 0 ve F = 0 ve S = 0 ise V = 0

CuTai
21-03-08, 00:43
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 goto if int long register return short signed sizeof static struct switch typedef union unsigned void volatile while

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.
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 ( ) { int number , k , total = 0 ;
printf ( "lütfen bir sayı giriniz\n" ) ; scanf ( "%d" , & number ) ;
for ( k = 1 ; k <= ; ++ k ) total += k ;
printf ( "toplam = %d\n" , toplam ) ; }

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

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

CuTai
21-03-08, 00:43
C DİLİNİN ÖNCEDEN TANIMLANMIŞ
(DEFAULT ) VERİ TÜRLERİ

TAMSAYI TÜRLERİ
(INTEGER TYPES)

TÜR İSMİ UZUNLUK(byte)
(DOS / UNIX) SINIR DEĞERLERİ
signed char 1 -128 127
unsigned char 1 0 255
signed short int 2 -32.768 32.767
unsigned short int 2 0 65.535
signed int 2 4 -32.768
-2.147.483.648 32.767
2.147.483.647
unsigned int 2 4 0
0 65.535
4.294.967.296
long int 4 -2.147.483.648 2.147.483.647
unsigned long int 4 0 4.294.967.296


GERÇEK SAYI TÜRLERİ
(FLOATING TYPES)

TÜR İSMİ UZUNLUK
(byte) SINIR DEĞERLERİ
en küçük pozitif değer en büyük pozitif değer
float 4 1.17 x 10-38
(6 basamak hassasiyet) 3.40 x 1038
double 8 2.22 x 10-308
(15 basamak hassasiyet) 1.17 x 10-38
(15 basamak hassasiyet)
long double 10 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

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.

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 char [signed ] char
2 unsigned char
3 short [signed] short short [int] [signed] short [int]
4 unsigned short
5 int [signed] int signed
6 unsigned int unsigned
7 long [signed] long long [int] [signed] long [int]
8 unsigned long unsigned long [int]
9 float
10 double
11 long double

Yukarıdaki tablodan da görüldüğü gibi, belirli türleri birden fazla şekilde ifade etmek mümkündür.
char a; int a; long a;
signed char a; signed int a; long int a;
signed 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 :

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 x;
signed int long x;
long signed int x;
long int signed x;
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

CuTai
21-03-08, 00:44
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. */
}

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


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 uzunluk sınır değerler
DOS, WINDOWS 3.1 2 byte - 32768, + 32767
UNIX WINDOWS 95 4 byte -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.

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

Tanım ASCII No
'\0' '\x0' '\0' NULL karakter 0
'\a' '\x7' '\07' çan sesi (alert) 7
'\b' '\x8' '\010' geri boşluk (back space) 8
'\t' '\x9' '\011' tab karakteri (tab) 9
'\n' '\xA' '\012' aşağı satır (new line) 10
'\v' '\xB' '\013' düşey tab (vertical tab) 11
'\f' '\xC' '\014' sayfa ileri (form feed) 12
'\r' '\xD' '\015' satır başı (carriage return) 13
'\"' '\x22' '\042' çift tırnak (double quote) 34
'\\' '\x5C' '\134' ters bölü (back slash) 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' /* 41H numaralı ASCII karakteridir. */
'\xff' /* FFH numaralı '2' karakter sabitidir. */
'\x1C' /* 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' /* 10 numaralı ASCII karakteri, Tam sayı değeri 10 */
'\16' /* 14 numaralı ASCII karakteri. Tam sayı değeri 14 */
'\123' /* 83 numaralı ASCII karakteri. Tam sayı değeri 83 */

Program içinde kullanımına bir örnek:

{
char a, b;

a = '\xbc' ; /* hex sistemde tanımlanmış char sabit */
b = '\012'; /* oktal sistemde tanımlanmış bir char sabit */
}

7 numaralı ASCII karakteri olan çan karakterini sabit olarak 3 biçimde de yazabiliriz.

'\x7' /* hex gösterimli karakter sabiti */
'\07' /* oktal gösterimli karakter sabiti */
'\a' /* ö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 (signed) int sabit
15000U (unsigned) int sabit.
1200L (signed) long sabit
1200Lu (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.

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 sayısı hex gösterimli bir tamsayı (int) sabit.
0X12L sayısı hex gösterimli bir uzun tamsayı (long) sabit.
0x1C205470 hex gösterimli bir uzun tamsayı (long) sabit. Çünkü (DOS'da) tamsayı sayı sınırını aşmaktadır.
0x1934ul hex gösterimli işaretsiz uzun tamsayı (unsigned long) sabittir.
01234 oktal gösterimli tamsayı (int) sabit
0567L oktal gösterimli uzun tamsayı (long) sabit
0777U oktal gösterimli işaretsiz tamsayı (unsigned int) sabit
0452Lu 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.

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.

CuTai
21-03-08, 00:53
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 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
...
}



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 :

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 ifadesiyle üretilen geri dönüş değeri sonuc değişkenine atanmaktadır. Bir başka deyişle bir fonksiyon çağırma ifadesinin ürettiği değer, ilgili fonksiyonun ürettiği (eğer üretiyorsa) geri dönüş değeridir. Yukarıdaki örnekte önce hesapla() fonksiyonu çağırılacak daha sonra fonksiyonun icra edilmesiyle oluşan geri dönüş değeri sonuc değişkenine atanacaktır.

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

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 sözcüğü yanında bir ifade olmaksızın tek başına da kullanılabilir :

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

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

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 enter tuşuna ihtiyaç duyar alınan karakter ekranda görünür.
getch enter tuşuna ihtiyaç duymaz alınan karakter ekranda görünmez
getche enter tuşuna ihtiyaç duymaz alınan karakter ekranda görünür.

Ekrana Bir Karakterin Görüntüsünü Yazan C Fonksiyonları
C dilinde ekrana karakter yazamakta iki fonksiyonun kullanıldığı görülür :

CuTai
21-03-08, 00:53
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 makro olarak tanımlanmıştır. Makrolar konusunu ileriki derslerde detaylı olarak öğreneceğiz.

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;

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 int türünü desimal sistemde yazar.
%ld long türünü desimal sistemde yazar
%x unsigned int türünü hexadecimal sistemde yazar.
%X unsigned int türünü hexadecimal sistemde yazar.(semboller büyük harfle)
%lx unsigned long türünü hexadecimal sistemde yazar.
%u unsigned int türünü decimal sistemde yazar.
%o unsigned int türünü okt