Fonksiyon Göstericileri ve Uygulamaları(c de)

murat335

New member
C dilinde yazdığımız br fonksiyonu çağırdığımızda şimdilik neler olup bittiğini tam olarak bilmesek de bildiğimiz bir şey var ki; o da fonksiyonlara ait kodların da bellekte tutulmasıdır. Fonksiyonlarda normal veri tipleri gibi bellekte bulunurlar ve bellekte bulunduğu bölgenin başlangıç adresi mevcuttur. Bu makalemizde fonksiyon göstericilerini tanımlama, fonksyion göstericilerinin uygulama alanlarını ve basit bir "Komut Yorumlayıcı" programıyla fonksyion göstericilerinin kullanımını göreceğiz.

Aşağıdaki kod parçasında olan bitene bir göz atalım
PHP:
int islev()
{
int x;
x= 2 ;
return x;
}
int main(void)
{
int y ;
y=islev(); 
return 0;
}
Programımızın akışı main işlevi içinde y= islev(); satırına geldiğindemain işlevinin akışı durdurulur ve "islev" fonksiyonunun bulunduğu adrese gidilir, ve o adresten işlemler yapılmaya devam edilir.İşlev fonksiyonu icra edildikten sonra main işlevi kaldığı yerden devam ediyor. Evet gördüğünüz gibi her şey bildiğimiz gibi normal bir şekilde işledi. Peki bu mekanizma nasıl işledi? Main işlevi içinden islev() fonksiyonuna nasıl atladık?Bütün bunların cevabı fonksiyon göstericileridir, şöyle ki, aslında biz farkına varmasak da y=islev(); dediğimizde "islev" adresindeki kodu icra etmek istediğimizi bildiriyoruz. Kısacası bir fonksiyonun ismi o fonksiyonun kodlarının bulunduğu bellek bölgesinin başlangıç adresidir."islev" bir adres "()" ise fonksiyon çağırma operatörüdür.Fonksiyon çağırma operatörü fonksiyonun geri dönüş değerini üretir.

islev=> geri dönüş değeri int türünden olan bir fonksiyonun adresini tutan sabit bir bilgidir.

Fonksiyon göstericileri de bir nesne olduğuna göre tanımlanmaları ve onlara değer atamak son derece legal bir durumdur. Mesela bir fonksiyonun başlangıç adresi, bir fonksiyon göstericisine atanabilir.
Bir fonksiyon gösterici aşağıdaki gibi tanımlanır:

<geri dönüş değeri türü> (* gösterici ismi)([parametreler])

Aşağıda tanımlamaları verilmiş fonksiyon göstericilerini dikkatlice izleyin.
PHP:
int (*p)(void);
void (*t)(int t,int m);
void (*k)(void);
Bir fonksiyon göstericisine her tür fonksiyon göstericisi atayamayız. Değerini atadığımız fonksiyon göstericisinin adresini tuttuğu fonksiyonun parametrik yapısı ve geri dönüş değeri, atama yapılacak göstericinin türüne uygun olmalıdır. Mesela yukarıda tanımlanan p fonksiyon göstericisine ancak ve ancak geri dönüş değeri int ve parametresi olmayan bir fonksiyonun adresi atanabilir.Aşağıdaki atamaların tamamı yanlış ve geçersiz atamalardır.

p=t; t=k; k=p; // yanlış

Fonksiyon gösterici tanımlarken kullandığımız ilk parantezler mutlaka kullanılmalıdır.Aksi halde tanımlamamız anlam değiştirip fonksiyon prototip tanımlamasına dönecektir. Aşağıda bu iki duruma örnek verilmiştir.

void (*pFunc)(int,int) // pFunc, geri dönüş değeri void ve parametrik yapısı int,int olan bir fonksiyon gösterici türüdür.

void *pFunc(int,int) // pFunc, geri dönüş değeri void türden bir gösterici olan ve parametrik yapısı int,int olan bir fonksiyon adıdır.Ve aynı zamanda bir adres sabitidir.

C dilinde fonksiyon isimleri tıpkı dizi isimlerinde olduğu gibi fonksiyonların bellekteki adres bilgilerini tutar ve bir sabit olarak ele alınırlar. Fonksiyon isimleri nesne olmadıkları için onlara herhangi bir fonksiyon göstericisinin değeri atanamaz.Aşağıdaki örnekte basit bir fonksiyon göstericisi kullanımı göreceksiniz.
PHP:
void func(int a,int b)
{
printf("Ben adım func\n");
} 

int main(void)
{
void (*pFunc)(int,int); // func’ın adresini atamak için bir gösterici tanımlıyoruz.
pFunc=func(); // uygun bir gösterici ataması yaptık.
return 0;
} 

Fonksiyon göstericisi ile fonksiyon çağırma, () operatörü ile yapılır. Bu durumda () operatörünün operandı fonksiyon adresi olabileceği gibi bir fonksiyon göstericisi de olabilmektedir.Operand fonksiyon göstericisi olması durumunda programın akışı gösterici içindeki adrese gidecektir. Fonksiyon göstericiler de diğer türler gibi fonksiyonlara paremetre olarak geçirilebilirler.Mesela aşağıdaki "func" fonksiyonu parametresi bir fonksiyon gösterici olan fonksiyondur.

void normalfunc(void)
{
printf("Normal Fonksiyon");
} 

void func(void (*p)(void))
{
p();
} 

int main(void)
{
func(normalfunc);
return 0;
}
Yukarıdaki kodda main işlevi içinde "func" fonksiyonuna "normalfunc" fonksiyonunun adresi geçiliyor ve "func" da kendisine gelen adresteki koda akışı sağlıyor.Bu kodda fonksiyonların çağrılma sırası aşağıdaki gibi olacaktır.

main() -> func() -> normalfunc() -> main()

Fonksiyon göstericileri genellikle, bir fonksiyonun parametresi olarak kullnanılırlar.Bu şekilde ana fonksiyonun işlevi genelleştirilerek belli durumlarda parametre olarak aldığı fonksiyon göstericisinin tutuğu adresteki fonksiyonu çalıştırır.Bu şekilde ana fonksiyonu hiç değiştirmeksizin programımıza yeni modüller ekleyebiliriz.Makalemizin sonunda fonksiyon göstericilerinin bu şekilde kullanımına örnek olması için basit bir komut yorumlayıcısı yazacağız.

Önemli Not:void (*p)(); ifadesinde p’ye geri dönüş değeri void olan ve herhangi
bir paremetrik yapıya sahip olan fonksiyon gösterici atanabilir. void (*p)(void); ifadesindeki p’ ye ise sadece geri dönüş değeri void ve parametresi void olan bir fonksiyon göstericisi atanabilir.

Fonksiyon göstericilerininde diğer türler gibi dizileri olabilir.Mesela void (*a[10])(void); tanımlaması a nın ,10 elamanlı bir fonksiyon gösterici dizisi olduğunu gösterir.Bu tür tanımlamalar okunabilirliği zorlaştırdığı için typedef edilmesi okunabilirlik açısından daha uygun olabilir.Örneğin;
PHP:
typedef void (*pF)(void); 
pF p; ile void (*p)(void); // yukarıdaki typedef işleminden sonra bu iki tanımlama aynı anlama gelir.

Buna benzer olarak,

typedef void (*a[10])(void); // burda a 10 elemanlı fonksiyon gösterici dizisidir.

Normal türler de olduğu gibi fonksiyon göstericilerine de tür dönüştürme işlemi ugulanabilir. Mesela,

int func(void)
{
... 
}
int (*p)(int,int);
p=func; //hata
p=( int(*)(int,int) ) func; //yukarıdaki hata tür dönüştürme ile legal getirilebilir. En dıştaki parantezler tür dönüştürme operatörüdür.
PHP:
Uygulama 

Fonksiyon göstericilerine örnek olması açısından aşağıdaki basit komut yorumlayıcısını inceleyelim.Bir prompt çıkararak kullanıcıdan komutlar alarak bunları yorumlayıp çeşitli işlemler yapan programlara "komut yorumlayıcısı" denir.Komut yorumlayıcı programların algoritması bir döngü içinde bir string almak, bunu komut listesinde taramak ve uygun işlemleri yapmaktır.Bu tür prgramlar genellikle fonksiyon göstericileri kullanırlar.Biz bu uygulamamızda komut yorumlayıcısının ana çatısını yazacağız fakat komutların anlamsal işlevlerini yapmak başka derslerin konusu olduğu için komutların işlevi boş bırakılacaktır.

#include <stdio.h>
#define CMD_SIZE 120

//Aşağıdaki komut yapısında, her komut için bir ad, ve her komutun yapılması için o komuta ait fonksiyonun adresi tutulur

typedef struct _KOMUT{
char *komutAdi;
void (*proc)(void);
}KOMUT;

//Komutlarımız.Dikkat ederseniz bütün fonksiyonların parametrik yapısı ve geri dönüş değeri özdeştir.

void Edit(void)
{
printf("Edit\n");
} 


void Copy(void)
{
printf("Copy\n");
} 


void Format(void)
{
printf("Format\n");
} 


void Dir(Exit)
{
printf("Exit\n");
} 

//KOMUT yapısı türünde bir global dizi oluşturup komutlarımızın adlarını ve komutlara ait fonksiyonları yerleştirelim

KOMUT komutlarim[]={ {"Edit",Edit},{"copy",Copy},{"Format",Format},{"exit",Exit} } ;


//Ana işlevimiz


int main()void
{
char KOMUTADI[CMD_SIZE];
int i;

for(; ;){
printf("CS>");
gets(KOMUTADI);
for (i=0 ; komutlarim[i].komutAdi !=NULL ; ++i)
if(!(strcmp(KOMUTADI,komutlarim[i].komutAdi))){
komutlarim[i].proc();
break; 
} 
if (komutlarim[i].komutAdi == NULL)
printf("Komut bulunmadı:\n") ;
}
return 0;
}
 

murat335

New member
nedemek kardeş zaten yaz oklunada gidiyorum eger yazılması gereken programı olan arkadaşlara duyrulur ama c# da olması ısrarla istenir ...........yazarım söz vermiştim zaten önceden yazar kodlarını sizlerle paylaşırım .....................sql dende istidigi triggeri oluşturmada ve istedigi sorguyuda yazmasına yardımcı olurum herkese kolay gele gaza geldim:)
 

punkD

New member
arkadaşım bir kere teşekkür ediyorum.
ama yapmayı beceremedigim bir kısım var:
ya komut yorumlayıcısına parametreli bir değer girmek istersek ?

mesela bir yaz("oğuz") yazıp entera bastığımızda ekrana oğuz yazması gibi..
parametre olayını nasıl halledebiliriz ?

teşekkürler

edit : neyse halettim yine de saol
 

HTML

Üst