FONKSİYON PROTOTİPLERİ C programlama dilinde, bir fonksiyonun çağırılması durumunda derleyiciler fonksiyonun geri dönüş değerinin türünü bilmek zorundadır. C derleyicileri fonksiyonların geri dönüş değerlerini CPU yazmaçlarından alırlar ve aslında geri dönüş değeri türü, değerin hangi yazmaçtan alınacağını gösterir. Eğer çağırılan fonksiyonun tanımlaması, fonksiyon çağırma ifadesinden daha önce yer alıyorsa, derleyici derleme işlemi sırasında fonksiyon çağırma ifadesine gelmeden önce, çağrılan fonksiyonun geri dönüş değeri türü hakkında zaten bilgi sahibi olacaktır. Çünkü derleme işlemi yukarıdan aşağı doğru yapılmaktadır. Yukarıdaki örnekte hesapla fonksiyonu kendisini çağıran main fonksiyonundan daha önce tanımlanmıştır. Dolayısıyla çağırma ifadesine gelmeden önce derleyici, hesapla fonksiyonunun geri dönüş değeri türünü zaten bilecektir. Eğer çağrılan fonksiyonun tanımlaması çağıran fonksiyondan daha sonra yapılmışsa, derleyici fonksiyon çağırma ifadesine geldiğinde, söz konusu fonksiyonun geri dönüş değerinin türünü belirleyemez. Bu problemli bir durumdur. Yukarıda hesapla fonksiyonu main içinde çağırılmıştır. Fakat hesapla fonksiyonunun tanımlaması kaynak kod içinde main’den daha sonra yer almaktadır. Derleme akışı içerisinde hesapla fonksiyonuna ilişkin çağırma ifadesine gelindiğinde, derleyici bu fonksiyonun geri dönüş değerini bilmemektedir. Çağırılan fonksiyonu çağıran fonksiyonun üstünde tanımlamak her zaman mümkün değildir. Büyük bir programda yüzlerce fonksiyon tanımlanabilir ve tanımlanan her fonksiyonun birbirini çağırması söz konusu olabilir. Bu durumda çağırılacak fonksiyonu çağıran fonksiyonun üzerinde tanımlanması çok zor olacaktır. Kaldı ki, C dilinde iki fonksiyon birbirini de çağırabilir. Bu tür bir fonksiyon tasarımında artık çağırılan fonksiyonun daha önce tanımlanması mümkün olamayacaktır: double func1(void) { ... func2(); ... } double func2(void) { ... func1(); ... } Ayrıca standart C fonksiyonları da ancak bağlama aşamasına gelindiğinde bağlayıcı (linker) tarafından kütüphanelerden alınarak çalışabilen kod (.exe) içine yerleştirilirler. İşte bu gibi durumlarda derleyiciye çağırılan fonksiyonun geri dönüş tür bilgisi fonksiyon prototipleriyle verilir. Çağırılana kadar tanımlaması yapılmamış fonksiyonlar hakkında derleyicilerin bilgilendirilmesi işlemi fonksiyon prototip bildirimleri ile yapılır. Fonksiyon Prototip Bildirimlerinin Genel Biçimi [geri dönüş değeri türü] <fonksiyon ismi> ([tür1], [tür2]...); Örneğin hesapla fonksiyonu için prototip aşağıdaki biçimde yazılabilir: float hesapla(float, float); Derleyici böyle bir prototip bildiriminden hesapla fonksiyonunun geri dönüş değerinin türünün float olduğunu anlayacaktır. Birkaç örnek daha verilirse: int multiply (int, int); double pow (double, double); void clrscr (void); Tıpkı fonksiyon tanımlamalarında olduğu gibi, fonksiyon prototip bildirimlerinde de, fonksiyonun geri dönüş değeri belirtilmemişse, derleyici bildirimin int türden bir geri dönüş değeri için yapıldığını anlayacaktır. Func (double); Eğer tanımlanacak fonksiyon geri dönüş değeri üretmeyecekse, void anahtar sözcüğü kullanılmalıdır: void func (double); Fonksiyon protipleri yalnızca derleyiciyi bildirme amacıyla kullanılır bir bildirimdir (declaration) bir tanımlama (definition) işlemi değildir, dolayısıyla yapılan bildirim sonucunda bellekte bir yer ayrılmaz. Fonksiyon prototip bildirimlerinde parametre değişkenlerinin türlerinden sonra parametre isimleri de yazılabilir. Buradaki değişken isimlerinin fonksiyonun gerçek tanımlamasında kullanılacak formal parametre değişkenlerinin isimleriyle aynı olması zorunluluğu yoktur. Yukarıdaki prototiplerini parametre isimleriyle tekrar yazılırsa; float calculate(float a, float b); int multiply(int number1, int number2); double pow(double base, double exp); Aynı türden geri dönüş değerine sahip fonksiyonların bildirimi virgüllerle ayrılarak yazılabilir, ama bu genel olarak pek tercih edilen bir durum değildir : double func1(int), func2(int, int), func3(float); Fonksiyon prototip bildirimleri değişken tanımlamalarıyla da birleştirilebilir. Bu da tercih edilen bir durum değildir. long func1(int), long func2(void), x, y; Fonksiyon Prototiplerinin Bildirim Yerleri Fonksiyon prototiplerinin bildirimi programın herhangi bir yerinde yapılabilir. Prototip bildirimleri tüm blokların dışında yapılmışsa, bildirildikleri yerden dosya sonuna kadar olan alan içinde geçerliliklerini sürdürürler. Önemli olan nokta söz konusu fonksiyon çağırılmadan önce bildiriminin yapılmış olmasıdır. Standart C Fonksiyonlarının Prototipleri Standart C fonksiyonlarının prototipleri standart başlık dosyaları içine yerleştirilmiştir. Programcı, uygulamalarda standart bir C fonksiyonunun prototipini kendi yazmaz, bu prototip bildiriminin bulunduğu başlık dosyasını #include önişlemci komutuyla koda dahil eder. Standart C fonksiyonlarının prototipleri sonu .h uzantılı olan (header) başlık dosyalar içindedir. Önişlemci komutuyla ilgili başlık dosyasının kaynak koda ilave edilmesiyle, aslında standart C fonksiyonunun da prototip bildirimi yapılmış olmaktadır. Fonksiyon prototiplerinin ana amacı yukarıda da belirtildiği gibi, derleyiciye fonksiyonun geri dönüş değeri türü hakkında bilgi vermektir. Ancak fonksiyon prototip bildirimlerinde fonksiyon parametrelerinin türleri belirtilmişse, derleyici prototip bildirimindeki parametre değişkeni sayısını fonksiyon çağırma ifadesindeki fonksiyona gönderilen arguman sayısı ile karşılaştırır. Örneğin: float calculate(float, float); biçiminde bir prototip yazıldığında eğer calculate fonskiyonu eksik ya da fazla parametre ile çağırılırsa derleme hatası oluşacaktır. x = calculate(5.8); /* hata eksik parametre ile çağırılmış */ y = calculate(4.6, 7.9, 8.0) /* hata fazla parametre ile çağırılmış */ Eğer fonksiyonun gerçekten parametre değişkeni yoksa, ve derleyicinin fonksiyonun çağırılması durumunda argüman parametre değişkeni kontrolu yapması isteniyorsa, prototip bildiriminde fonksiyon parantezi içerisine void anahtar sözcüğü yazılmalıdır. float ornek(void); Burada ornek fonksiyonunun parametre almadığı bildirilmiştir. Eğer fonksiyon x = ornek(20); /* derleme hatası */ ifadesiyle çağırılırsa derleme hatası oluşur. Fonksiyon prototip bildiriminin yapılmış olması o fonksiyonun tanımlamasını ya da çağırılmasını zorunlu kılmaz. Bir fonksiyonun prototip bildirimi birden fazla yapılabilir. Bu durumda hata oluşturmaz. Ama yapılan bildirimler birbirleriyle çelişmemelidir. Kaynak dosya içinde aynı fonksiyona ilişkin prototip bildirimlerinin farklı yerlerde ve aşağıdaki biçimlerde yapıldığını düşünelim: int sample (int, int); sample (int, int); int sample(int x, int y); sample(int number1, int number2); Yukarıdaki bildirimlerinin hiçbirinde bir çelişki söz konusu değildir. Fonksiyon parametre değişkenlerinin isimleri için daha sonraki bildirimlerde farklı isimler kullanılması bir çelişki yaratmayacaktır. Çünkü bu isimlerin faaliyet alanı (name scope) yalnızca bildirimin yapıldığı parantezin içidir. Ancak aşağıdaki farklı bildirimler derleme zamanında error oluşturacaktır: double func(int x, double y); double func(int x, float y); çelişki var */ long sample(double x); sample (double x); /* error! bildirimler arasında /* error! bildirimler çelişki var. */ arasında DÖNGÜ DEYİMLERİ Bir program parçasının yinelemeli olarak çalıştırılmasını sağlayan kontrol deyimlerine döngü denir. C dilinde 3 ayrı döngü deyimi vardır: Kontrolün başta yapıldığı while döngüleri Kontrolün sonda yapıldığı while döngüleri (do while döngüleri) for döngüleri Kontrolun Başta Yapıldığı while Döngüleri Genel biçimi: while (ifade) deyim; while anahtar sözcüğünü izleyen parantez içerisindeki ifadeye kontrol ifadesi (control statement) denir. while parantezini izleyen ilk deyime döngü gövdesi denir. Döngü gövdesi basit bir deyim olabileceği gibi, bloklanmış birden fazla deyimden de (bileşik deyim) oluşabilir. while deyiminin icrası şu şekilde olur: Kontrol ifadesinin sayısal değeri hesaplanır. Kontrol ifadesinin sayısal değeri 0 dışı bir değerse, mantıksal olarak doğru kabul edilir ve döngü gövdesindeki deyim ya da deyimler çalıştırılır. Kontrol ifadesinin sayısal değeri 0 ise mantıksal olarak yanlış kabul edilir programın akışı döngünün dışındaki ilk deyimle devam eder. C dilinde yalın bir deyimin olduğu yere bileşik bir deyim de yerleştirilebilir. Bu durumda while döngüsü aşağıdaki gibi de oluşturulabilir: while (ifade) { ifade1; ifade2; ifade3; ...... } Bu durumda kontrol ifadesinin sayısal değeri 0 dışı bir değer olduğu (doğru) sürece blok parantezleri arasında kalan tüm deyimler icra edilecektir. Örnek: while parantezinin içindeki ifade yani koşul ifadesi, ifade tanımına uygun herhangi bir ifade olabilir. while (1) { .... } Yukarıdaki while deyiminde kontrol ifadesi olarak bir sabit olan 1 sayısı kullanılmıştır. 1 değeri 0 dışı bir değer olduğundan ve kontrol ifadesi bir değişkene bağlı olarak değişemeyeceğinden, böyle bir döngüden çıkmak mümkün olmayacaktır. Bu tür döngülere sonsuz döngüler (infinite loops) denir. Sonsuz döngüler bir yanlışlık sonucu oluşturulabildiği gibi, bilinçli olarak da oluşturulabilir. Sonsuz döngülerden bazı yöntemlerle çıkılabilir. break Anahtar Sözcüğü break anahtar sözcüğü ile bir döngü sonlandırılabilir. Kullanımı break; şeklindedir. Programın akışı break anahtar sözcüğünü gördüğünde, döngü kırılarak döngünün akışı döngü gövdesi dışındaki ilk deyim ile devam eder. Yani koşulsuz olarak döngüden çıkılır. Yukarıdaki programda bir sonsuz döngü oluşturulmuştur. Döngü içerisinde, döngünün her bir iterasyonunda ch değişkenine klavyeden bir değer alınmaktadır. Eğer klavyeden alınan karakter 'q' ise break anahtar sözcüğüyle programın akışı while döngü gövdesi dışındaki ilk deyimle devam edecektir. İç içe Döngüler Bir döngünün gövdesini başka bir kontrol deyimi oluşturabilir. Döngü gövdesini oluşturan kontrol deyimi bir if deyimi olabileceği gibi başka bir döngü deyimi de olabilir. (while, do while, for deyimleri) İç içe döngülerde içerideki döngüde break deyimi kullanıldığında yalnızca içerideki döngüden çıkılır. Burada ikinci while döngüsü tek bir kontrol deyimi olarak ele alınacağı için, bloklamaya gerek yoktur. while döngüsünün yanlışlıkla boş deyim ile kapatılması çok sık yapılan bir hatadır. Döngü while parantezi içerisindeki ifadenin değeri 0 olana kadar devam eder ve boş deyim döngü gövdesi olarak icra edilir. Döngüden çıkıldığında ekrana 0 basılır. Aynı program boş while döngüsü kullanmadan hatasız yazılırsa; while Döngüsü İçerisinde Postfix ++ ya da -- Operatörünün Kullanılması Bir postfix artırım ya da eksiltme işlemi yapıldığında önce döngüye devam edilip edilmeyeceği kararı verilir, sonra artırım ya da eksiltim uygulanır. Örnek : Başka bir örnek: Kontrolün Sonda Yapıldığı while Döngüleri Genel biçim; 1. do ifade 1; while (ifade 2); 2. do { ifade 1; ifade 2; } while (ifade); do while döngüsünde kontrol ifadesi sondadır. while parantezinden sonra sonlandırıcı ";" bulunmalıdır. Döngü gövdesindeki deyim(ler) en az bir kere icra edilecektir. Örnek: örnek: Uygulama 1'den 100'e kadar sayıları her satırda beş tane olacak biçimde ekrana yazan bir C programının yazılması: Başka bir çözüm: Uygulama Bir tamsayının basamak sayısını bulan program. Aynı programı while döngüsü kullanarak yazılırsa; for Döngüleri for döngüleri yalnızca C dilinin değil, belki de tüm programlama dillerinin en güçlü döngü yapılarıdır. for döngülerinin genel biçimi şu şekildedir: for (ifade1; ifade2; ifade3) deyim1; for (ifade1; ifade2; ifade3) deyim1; deyim2; ... } { Derleyici for anahtar sözcüğünden sonra bir parantez açılmasını ve parantez içerisinde iki noktalı virgül bulunmasını bekler. Bu iki noktalı virgül for parantezini üç bölüme ayırır. Bu bölümler yukarıda ifade1 ifade2 ve ifade 3 olarak gösterilmiştir. for parantezinin kapanmasından sonra gelen ilk deyim döngü gövdesini (loop body) oluşturur. Döngü gövdesi basit bir deyimden oluşabileceği gibi, bileşik deyimden de oluşabilir. for parantezi içerisindeki her üç kısımın da ayrı ayrı işlevleri vardır. for parantezinin 2. kısımını oluşturan ifadeye kontrol ifadesi denir. (control expression). Tıpkı while parantezi içindeki ifade gibi, döngünün devamı konusunda bu ifade söz sahibidir. Bu ifadenin değeri mantıksal olarak doğru ise, döngü devam eder. Döngü gövdesindeki deyim(ler) icra edilir. Kontrol ifadesinin değeri mantıksal olarak yanlış ise programın akışı for döngüsünün dışındaki ilk deyimle devam eder. Programın akışı for deyimine gelince, for parantezinin 1. kısmı 1 kez icra edilir ve genellikle döngü değişkenine ilk değer verme amacıyla kullanılır. for döngüsünün 3. kısım döngü gövdesindeki deyim ya da deyimler icra edildikten sonra, dönüşte çalıştırılır. Ve çoğunlukla döngü değişkeninin artırılması ya da azaltılması amacıyla kullanılır. for (ilk değer; koşul; işlem) { ... ... ... } Yukarıdaki programı incelendiğinde: Programın akışı for deyimine gelince, önce for parantezi içindeki 1. ifade icra ediliyor. Yani i değişkenine 0 değeri atanıyor. Şimdi programın akışı for parantezinin 2. kısmına yani kontrol ifadesine geliyor ve i < 2 koşulu sorgulanıyor. Kontrol ifadesinin değeri 0 dışı bir değer olduğu için, ifade mantıksal olarak doğru kabul ediliyor ve programın akışı döngü gövdesine geçiyor. Döngü gövdesi bloklanmadığı için, döngü gövdesinde tek bir deyim var. Bu deyim icra ediliyor. Yani ekrana i değişkeninin değeri yazılarak imleç alt satıra geçiriliyor. Programın akışı bu kez for parantezinin 3. kısımına geliyor ve buradaki ifade bir deyimmiş gibi icra edeiliyor, yani i değişkeninin değeri 1 artırılıyor. i değişkeninin değeri 1 oluyor. ifade yeniden değerlendiriliyor ve i < 2 ifadesi doğru olduğu için bir kez daha döngü gövdesi içra ediliyor. Programın akışı yine for parantezinin 3. kısımına geliyor ve buradaki ifade bir deyimmiş gibi icra edeiliyor, yani i değişkeninin değeri 1 artırılıyor. i değişkeninin değeri 2 oluyor. Programın akışı yine for parantezinin 2. kısmına geliyor ve buradaki kontrol ifadesi tekrar sorgulanıyor. i < 2 ifadesi bu kez yanlış olduğu için programın akışı döngü gövdesine girmiyor ve programın akışı döngü gövdesi dışındaki ilk deyimle devam ediyor. Yani ekrana: son değer = 2 yazılıyor. Döngü değişkeninin tamsayı türlerinden birinden olması gibi bir zorunluluk yoktur. Döngü değişkeni gerçek sayı türlerinden de olabilir. for döngüsünün 1. kısmı hiç olmayabilir. Örneğin döngü dışında, programın akışı for deyiminin icrasına gelmeden önce, döngü değişkenine ilk değer verilmiş olabilir. for döngüsünün 3. kısmı da olmayabilir. Döngü değişkeninin artırılması ya da eksiltilmesi for parantezi içi yerine döngü gövdesi içerisinde gerçekleştirilebilir. 1. ve 3. kısmı olmayan (yalnızca 2. kısma sahip) bir for döngüsü örneği: ... 1.ve 3. kısmı olmayan for döngüleri tamamen while döngüleriyle eşdeğerdir. C’de for döngüleriyle while döngüleriyle yapabildiğimiz her şeyi yapabiliriz. for (;;) ile while (1) eşdeğerdir. İkisi de sonsuz döngü belirtir. Sonsuz döngü oluşturmak için for (;;) biçimi while (1)'e göre daha çok tercih edilir. Sonsuz Döngülerden Çıkış 1. break anahtar sözcüğü ile. Bu durumda programın akışı döngü gövdesi dışındaki ilk deyime yönlenecektir. (eğer iç içe döngü varsa break anahtar sözcüğü ile yalnızca içteki döngüden çıkılacaktır.) 2. return anahtar sözcüğü ile bu durumda fonksiyonun (main de olabilir) icrası sona erecektir. 3. goto anahtar sözcüğüyle. İçiçe birden fazla döngü varsa en içteki döngü içinden en dıştaki döngünün dışına kadar çıkabiliriz. (goto anahtar sözcüğünün çok az sayıdaki faydalı kullanımından biri budur.) 4. exit fonksiyonu ile. continue Anahtar Sözcüğü continue anahtar sözcüğü de tıpkı break anahtar sözcüğü gibi bir döngü içerisinde kullanılabilir. Programın akışı continue anahtar sözcüğüne geldiğinde sanki döngü yinelemesi bitmiş gibi yeni bir yinelemeye geçilir. Eğer for döngüsü içerisinde kullanılıyorsa yeni bir yinelemeye geçmeden önce döngünün 3. kısmı yapılır. Örnek: break anahtar sözcüğü bir döngüyü sonlandırmak için, continue anahtar sözcüğü de bir döngünün o anda içinde bulunulan yinelemesini sonlandırmak için kullanılır. n kere dönen for deyimi kalıpları for (i = 0; i < n; ++i) for (i = 1; i <= n; ++i) for (i = n - 1; i >= 0; --i) for (i = n; i > 0; --i) Bir döngüden çıkmak için döngü değişkeni ile oynamak kötü bir tekniktir. Bu programları okunabilirlikten uzaklaştırır. Bunun yerine break anahtar sözcüğü ile döngülerden çıkılmalıdır. Uygulama Basamaklarının küpleri toplamı kendisine eşit olan 3 basamaklı sayıları bulan program. Başka bir çözüm: