4.5. Fonksiyonlara Göstergeler
C dilinde, tıpkı bir değişkenin adresi gibi, bir fonksiyonun adresini de bir gösterge değişkeninde depolayabilir veya başka bir fonksiyona argüman olarak geçirebiliriz. Bu kısımda, diğer fonksiyonlara fonksiyon göstergelerini nasıl geçirebileceğimiz konusuyla ilgileneceğiz.
Derleyici tarafından, bir tanıtıcı sözcüğün bir fonksiyonu gösterdiği, ya daha önce bir fonksiyon olarak tanımlandığı veya bildirimi yapıldığı için, yada tanıtıcı sözcüğün arkasında sol parantez olduğu için (yani bağlamdan) derleyici tarafından yapılan otomatik bildirim sonucu bilinir. Eğer bu tanıtıcı sözcük daha sonra bir parantezle birlikte kullanılmazsa, derleyici bu fonksiyonu çağırmaya kalkmayacak, onun yerine fonksiyonun adresini kullanacaktır. (C dilinde sık yapılan bir yanlış da argümanı olmayan bir fonksiyonu parantezleri belirtmeden çağırmaya çalışmaktır. Yani
f();
yerine
f;
şeklinde bir deyim kullanmaktır. İkinci deyim,
yerine fonksiyonun adresini koyma
dışında bir şey yapmayacaktır.)f
Bazı değerler ile bu değerler üzerinde uygulanacak herhangi bir fonksiyondan geri döndürülen değerlerin bir çizelgesini çıkaracak bir fonksiyon yazmak istediğimizi düşünün. Bu, örneğin, bir sinüs, karekök veya doğal logaritma çizelgesi olabilir:
#include <stdio.h> #include <float.h> void cizelge (double al, double ul, double art, double (*fg)(double), char *fi) { double x; printf("\n x\t%s(x)\n\n", fi); for (x = al; x <= ul; x += art) printf("%7.2f\t%7.2f\n", x, (*fg)(x)); }
Buradaki
double (*fg)(double);
tanımına dikkat edin. Bunun ne olduğunu
anlamak için işleçlerin uygulanış sırasını göz önünde tutmamız gerekir. Bu
bir double
döndürüp argümanı da
double
olan fonksiyona bir
göstergedir. İleride, bir ifade içinde
yazdığımızda böyle bir fonksiyona çağrı yapmış oluyoruz.
Şimdiye kadar incelediğimiz diğer gösterge değişkenlerinin,
örneğin (*fg)(
…)
int
göstergelerinin, hem tanım hem de
kullanımındaki benzerliğe dikkat edin. fg
fonksiyona bir
göstergedir, (*fg)
ise fonksiyonun kendisidir.
Gösterge ifadesini çevreleyen parantezler gereklidir, çünkü aksi takdirde
double *fg(double);
ifadesi
double *(fg(double));
anlamına gelecekti, bu da double
gösterge döndüren bir fonksiyon demektir ki bu bildirim parametre tanımlarında
kullanılamayacak çok farklı bir şeydir. Bunun nedeni fg
’den
sonra gelen parantezlerin *
’dan
daha yüksek önceliğe sahip bir işleç olmasıdır.
Aşağıdaki program cizelge
fonksiyonuna geçerli çağrılar
yapmaktadır:
#include <math.h> int main (void) { double sin(double), sqrt(double), log(double); cizelge(0.0, 3.15, 0.13089, sin, "sin"); cizelge(1.0, 100.01, 1.0, sqrt, "k.kok"); cizelge(1.0, 2.72, 0.0859, log, "log"); return 0; }
Dördüncü argümanın bir değişken değil de bir
fonksiyon ismi olduğuna dikkat edin. Fonksiyon tarafımızdan tanımlanmış
olabileceği gibi bir kütüphane fonksiyonu da olabilir. Bu noktada bu
fonksiyona bir çağrı söz konusu değildir, çünkü argümanlar verilmemiştir, hatta
parantezler bile yoktur. Derleyici, sin
, sqrt
ve log
’un fonksiyon olduğunu bilir, çünkü yukarıda
bildirimleri yapılmıştır; böylece bu fonksiyonların başlangıç adreslerini
alıp cizelge
fonksiyonuna geçirir. Dizilerde olduğu
gibi burada da adres alma (&
) işlecini kullanmamıza
gerek yoktur. Eğer bir dizi isminin arkasında
varsa, o zaman dizinin belirtilen elemanının değeri kullanılır; aksi
takdirde dizinin temel adresi kullanılır. Aynı şekilde, bir
fonksiyon isminden sonra eğer []
varsa (çağrı
sonucu) fonksiyondan döndürülen değer kullanılır; aksi takdirde ifadenin
değeri olarak fonksiyonun başlangıç adresi kullanılır.()
cizelge
fonksiyonu, ona geçirilen adresi kullanarak asıl
çağrıyı yapar. cizelge
’ye geçirilen bütün fonksiyonların
benzer
olması gerekir, yani aynı sayıda ve tipte argüman kabul
edip aynı tipi döndürmelidirler. Parametrenin tanımlanması esnasında bütün
bunlar belirtilir. main
içinde verilen fonksiyon bildirimleri
gerekli değildir, çünkü #include
edilen standart başlık
dosyası math.h
’de bu bildirimler zaten mevcuttur.