← Kursa Dön
📄 Text · 12 min

Fonksiyon Tanımlama ve Çağırma

Bir mutfakta yemek yapıyorsun. Her seferinde sıfırdan "önce tavayı al, yağı koy, ısıt..." demek yerine bir tarif kartın var: "Yumurta pişir" diyorsun ve adımlar otomatik uygulanıyor. İşte fonksiyon tam olarak bu tarif kartıdır — bir işi paketleyip isim verirsin, sonra o ismi çağırarak işi tekrar tekrar yaptırırsın.

Fonksiyonlar programlamanın temel yapı taşıdır. Kodu organize eder, tekrarı önler ve büyük problemleri küçük parçalara böler. Bu derste fonksiyon tanımlamayı, çağırmayı ve C++'ta fonksiyonların nasıl çalıştığını sıfırdan öğreneceksin.


Fonksiyon Nedir?

Fonksiyon, belirli bir görevi yerine getiren isimlendirilmiş kod bloğudur. Bir kere yazarsın, istediğin kadar çağırırsın.

Fonksiyonsuz dünya:

// Aynı hesaplamayı 3 kez yapıyoruz — tekrar, tekrar, tekrar
double alan1 = 3.14159 * 5.0 * 5.0;
double alan2 = 3.14159 * 8.0 * 8.0;
double alan3 = 3.14159 * 12.0 * 12.0;

Fonksiyonlu dünya:

double daireAlani(double yaricap) {
    return 3.14159 * yaricap * yaricap;
}

double alan1 = daireAlani(5.0);
double alan2 = daireAlani(8.0);
double alan3 = daireAlani(12.0);

İkinci versiyon daha kısa, daha okunabilir ve formülde hata varsa tek bir yerde düzeltirsin.


Fonksiyon Söz Dizimi

C++'ta bir fonksiyon tanımının dört parçası var:

dönüşTipi fonksiyonAdı(parametre1Tipi param1, parametre2Tipi param2) {
    // fonksiyon gövdesi
    return değer;  // dönüş tipi void değilse
}
  • Dönüş tipi: Fonksiyonun geriye döndürdüğü değerin tipi (int, double, string, bool vb.)

  • Fonksiyon adı: Fonksiyonu çağırmak için kullandığın isim

  • Parametreler: Fonksiyona verilen girdi değerleri (virgülle ayrılır)

  • Gövde: Fonksiyonun yaptığı iş (süslü parantez içinde)

#include <iostream>
using namespace std;

// Fonksiyon tanımı
int topla(int a, int b) {
    int sonuc = a + b;
    return sonuc;
}

int main() {
    // Fonksiyon çağrısı
    int s = topla(3, 5);
    cout << "3 + 5 = " << s << endl;  // 8

    // Doğrudan kullanım
    cout << "10 + 20 = " << topla(10, 20) << endl;  // 30

    return 0;
}

Fonksiyon çağrıldığında şunlar olur:

  1. Argümanlar (3 ve 5) parametrelere (a ve b) kopyalanır

  2. Gövde çalışır (sonuc = 3 + 5 = 8)

  3. return ile değer geri döner

  4. Çağıran yerde bu değer kullanılır


void Fonksiyonlar — Değer Döndürmeyen

Her fonksiyonun bir değer döndürmesi gerekmez. Sadece bir iş yapıp biten fonksiyonlar için void kullanılır.

#include <iostream>
#include <string>
using namespace std;

void selamla(string isim) {
    cout << "Merhaba, " << isim << "!" << endl;
    // return yok — void fonksiyon
}

void cizgiCiz(int uzunluk) {
    for (int i = 0; i < uzunluk; i++) {
        cout << "-";
    }
    cout << endl;
}

int main() {
    selamla("Ali");       // Merhaba, Ali!
    cizgiCiz(20);         // --------------------
    selamla("Ayşe");      // Merhaba, Ayşe!

    return 0;
}

void fonksiyonlar ekrana yazdırma, dosyaya yazma, bir durumu değiştirme gibi "yan etki" (side effect) üreten işler için kullanılır.

void Fonksiyonda return

void fonksiyonlarda return; (değersiz) kullanarak fonksiyondan erken çıkabilirsin:

void yasKontrol(int yas) {
    if (yas < 0) {
        cout << "Geçersiz yaş!" << endl;
        return;  // Fonksiyondan erken çık
    }

    if (yas >= 18) {
        cout << "Yetişkin" << endl;
    } else {
        cout << "Çocuk" << endl;
    }
}

return İfadesi

return iki iş yapar:

  1. Fonksiyonun çalışmasını sonlandırır

  2. Bir değer döndürür (void hariç)

#include <iostream>
using namespace std;

int mutlakDeger(int x) {
    if (x >= 0) {
        return x;      // Pozitifse olduğu gibi döndür
    }
    return -x;         // Negatifse işaretini değiştir
}

// Birden fazla return olabilir — ilk çalışan kazanır
bool ciftMi(int n) {
    if (n % 2 == 0) {
        return true;
    }
    return false;

    // Daha kısa yazım:
    // return n % 2 == 0;
}

int main() {
    cout << mutlakDeger(-7) << endl;   // 7
    cout << mutlakDeger(3) << endl;    // 3
    cout << boolalpha;
    cout << ciftMi(4) << endl;         // true
    cout << ciftMi(7) << endl;         // false

    return 0;
}

⚠️ Dikkat: Void olmayan bir fonksiyonda return unutursan, fonksiyon tanımsız davranış (undefined behavior) sergiler. Derleyici uyarı verir ama program beklenmedik sonuçlar üretebilir. Her code path'te return olmalı.

// KÖTÜ — else dalında return yok
int buyukOlan(int a, int b) {
    if (a > b) {
        return a;
    }
    // b >= a durumunda ne dönecek? Tanımsız davranış!
}

// İYİ — her durumda return var
int buyukOlan_duzeltilmis(int a, int b) {
    if (a > b) {
        return a;
    }
    return b;
}

Fonksiyon Prototipi (Declaration vs Definition)

C++ kodunu yukarıdan aşağıya okur. Bir fonksiyonu çağırmadan önce derleyicinin o fonksiyonu tanıması gerekir. İki yol var:

Yol 1: Fonksiyonu Çağırmadan Önce Tanımla

#include <iostream>
using namespace std;

// Tanım main'den ÖNCE
int kare(int x) {
    return x * x;
}

int main() {
    cout << kare(5) << endl;  // Çalışır
    return 0;
}

Yol 2: Prototip (Declaration) + Sonradan Tanım

#include <iostream>
using namespace std;

// Prototip — fonksiyonun "kimlik kartı"
int kare(int x);          // Sadece imza, gövde yok
double topla(double, double);  // Parametre isimleri opsiyonel

int main() {
    cout << kare(5) << endl;          // 25
    cout << topla(3.5, 2.1) << endl;  // 5.6
    return 0;
}

// Tanım — fonksiyonun gerçek gövdesi
int kare(int x) {
    return x * x;
}

double topla(double a, double b) {
    return a + b;
}

Prototip, derleyiciye "böyle bir fonksiyon var, adı şu, parametreleri şu tipte, dönüş tipi şu" der. Gövdesi daha sonra yazılır.

Prototip Neden Önemli?

Küçük programlarda fark etmez ama büyük projelerde fonksiyonlar farklı dosyalarda olur. Header dosyalarında (.h) prototipler, kaynak dosyalarında (.cpp) tanımlar bulunur. Bu yapıyı ilerideki derslerde detaylı göreceksin.

// matematik.h  — prototipler
int topla(int a, int b);
int cikar(int a, int b);

// matematik.cpp — tanımlar
int topla(int a, int b) { return a + b; }
int cikar(int a, int b) { return a - b; }

// main.cpp — kullanım
#include "matematik.h"
int sonuc = topla(3, 5);

💡 İpucu: Prototipte parametre isimleri yazmak zorunlu değildir (int topla(int, int); geçerli). Ama okunabilirlik için isim yazmak iyi bir alışkanlıktır.


main() Fonksiyonunun Özel Yeri

main() fonksiyonu C++ programının giriş noktasıdır (entry point). İşletim sistemi programını çalıştırdığında ilk çağrılan fonksiyon budur.

int main() {
    // Program buradan başlar
    return 0;  // 0 = başarılı çıkış
}

main() Hakkında Kurallar

  • Her C++ programında bir ve yalnız bir main() olmalı

  • Dönüş tipi her zaman `int`

  • return 0 başarılı çıkışı, sıfır olmayan değerler hatayı belirtir

  • return 0; yazmasanız bile derleyici otomatik ekler (sadece main için geçerli)

main() ile Komut Satırı Argümanları

main() iki parametre alabilir:

#include <iostream>
using namespace std;

int main(int argc, char* argv[]) {
    cout << "Argüman sayısı: " << argc << endl;

    for (int i = 0; i < argc; i++) {
        cout << "argv[" << i << "] = " << argv[i] << endl;
    }

    return 0;
}

Programı ./program merhaba dunya şeklinde çalıştırırsan:

Argüman sayısı: 3
argv[0] = ./program
argv[1] = merhaba
argv[2] = dunya
  • argc — argüman sayısı (argument count)

  • argv — argüman dizisi (argument vector), her eleman bir C-string


Parametresiz Fonksiyonlar

Fonksiyonların parametre alması zorunlu değil:

#include <iostream>
#include <ctime>
using namespace std;

int rastgeleSayi() {
    return rand() % 100 + 1;  // 1-100 arası
}

void simdikiZaman() {
    time_t simdi = time(nullptr);
    cout << "Şu an: " << ctime(&simdi);
}

int main() {
    srand(time(nullptr));

    cout << "Rastgele: " << rastgeleSayi() << endl;
    simdikiZaman();

    return 0;
}

Parametresiz fonksiyonlar genellikle global durumu okur, sistem bilgisi döndürür veya sabit bir iş yapar.


Fonksiyonları Organize Etme

İyi bir programda her fonksiyonun tek bir sorumluluğu olmalı. Buna Single Responsibility Principle (tek sorumluluk ilkesi) denir.

#include <iostream>
#include <string>
using namespace std;

// KÖTÜ — tek fonksiyon her şeyi yapıyor
void herSeyiYap(string isim, int puan) {
    // Giriş doğrulama
    if (isim.empty()) { cout << "Hata!" << endl; return; }
    if (puan < 0 || puan > 100) { cout << "Hata!" << endl; return; }

    // Not hesaplama
    string not_harf;
    if (puan >= 90) not_harf = "A";
    else if (puan >= 80) not_harf = "B";
    else not_harf = "C";

    // Yazdırma
    cout << isim << ": " << not_harf << endl;
}

// İYİ — her fonksiyonun tek görevi var
bool gecerliMi(const string& isim, int puan) {
    return !isim.empty() && puan >= 0 && puan <= 100;
}

string notHesapla(int puan) {
    if (puan >= 90) return "A";
    if (puan >= 80) return "B";
    return "C";
}

void sonucYazdir(const string& isim, const string& not_harf) {
    cout << isim << ": " << not_harf << endl;
}

int main() {
    string isim = "Ali";
    int puan = 85;

    if (gecerliMi(isim, puan)) {
        string not_harf = notHesapla(puan);
        sonucYazdir(isim, not_harf);
    }

    return 0;
}

İkinci yaklaşımda her fonksiyon küçük, test edilebilir ve yeniden kullanılabilir.

💡 İpucu: Bir fonksiyon 20-30 satırdan uzunsa, muhtemelen birden fazla iş yapıyordur. Parçalara bölmeyi düşün. Fonksiyon ismi "ve" içeriyorsa (hesaplaVeYazdir) bu genellikle iki ayrı fonksiyon olması gerektiğinin işaretidir.


Fonksiyon İsimlendirme Kuralları

İyi fonksiyon isimleri kodun okunabilirliğini dramatik şekilde artırır:

  • Fiil ile başla: hesapla, bul, kontrolEt, yazdir

  • Ne yaptığını anlat: daireAlaniHesapla(), kullaniciDogrula()

  • Kısa ama açık: calc() yerine hesaplaVergi()

  • Bool döndürenler: mi/mu sorusu sor — gecerliMi(), bosalanMi(), hazirMi()

  • camelCase veya snake_case: Projede tutarlı ol

// İYİ isimler
double hesaplaKDV(double fiyat);
bool stokVarMi(int urunId);
void raporOlustur();
string formatlaParaBirimi(double miktar);

// KÖTÜ isimler
double f(double x);        // Ne yaptığı belirsiz
void islem();              // Hangi işlem?
int abc(int n);            // Anlamsız

Özet

  • Fonksiyon belirli bir görevi paketleyen isimlendirilmiş kod bloğudur — dönüşTipi isim(parametreler) { gövde }

  • void fonksiyonlar değer döndürmez — yan etki üreten işler için kullanılır

  • return fonksiyonu sonlandırır ve değer döndürür — void olmayan fonksiyonlarda her code path'te return olmalı

  • Prototip (declaration) fonksiyonun imzasını bildirir — tanım (definition) gövdeyi içerir, büyük projelerde ikisi ayrı dosyalarda olur

  • main() programın giriş noktasıdır — dönüş tipi int, return 0 başarılı çıkış anlamına gelir

  • Her fonksiyon tek bir sorumluluk taşımalı — küçük, odaklı, iyi isimlendirilmiş fonksiyonlar yazılabilir kod üretir