|
Fonksiyon Göstericileri ve Uygulamaları |
|
Gönderiliyor lütfen bekleyin... |
|
|
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;
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.
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.
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 pye 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;
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.
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;
}
Makale:
Fonksiyon Göstericileri ve Uygulamaları C ve Sistem Programlama Sefer Algan
|
|
|
-
-
Eklenen Son 10
-
Bu Konuda Geçmiş 10
Bu Konuda Yazılmış Yazılmış 10 Makale Yükleniyor
Son Eklenen 10 Makale Yükleniyor
Bu Konuda Yazılmış Geçmiş Makaleler Yükleniyor
|
|