1 - WordPress.com

advertisement
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:
Download