Standart C Programlama Dili


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ış ta argümanı olmayan bir fonksiyonu parantezleri belirtmeden çağırmaya çalışmaktır. Yani

f();

yerine

f;

şeklinde bir deyim kullanmaktır. İkinci deyim, “f” yerine fonksiyonun adresini koyma dışında bir şey yapmayacaktır.)

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 “(*fg)(...)” yazdığımızda böyle bir fonksiyona çağrı yapmış oluyoruz. Şimdiye kadar incelediğimiz diğer gösterge değişkenlerinin, örneğin 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.14,  0.1,  sin, "sin");
  cizelge(1.0, 100.0,  1.0, sqrt, "k.kok");
  cizelge(1.0, 2.718, 0.05,  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özkonusu 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.