C/C++ da Fonksiyonlar

Merhaba arkadaşlar.Başka bir başlangıç düzeyinde dökümanda tekrar birlikteyiz.Bu dökümanda c/c++ dillerinde fonksiyonlardan bahsedeceğiz. Önce basitçe fonksiyonların matematikte ki haline bakacağız daha sonra c/c++ dillerinde nasıl yazıldıklarını ve nasıl parametre aldıklarını inceleyeceğiz. Ardından sırasıyla nasıl fonksiyon üstüste yüklemesi yapıldığını,bir fonksiyon ile bir değişkenin değerini nasıl kalıcı şekilde değiştireceğimizi ve son olarak varsayılan parametreleri(default parameters) göreceğiz.Uzatmadan başlayalım.

Matematikte Fonksiyonlar

Öncelikle fonksiyonların matematikteki hepimizin bildiği halini bir görelim :

        y = f(x)

Burada bir f(x) fonksiyonu var.Bu fonksiyonun ne yaptığını burada göremiyoruz.Ama bu fonksiyona bir x parametresi yolladığımızı anlıyoruz. Ayrıca bu fonksiyon hesaplandıktan sonra sonuçta oluşan değer y olacak.

f(x) fonksiyonunun da şu olduğunu düşünelim :

    f(x) = 2x2+3x+5

Artık f(x) fonksiyonunun ne yaptığını biliyoruz.Herhangi bir x değeri için f(x) fonksiyonunu hesaplayabiliriz.Örneğin :

    f(3) = 2*32+3*3+5

    f(3) = 32

Yani y artık 32 oldu.Fonksiyonlar temel olarak böyle.Ayrıca fonksiyonlara birden fazla parametre de yollayabilirsiniz.

    y = f(x,y) gibi.

C/C++ da Fonksiyonlar

Peki c/c++ da nasıl oluyor bu iş?Aslında pek bi fark yok.Fonksiyonun ismine karar veriyorsunuz,alacağı parametreleri ya da parametre almamasını belirliyorsunuz.Sonra yapacağı işi belirliyorsunuz ve programınız da kullanıyorsunuz. Zaten c/c++ herhangi bir program yazdıysanız.çoktan bir fonksiyon kullandınız demektir :) Hangi fonksiyon mu??Tabi ki main() :)

Şimdi main'e yakından bakalım.

void main()
{


}

En basit haliyle yazabileceğimiz main bu.Aynı f(x) gibi düşünün.f(x) fonksiyonunun aksine main burada herhangi bir parametre almıyor.Matematikte bu pek işe yarar birşey değil yani parametre almayan bir fonksiyon ama program yazarken parametreye ihtiyaç duymayan fonksiyonlarınız olabilir.

main() in başında yazan void nedir?

void in anlamı hiç birşey demek.Boşluk,yokluk anlamlarına da geliyor.Yani main() fonksiyonu tamamlanırken geri birşey döndürmüyor.Halbuki f(x) fonksiyonu geriye yaptığı işlemin değerini döndürüyordu.Bir de main() in geriye birşey döndüren haline bakalım.

int main()
{

    return 0;
}

Gördüğünüz gibi main'in geri döndüreceği tipi yazdık ve return anahtar kelimesini(keyword) kullanarak istediğimiz değeri geri gönderdik.Bu durumda 0 değeri işletim sistemine gidiyor çünkü main() fonksiyonu programımızın ana fonksiyonu.

Şimdi dökümanın başında yazdığımız f(x) fonksiyonunu c/c++ da yazalım.

int f(int x)
{
    return (
2*x*x+3*x+5);
}

Görüldüğü üzere f(x) fonksiyonu geriye tam sayı döndürecek fonksiyonun ismi f ve tamsayı bir x parametresi alıyor.Fonksiyon ismini yukarıdaki ile aynı olsun diye f yaptım ama buraya istediğiniz ismi yazabilirsiniz(draw,render,patlican vs.. :D).Aynı şekilde parametre olarak kullandığımız x değişkeni de herhangi bir isim alabilir. Tabi fonksiyon içindeki formülde de bu isim kullanılmalı.Şimdi bu fonksiyonu yaptığımız bir programda nasıl kullanırız onu görelim.

#include <stdio.h>

#include <conio.h>

int f(int x)
{
    return (
2*x*x+3*x+5);
}

void main()

{

    int iParam = 0;

    int iResult = 0;

    printf("f(x) fonksiyonu icin x parametresi alim canim : ");

    scanf("%d",&iParam);  

    iResult = f(iParam);

    printf("%d",iResult);

    getch();

}

Gördüğünüz gibi f fonksiyonunu main fonksiyonundan önce yazdık.Böylece f fonksiyonunu main fonksiyonu içinde kullanabiliyoruz.Bunu yapmanın bir başka yolu da main fonksiyonundan önce fonksiyonun sadece tanımını yapmak ama gövdesini yani neler yaptığını başka biyerde yazmak.Bunu da yazalım.

#include <stdio.h>

#include <conio.h>

int f(int x);

void main()

{

    int iParam = 0;

    int iResult = 0;

    printf("f(x) fonksiyonu icin x parametresi alim canim : ");

    scanf("%d",&iParam);  

    iResult = f(iParam);

    printf("%d",iResult);

    getch();

}

int f(int x)
{
    return (
2*x*x+3*x+5);
}

Bu nerede işimize yarar?Projemiz büyüdükçe birden fazla kaynak(source) dosyamız olacak.Ve tabiki başlık(header) dosyalarımız.Fonksiyonların başlığını başlık dosyasına gövdesini ise istediğimiz bir kaynak dosyasına koyabiliriz.Daha sonra bu fonksiyonu kullanmak istediğimizde tanımının bulunduğu başlık dosyasını eklememiz yeterli olacaktır. Buna örnek görmek için dökümanla gelen kaynak dosyasını inceleyebilirsiniz.

İki Parametre

Fonksiyonlara birkaç parametre birden yollayabileceğimizden bahsetmiştik bunu yapmak için parantezlerin içine fonksiyonun alacağı parametreleri sırası ile tiplerini belirterek yazıyoruz.Örneğin :

int carp(int a,int b)
{
    return a*b;
}

Bu fonksiyon gönderilen iki tam sayı değeri çarpıyor ve sonucu geri döndürüyor.İsterseniz farkli tipte parametreleri de fonksiyona yollayabilirsiniz. Peki diyelim ki biz tamsayı değilde iki tane kesirli sayı çarpmak istedik ancak yine carp isimli bir fonksiyon kullanmak istiyoruz.Bunu nasıl yapıcaz?C de mümkün değil ancak farkli bir fonksiyon yazip carp_kesirli gibi bunun parametrelerini ve döndüreceği değeri float tipinde yapabiliriz.Örnek :

//Tam sayi carpan fonksiyon

int carp(int a,int b)
{
    return a*b;
}

//Kesirli sayi carpan fonksiyon

float carp_kesirli(float a,float b)
{
    return a*b;
}

Fonksiyon Üst Üste Yükleme(Function Overloading)

Bunun c++ da çok daha kullanışlı bir yolu var.Function Overloading.Türkçeye direk çevirmeye kalkarsak fonksiyon aşırı yüklemesi diyebiliriz.Ama ayıp etmiş oluruz :) Çünkü aşırı yükleme falan yapmıyoruz.Fonksiyon üst üste yükleme diyelim daha iyi.Bir fonksiyonu yüklediğimiz zaman fonksiyonun ismi aynı kalıyor ama ona gönderdiğimiz parametre leri değiştirebiliyoruz.Yukarıda ki fonksiyonu birde yükleme ile yapalım :

//Tam sayi carpan fonksiyon

int carp(int a,int b)
{
    return a*b;
}

//Kesirli sayi carpan fonksiyon

float carp(float a,float b)
{
    return a*b;
}

Görüldüğü üzere fonksiyon isimleri aynı ama farklı veri tipleri üzerinde çalışıyorlar.Burada unutulmaması gereken bir fonksiyonu yüklerken farklı olması gereken parametreler. Fonksiyonların sadece dönüş tiplerini değiştirip yükleyemezsiniz.

//Tam sayi carpan fonksiyon

int carp(int a,int b)
{
    return a*b;
}

//Kesirli sayi carpan fonksiyon

float carp(int a,int b)
{
    return a*b;
}

Bu yazdığım hata verecektir.

Fonksiyon ile bir değişkenin değerini değiştirme

Eninde sonunda bunu yapmanız gerekecektir.Mesela bir değişkeniniz var,atıyorum "speed" olsun.Bunu "stop" diye bir fonksiyona gönderip sıfır olmasını istiyorsunuz. speed değişkeni main fonksiyonunda tanımlı.Siz bunu parametre olarak fonksiyona yollayacaksınız.Şöyle bir deneme yapalım :

#include <stdio.h>

#include <conio.h>

int stop(int deger)
{
    deger = 0;
}

void main()

{

    int speed = 100;

    printf("speed degiskeninin su anki degeri %d",speed);

        stop(speed);

    printf("speed degiskeninin su anki degeri %d",speed);

    getch();

}

Bu programı yazıp çalıştırırsak alacağımız sonuç bizi şaşırtabilir çünkü speed değişkeni ekrana iki defa 100 olarak yazılır.Halbuki biz bu değişkeni stop fonksiyonuna yolladık ve fonksiyon içinde sıfıra eşitledik.Ama neden bu değişiklik main fonksiyonuna yansımadı??Burada bilinmesi gereken önemli birşey var.Ne zaman bir değişkeni bir fonksiyona yollarsanız bu değişkenin o fonksiyon için bir kopyası oluşur ve siz fonksiyon içinde bu kopyayı kullanırsınız.Yani aslında "speed" değişkenini diil onunla aynı değere sahip olan kopyası "deger" değişkenini değiştiriyoruz.Buna pass by value yani değerle göndermekte deniyor.Gerçekten main fonksiyonu içindeki speed değişkenin değiştirmek için yapabileceğimiz iki şey var.Bunlar işaretçi(pointer) veya referans(reference) kullanmakBunların ikiside aynı işi yapıyor aslında ama referanslar c++ da var.Temel mantıkları fonksiyona değişkenin değerini yollamaktansa değişkenin bellekteki adresini yollamak böylece o değişkeni kalıcı olarak değiştirilebiliyoruz.Şimdi yukarıdaki programı bir de bunları kullanarak yapalım :

#include <stdio.h>

#include <conio.h>

void stop(int deger)
{
    deger = 0;
}

void stop_pointer(int *deger)
{
    *deger = 0;       
}

void stop_reference(int &deger)
{
    deger = 0;
}

void main()

{

    int speed = 100;

    printf("speed degiskeninin su anki degeri %d",speed);

        stop(speed);

    printf("speed degiskeninin su anki degeri %d",speed);

    stop_pointer(&speed);

    //veya

    //stop_reference(speed);

    getch();

}

Burada dikkat edilmesi gereken pointer kullanırken fonksiyona değişkenin adresini yolladığımızı belirtmek (& ile).Ve fonksiyon içinde değişkene ulaşmak için "*deger" kullanmak.Eğer deger i kullanırsak işaretçinin gösterdiği adresi değiştiririz.Bunu istemiyoruz :)Referans ile yollamada tek yapmamız gereken fonksiyon tanımında parametre isminden önce & eklemek.

Varsayılan Parametreler (Default Parameters)

Son olarak bahsetmek istediğim konu varsayılan parametreler.Şimdiye kadar gördüğümüz tüm fonksiyonlarda fonksiyonun parametrelerini fonksiyonu kullanırken yazmak zorundaydık.Ama buna mecbur değiliz.Bazen öyle durumlar oluyor ki bir fonksiyonun ilk parametresini siz girmek istiyorsunuz ama diğer parametrelerin otomatik olarak doldurulmasını istiyorsunuz.Ama gerektiğinde yine bu parametrelere değer verebiliyorsunuz :) Karışık oldu biraz ondan örnek yazalım birtane:

#include <stdio.h>

#include <conio.h>

float findHeight(int t,float g = 9.8f)
{
    return 1.0f/2.0f*g*t*t); 

}

void main()

{

    int time = 0;

    printf("cismin yere düsme süresini girin : ");

        scanf("%d",&time);

    printf("cisim %f metreden dustu",findHeight(time));

    getch();

}

Görüldüğü gibi fonksiyona sadece bir tek parametre yolladık.İsteseydik ikinci parametreyide gönderebilirdik.Ama göndermediğimiz zaman g değeri 9.8f olacaktır. Varsayılan parametrelerde dikkat edilmesi gereken şey çok sayıda parametre varsa ve bunlar default ise aradan herhangi bir parametreye değer veremeyecek olmanız. Örneğin şöyle bir fonksiyon olsun :

    void func(int t,int a = 9,int b = 1,int c = 2,int d = 20);
 

Bu fonksiyonu programda kullanırken eğer c parametresine değer vermek istiyorsak ondan önceki a ve b parametrelerine de değer vermek zorundayız.Aradan karpuz gibi şeçmeye kalkarsak c/c++ hangi parametreden bahsettiğimizi anlamaz.Örnek:

    func(time,3,2,0);

Böyle çağırılmış fonksiyon t yi time'a,a'yı üçe,b'yi ikiye,c'yi sıfıra ve d'yi yirmiye(varsayılan) eşitler.Hepsi bu.

Kapanış

Evet dökümanımızın sonuna geldik :).Fonksiyonlar gerçekten basit ve her zaman kullanacağınız şeyler o yüzden öğrenmekte fayda var :) Dökümanla birlikte gelen kaynak dosyalarında burda yazdığım fonksiyonlarla yapılmış bir program bulabilirsiniz. Başka değinmek istediğim bir konu:Fonksiyonlara gönderdiğiniz değişken eğer büyük bir veri yapısı ise, buu pointer ya da referans olarak göndermeniz aksi halde fonksiyon bu yapının bir kopyasını yaratmakla uğraşacaktık ve bu zaman kaybına yok açar.

Dökümandaki yazım hatalarını ve diğer hataları farkedersek lütfen paylaşalım Herkese İyi Çalışmalar.

Not : Bu döküman hazırlanırken bol miktarda kola,panço tüketilmiştir.Ayrıca In Flames,NightWish,Ensiferum ve Hammerfall ile ortam renklendirilmiştir :)

[ Bu dökümana ilişkin örnek dosyaları indirmek için tıklayın (16Kb) ]

Black_Knight :: Barış S. Uşaklı :: 2005 :: www.oyunyapimi.org




Bu haberin geldigi yer: oyunyapimi.org
http://www.oyunyapimi.org

Bu haber icin adres:
http://www.oyunyapimi.org/modules.php?name=Sections&op=viewarticle&artid=80