yazan: Şadi Evren ŞEKER

fonksiyon göstericilerinin amacı, programlama dilinde bulunan fonksiyonları gösteren birer referans bilgisi tutmaktır. Bu sayede gösterilmekte olan fonksiyon için hafızada ayrılmış olan yere erişmek ve dolayısıyla örneğin fonksiyonun yerel değişkenlerine ulaşmak mümkündür. Aşağıda C dilinde yazılmış bir fonksiyon göstericisi kullanan kod örneği verilmiştir:

#include 
#include 

void func(int);

main(){
      void (*fp)(int);

      fp = func;

      (*fp)(1);
      fp(2);

}

void
func(int arg){
      printf("%dn", arg);
}

Yukarıdaki kodda “func” isminde bir fonksiyon tanımlanmıştır. Ayrıca void tipinde dönüş değerine sahip ve int tipinde parametre alan bir fonksiyoö göstericisi “fp” tanımlanmıştır. Dikkat edilirse “func” fonksiyonunun ve “fp” göstericisinin hem parametreleri hem de dönüş değerleri aynıdır. Bu durum bir göstericinin foknsiyonu göstermesi (refer etmesi ) için gereklidir. Bu gösterme işlemi atama satırı olan
fp=func;
satırı ile yapılmaktadır. artık bu satırdan sonra “fp” göstericisine verilen her değer “func” fonksiyonuna verilmiş gibi icra edilir. Yani yukarıdaki kod çalışıtırıldığında ekranda önce 1 sonra 2 görülmektedir.

Karıştırılmaması gereken bir nokta:
void (*fp)(int);
void *fp(int);
Yukarıdaki iki satır birbirinden farklıdır. İlk satır bir fonksiyon göstericisini, ikinci satır ise gösterici döndüren bir fonksiyonu tanımlarken kullanılmalıdır. Yani yukarıdaki iki satır aynı değildir.

Fonksiyon göstericileirinin fonksiyonlara parametre olarak verilmesi.
bir fonksiyon parametre olarak bir fonksiyon göstericisini alabilir. Aşağıda bunu yapan temsili kod verilmiştir:

#include 
#include 
int func(int);
void PassPtr(int (*pt2Func)(int))
{
   int sonuc = (*pt2Func)(12);
   printf("%d",sonuc);
}

main(){
      int (*fp)(int);
      fp = func;
      PassPtr(fp);

}
int
func(int arg){
     return ++arg;
}

Yukarıdaki örnek kodda, func ismindeki fonksiyonu gösteren fp isminde bir fonksiyon göstericisi tanımlanmıştır. Bu gösterici PassPtr fonksiyonuna parametre olarak verilmiştir. Bu kod çalıştırıldığında ekranda 13 sayısı görlür çünkü, func fonksiyonunu gösteren fp göstericisi PassPtr fonksiyonunun içinden çağrılmış ve değer olarak 12 parametresi atanmıştır. Fonksiyon incelenirse parametre olarak aldığı sayıyı bir arttırdığı görülür. Bu durumda ekrandaki değer 13 olmaktadır.
Dikkat edilirse yukarıdaki kod ile, bir fonksiyona başka bir fonksiyon verilebilmektedir. Bu sayede genel amaçlı fonksiyonlar yazılarak ve bu fonksiyonlar parametre olarak geçirilerek programlamada avantaj elde edilebilmektedir.

Fonskiyon göstericilerinden dizi oluşturmak:

Fonksiyon göstericileri de birer gösterici olduğu için normal bir göstericiye yapılan herşey bu göstericilere de yapılabilir. Bunlardan birisi de bir dizi tanımlamaktır.
Aşağıdaki örnek kodu inceleyelim:

#include 
#include 
typedef int (*pt2Function)(int);
int
func(int arg){
     return ++arg;
}
int main(){
     pt2Function funcArr1[10] = {NULL};
     int (*funcArr2[10])(int) = {NULL};
    funcArr1[0] = funcArr2[1] = func;
    printf("%dn", funcArr1[1](12));
}

Yukarıdaki örnek kodda, iki adet fonksiyon gösterici dizisi tanımlanmıştır. İlk dizi olan funcArr1 dizisi, typedef marifeti ile tanımlanmıştır ve bu tip tanımı daha önceden yapılmıştır. İkinci dizi olan funcArr2 dizisi ise daha önceden tanımlanmış herhangi bir tip kullanmaksızın tanımlanmıştır. Sonuçta ekranda 13 sayısını gördüğümüz bu yukarıdaki kodda fonksiyon göstericisi, bir dizinin elemanı olarak tutulmakta ve çağrılmaktadır.

Yorumlar

  1. Gurcan Abi

    int main(){
    pt2Function funcArr1[10] = {NULL};
    int (*funcArr2[10])(int) = {NULL};
    funcArr1[0] = funcArr2[1] = func;
    printf(“%dn”, funcArr1[1](12)); //printf(“%dn”, funcArr1[0](12));
    }
    şeklinde olması gerekmiyor mu? yanlış anlamayın niyetim sadece yazım hatasını düzeltmek.

    Fonksiyon göstericiler hep karışık geliyor bana, biraz daha çalışmam gerek. yazı için teşekkürler.

  2. Şadi Evren ŞEKER Article Author

    Sizin yazdığınız kod doğru. Yazıda geçen kod da doğru. Kodda örnek olması için iki tane dizi elemanı fonksiyonu (func) göstermek için atanmış.
    Yazıdaki kodda 0. eleman, sizin kodunuzda ise 1. eleman çağrılmış ve bu iki fonksiyon göstericisi de aslında aynı fonksiyonu gösteriyor.
    Dolayısıyla iki kod da aynı işi yapar.

  3. Engin

    Merhaba Hocam.
    Sitedeki bilgiler için çok teşekkürler öncelikle. Başlıkta Event Listener dedim ancak sorun onunla mı alakalı ben de bilmiyorum; bir problem var ve nasıl çözeceğim hakkında bir fikrim yok. Programı java ile kodluyorum hocam öncelikle. Şimdi bir istatistik programı düşünelim. Mesela kullanıcı size bir metin dosyası verdi ve siz de metin dosyasını okudunuz. Atıyorum 3 tane paragraf var, 256 tane kelime, 46 tane noktalama işareti var. Şimdilik elimizde 7 tane istatistik kuralımız olsun, onlar da atıyorum; 1-kelime sayısı, 2-noktalama işareti sayısı, 3-ortalama cümle uzunluğu(cümlelerdeki harf sayısına göre), 4-ortalama cümle uzunluğu(cümlelerdeki kelime sayısına göre),5…. diye gidiyor hocam. Kullanıcı her metin dosyası için sonucunu görmek istediği istatistik numarasını verecek, yani mesela bir metin için “3,1” girdiyse biz kullanıcıya “1.kelime sayısı- 3.ortalama cümle uzunluğu” nolu istatistik kurallarının sonuçlarını vereceğiz. Benim sormak istediğim nokta ise şu: Bu kullanıcının verdiği, hangi istatistik kurallarını istediğini belirten, numaraları else-if yapısıyla kontrol etmeden nasıl fonksiyonlara gönderebilirim? Yani;
    i == 1 ise number of the sentences fonksiyonuna git,
    i == 2 ise number of the words fonksiyonuna git,
    gibi bir kontrolü else-if ile yapmadan nasıl gerçekleştirebilirim? Problemi şundan soruyorum hocam, eğer bizim istatistik sayımız 100 olsaydı, 100 tane else-if kullanmak zorunda kalacaktım. Umarım anlatabilmişimdir hocam. Eğer yardımcı olabilir ya da ipucu verebilirseniz çok sevinirim.
    Kolay gelsin, iyi günler.
    (Hocam internetten araştırdığım kadarıyla java.util.observable ile hallolabilecekmiş gibi görünüyor ancak emin değilim)

  4. Şadi Evren ŞEKER Article Author

    Kesinlikle doğru. Yani observer pattern (gözlemci örüntüsü) ismi verilen bir yaklaşım ile sorun çözülür. Bu yaklaşım da C dilinde fonksiyon göstericilerine tekabül eder. Öncelikle C dilinde problemin nasıl çözüleceğini Callback kavramını kullanarak anlatan bir yazı ekleyeceğim ardından sizin probleminiz ile daha doğrudan ilgili olan ve nesne yönelimli programlama dillerinde (object oriented programming languages) problemin nasıl çözüldüğünü anlatan bir yazı ekleyip yayınlayacağım. Yazıların bağlantılarını birazdan yayınlayınca buradan paylaşırım.

    sorunuz ve katkınız için tekrar teşekkür ederim.

  5. Engin

    İlginiz için çok teşekkürler hocam. Callback yazınızı yayınlamışsınız bile 🙂 Diğerini de merakla bekliyorum. Tekrar teşekkürler

  6. Şadi Evren ŞEKER Article Author

    Evet iki konuyu da yayınladım, aşağıdaki bağlantılardan erişilebilir:

    http://www.bilgisayarkavramlari.com/2011/11/11/callback-gericagrim/
    http://www.bilgisayarkavramlari.com/2011/11/11/observer-design-pattern-gozlemci-tasarim-kalibi/

    Gelelim sizin sorunuzun cevabına:

    Öncelikle probleminiz, bu yazıda geçen ve yazının sonunda yer alan fonksiyon göstericilerinden bir dizi oluşturmak başlıklı kısımdaki kod ile çözülebilir. Yapmanız gereken fonsiyonları içeren bir dizi oluşturmak ve bu dizinin hangi elemanını isterseniz o elamanı sizin sorunuzda geçtiği şekli ile çağırmak. Örneğin kullanıcı 3 girdiğinde 3. fonksiyonu çağırmak istiyorsanız, funcArr[3]() yazmanız, sizin dizinizdeki 3. fonksiyonu çağıracaktır. Herhangi bir ilave if-else yapısına ihtiyaç duymadan doğrudan kullanıcının hangi fonksiyonu istediğini parametre alabilirsiniz.

    Yukarıdaki yazı C için yazılmış olup benzer yaklaşımı gözlemci tipi tasarım kalıbı ile de uyarlayabilirsiniz (basitçe gözlemci sınıfından bir dizi oluşturarak). Yine de problem yaşarsanız ilgili yazının altına yorum yazın yardımcı olmaya çalışırım.

    başarılar

  7. selam hocam

    ben fonksiyon göstericileri anlamıyorum şuan kendim çalışıyorum ama hiç oturmadı kafamda ne yapmam gerekiyor
    teşekkürler

  8. Şadi Evren ŞEKER Article Author

    Bakın yukarıda anlattım ama bir kere daha sizin yorumunuz üzerine basitçe anlatıyorum. Ancak anlatmadan önce belirteyim. Fonksiyon göstericilerini anlamadan önce mutlaka normal gösterici (pointer) kavramını anlayın. Aksi halde doğrudan fonksiyon göstericisini anlamanız çok zordur.

    Kısaca, fonksiyon göstericisi, bir fonksiyonun, diğer bir fonksiyonu parametre alması için icad edilmiştir.

    Örneğin f(x) = x + 5 fonksiyonunu size versem ve f(3) kaçtır desem 8 dersiniz.

    f(x,y) = x + y + 5 için f(5,3) kaçtır dersem 13 dersiniz ( 5 + 3 + 5 )

    Benzer şekilde f( g(x), y ) = g(y) + 5 yazımında g(x) = x + 2 dersem ve f( g(x),3) dersem yapacağını şudur:

    f( g(x) , y ) = g(y) + 5 olduğuna göre, ve g(x) = x + 2 olduğuna göre , g(y) yerine g(x) yazalım:

    f( g(x) , 3 ) = g(3) + 5

    f( g(x) , 3 ) = 3 + 2 + 5

    dolayısıyla sonuç 10 çıkacaktır.

    Kısacası bir fonksiyon (f) diğer bir fonksiyonu (g) parametre olarak almıştır.

    İşte yukarıdaki bu durumun aynısını C dilinde yaparsanız (ki nasıl yağıldığı yukarıda detaylıca anlatılmıştır) fonksiyon göstericisi kullanmış olursunuz.

    Başarılar

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir