Temel C Programlama -27- Diğer Fonksiyon Konuları ve Recursive Fonksiyonlar

C dilinde fonksiyonlara dair anlatacağımız iki konu kaldı. Bunlar iç içe fonksiyonlar ve özyinelemeli (recursive) fonksiyonlardır. Eğer C++ dilini anlatsaydık fonksiyonlar hakkında daha çok bilgiyi anlatacaktık. Çünkü C++ dilinde fonksiyon konusuna ek özellikle getirilmiştir. Fakat C dilinde öğrendiğimiz bilgilerin neredeyse tamamını C++ dilinde de kullanabileceğimiz için biz hiç C++ konularına değinmeden C üzerinden konumuza devam edeceğiz. İleride C++, Visual C++ ve masaüstü yazılım geliştirme konularına geldiğimizde iyi ki önceden C öğrenmişim diyeceksiniz. Çünkü C++ kapsamlı, karmaşık ve yoğun bir dildir. C öğrenmekle sade bir dil üzerinden programlama mantığını öğrenirsiniz fakat ilk seferde C++ öğrenmekle bütün ayrıntıyı öğrenmek zorunda kalırsınız. Bu da kafanızı karıştırmaya yeterli olur.

İç İçe Fonksiyonlar

İç içe fonksiyonlar prensipte oldukça basittir. Fonksiyon çağrısı içerisinde fonksiyon çağırmak kadar basit olan bu yöntem ile kodlarınızı daha kısa yazma imkanı bulursunuz ve fonksiyondan dönen değerleri doğrudan argüman olarak aktarırsınız. Daha önceki yazıdaki örnekte yaptığımız üs alma fonksiyonunu şimdi printf içerisinde çağıralım ve bir satır koddan tasarruf edelim.

#include <stdio.h>
#include <stdlib.h>
int us_al (int taban, int us);
int main() {
	int n;
	int p;
    printf("Ussunu Almak istediginiz karakteri giriniz:");
    scanf("%i", &n);
    printf("\nKac Us Alinacagini giriniz:");
    scanf("%i", &p);
    //int sonuc = us_al(n,p);
	printf("\n Sonuc: %i \n", us_al(n, p));
system("PAUSE");
}


int us_al (int taban, int us)
{
    int sonuc=1;
    while ( us != 0)
    {
        sonuc *= taban;
        us--;
    }
    return sonuc;

}

printf(“\n Sonuc: %i \n”, us_al(n, p));

Bu printf fonksiyonu işletilmeden önce parantez içindeki aritmetik ve mantık işlemlerinin öncelikle yapıldığını biliyorduk. Aynı zamanda parantez içerisinde çağırılan fonksiyonlar da önce çalıştırılmakta sonra da geri dönen değer argüman halinde prinf fonksiyonuna gitmektedir. Bu C dilinin esnek özellikllerinden biridir. Eğer yazdığınız kodu bu şekilde anlamakta zorlanıyorsanız bunu kullanmayabilirsiniz. Daha yüksek seviye geliştirme ortamlarından farklı olarak C dilinde kod sadeleştikçe okunabilirliği azalmaktadır. Okunabilirliğin artmasına yönelik yaptığımız çalışmalar kodu kalabalıklaştırmakta ve performansı düşürmektedir.

Özyinelemeli fonksiyonlar (Recursion)

Yukarıda fonksiyon çağırırken parantezler içerisinde farklı bir fonksiyonu çağırmıştık. Peki bu fonksiyon fonksiyon kendi içerisinde kendisini çağırırsa ne olur dersiniz? Muhtemelen program sürekli aynı fonksiyonu çağırır ve sonsuz döngüye girer veya derleyici hata verir, diye bir cevap vermeniz muhtemeldir. Fakat C dilinde bu esneklik vardır ve bir fonksiyon kendi içerisinde kendini çağırabilir. Elbette bu tehlikeli bir yöntemdir ve acemi programcıların kolay kolay bulaşmaması lazımdır. Fakat biz bir kod veya kütüphane incelediğimizde fonksiyonun kendisini çağırdığını gördüğümüz vakit “Bu da neyin nesi?” dememek için başlangıçta öğrenmemiz lazımdır. Bu yöntemi bazı matematik ve veri işleme fonksiyonlarında kullanmanız ise oldukça etkili olacaktır. Özyinelemeli fonksiyonlar ciddi derecede bellek tasarrufu sağlamaktadır.

Özyinelemeli fonksiyonları şu şekilde özetlemek mümkündür.

void oz_yineleme()
{
  komutlar;
  komutlar;
  komutlar; 
  oz_yineleme();
  komutlar; 
}

int main()
 {
  oz_yineleme();
 }

Herhangi bir döngü veya karar mekanizmasına tabi tutmadan şartsız bir şekilde böyle bir programı çalıştırmak oz_yineleme() fonksiyonu çağırıldığı andan itibaren fonksiyon kendini fonksiyon blokunda sürekli çağıracak ve sonsuz bir döngü halinde blok başı ile kendi arasında olan komutları işletip duracaktır. Ama biz aynı komutu şu şekilde yazarsak durum nasıl olur bir bakalım.

void oz_yineleme()
{
  komutlar;
  komutlar;
  komutlar; 
  if ( sart == TRUE)
  return 1;
  oz_yineleme();

}

int main()
 {
  oz_yineleme();
 }

Burada oz_yineleme() fonksiyonu artık kendini sonsuz döngüye sokmuş olsa da biz buraya bir şart ekleyerek return komutu ile döngüden çıkma fırsatı tanıdık. Eğer bu şart yapısı eksiksiz olmazsa ve bir noktada hata çıkabilirse program sonsuz döngüye girecektir. Biz burada önce programı sonsuz döngüye sokuyoruz ve sonra sonsuz döngüden çıkarma çözümünü arıyoruz. Şimdi örnek bir fonksiyonu inceleyerek ne kadar derine inebildiğini görelim.

int toplam(int sayi)
{
    if (sayi!=0)
        return sayi + toplam(sayi-1); // toplam() kendini çağırır
    else
        return sayi;
}

Burada ilk satırdan itibaren fonksiyonun basit bir fonksiyon gibi durduğunu görüyoruz. sayi adında bir değer alıyor ve adından da bu sayıya kadar olan sayıların toplamını verebileceğini tahmin edebiliyoruz. Defalarca toplama işlemi yapması için normalde döngüye ihtiyaç olsa da burada döngü yerine tek bir karar yapısı görüyoruz. Eğer sayı 0 değilse return komutu ile fonksiyondan çıkılıyor fakat return’dan önce bir dizi işlem yapılmış. Bu işlemler sayi + toplam(sayi-1) olunca kafamız oldukça karışabilir. sayi + ‘ya kadar olan kısmı anlasak da sayıyla neyin toplanacağı konusunda kafamız karışıyor. Bu işlem yapılmadan ve return ile fonksiyondan çıkışmadan önce toplam(sayi-1) ile fonksiyon bu sefer argüman olarak sayi değişkeninin bir eksiğini alıyor ve fonksiyon içindeyken yine çağırılıyor. Bu sefer sayi değeri bir eksik olsa da karşımıza tekrar aynı if yapısı çıkıyor ve aynı şartı sağlarsa yine bir defa çağırılıyor. Bu sefer 2. fonksiyona göre sayi-1 olsa da birinci fonksiyona göre gönderilen argüman sayi-2 oluyor. Böylece alt alta sayı miktarınca fonksiyon çağırıldıktan sonra bütün sayı değerlerinin sayi ile toplamını elde ediyoruz.

Evet, bahsettiğimiz konu oldukça kafanızı karıştırsa da bu normaldir. Benim de bunu anlamam uzun sürmüştür. Bunu anlayabilmek için C dili mantığını kafanıza oturtmanız ve pratik yapmanız gereklidir. Sadece bunun üzerinde değil fonksiyonlar üzerinde pratik yaptığınızda ve C dilinin esnekliğini anladığınızda bunu rahatça kavrarsınız. Sizin için daha anlaşılır olması için bir resim vereceğim.

Resim: https://cdn.programiz.com/sites/tutorial2program/files/natural-numbers-sum-recursion_0.jpg

Karar yapılarını anlayabilmenin göstergesi kümelenmiş else if yapılarını etkin kullanabilmek olduğu gibi fonksiyonları tam olarak anlamanın göstergesi de özyinelemeli fonksiyonları anlamaktır. Biz pratikte çok fazla kullanmadığımız için yukarıda verdiğimiz örnek kod ile yetiniyoruz. Eğer bir kitap yazsaydım elbette daha ayrıntılı açıklardım fakat bu yazıların kitap kalitesinde olması için çabalasam da kitap yazacak kadar çok zaman bulamıyorum.

Last updated