← Kursa Dön
📄 Text · 10 min

switch-case Yapısı

Diyelim ki bir restoran menüsündesin ve garson sana soruyor: "1 numaralı menü mü, 2 numaralı mı, 3 numaralı mı?" Sen bir numara söylüyorsun ve garson ona göre yemeği getiriyor. İşte switch-case tam olarak böyle çalışır — bir değere bakarsın ve o değere göre doğru yolu seçersin.

if-else if zincirleri de aynı işi yapar ama bir değişkeni birçok sabit değerle karşılaştırıyorsan, switch çok daha temiz ve okunabilir bir yapı sunar.


switch Temel Yapısı

switch bir ifadenin değerini alır ve onu case etiketleriyle eşleştirir. Eşleşen case'in kodu çalışır.

#include <iostream>
using namespace std;

int main() {
    int gun = 3;

    switch (gun) {
        case 1:
            cout << "Pazartesi" << endl;
            break;
        case 2:
            cout << "Salı" << endl;
            break;
        case 3:
            cout << "Çarşamba" << endl;
            break;
        case 4:
            cout << "Perşembe" << endl;
            break;
        case 5:
            cout << "Cuma" << endl;
            break;
        default:
            cout << "Hafta sonu" << endl;
            break;
    }

    return 0;
}

gun değeri 3 olduğu için case 3: eşleşir ve "Çarşamba" yazdırılır. break ifadesi switch'ten çıkmayı sağlar — birazdan neden bu kadar önemli olduğunu göreceksin.

switch'in Kuralları

  • switch ifadesi tam sayı (integer) veya enum tipinde olmalı. string, float, double kullanamazsın.

  • Her case etiketi derleme zamanında bilinen sabit bir değer (constant expression) olmalı.

  • Aynı switch içinde iki case aynı değere sahip olamaz.

// ÇALIŞMAZ — string ile switch kullanılamaz
string renk = "kirmizi";
switch (renk) {  // Derleme hatası!
    case "kirmizi": break;
}

// ÇALIŞIR — char ile switch
char harf = 'A';
switch (harf) {
    case 'A': cout << "Harf A" << endl; break;
    case 'B': cout << "Harf B" << endl; break;
    default:  cout << "Diğer" << endl; break;
}

default — Hiçbir case Eşleşmezse

default etiketi, hiçbir case değeri eşleşmediğinde çalışan bloktur. if-else'deki son else gibi düşünebilirsin.

#include <iostream>
using namespace std;

int main() {
    int secim = 7;

    switch (secim) {
        case 1:
            cout << "Seçenek 1" << endl;
            break;
        case 2:
            cout << "Seçenek 2" << endl;
            break;
        case 3:
            cout << "Seçenek 3" << endl;
            break;
        default:
            cout << "Geçersiz seçim!" << endl;
            break;
    }

    return 0;
}

default zorunlu değil ama her zaman eklenmesi iyi bir alışkanlıktır. Beklenmeyen değerlerle karşılaşıldığında programın sessizce hiçbir şey yapmaması yerine en azından bir uyarı vermesi çok daha sağlıklı.

default etiketini switch'in herhangi bir yerine koyabilirsin — sona koymak zorunlu değil ama konvansiyon olarak en sona yazılır.


break'in Önemi ve Fall-Through

İşte switch-case'in en tehlikeli ve en çok hata yapılan noktası: break yazmazsan ne olur?

break olmadan program bir sonraki case'e "düşer" (fall-through) ve o case'in kodunu da çalıştırır. Bu durum eşleşme kontrolü yapmadan devam eder — ta ki bir break bulana veya switch'in sonuna gelene kadar.

#include <iostream>
using namespace std;

int main() {
    int sayi = 2;

    // break OLMADAN — fall-through!
    cout << "break olmadan:" << endl;
    switch (sayi) {
        case 1:
            cout << "Bir" << endl;
        case 2:
            cout << "İki" << endl;
        case 3:
            cout << "Üç" << endl;
        case 4:
            cout << "Dört" << endl;
        default:
            cout << "Diğer" << endl;
    }

    return 0;
}

Çıktı:

break olmadan:
İki
Üç
Dört
Diğer

sayi 2 olduğu için case 2: ile eşleşir ama break olmadığı için case 3:, case 4: ve default: da çalışır. Bu genellikle istemediğin bir davranıştır.

⚠️ Dikkat: Her case bloğunun sonuna break; koymayı alışkanlık edin. Unutmak en yaygın switch hatalarından biridir ve bulması zor bug'lara yol açar.


Bilinçli Fall-Through

Bazen fall-through davranışını bilerek isteyebilirsin. Birden fazla case'in aynı kodu çalıştırmasını istediğinde kullanışlıdır.

#include <iostream>
using namespace std;

int main() {
    int ay = 4;

    switch (ay) {
        case 12:
        case 1:
        case 2:
            cout << "Kış" << endl;
            break;
        case 3:
        case 4:
        case 5:
            cout << "İlkbahar" << endl;
            break;
        case 6:
        case 7:
        case 8:
            cout << "Yaz" << endl;
            break;
        case 9:
        case 10:
        case 11:
            cout << "Sonbahar" << endl;
            break;
        default:
            cout << "Geçersiz ay" << endl;
            break;
    }

    return 0;
}

Burada case 3:, case 4: ve case 5: hepsi aynı kodu çalıştırır. Bu yasal ve yaygın bir kullanımdır — çünkü boş case'ler bir sonraki case'e düşer.


[[fallthrough]] Attribute (C++17)

Peki bilinçli fall-through kullanırken case'in içinde kod varsa? Derleyici seni uyarabilir: "Hey, burada break unutmuş olabilirsin." Bu uyarıyı bastırmak ve "evet, bilerek yapıyorum" demek için C++17'de `[[fallthrough]]` attribute'u eklendi.

#include <iostream>
using namespace std;

int main() {
    int seviye = 3;

    cout << "Ödüllerin:" << endl;
    switch (seviye) {
        case 3:
            cout << "- Altın kupa" << endl;
            [[fallthrough]];  // Bilerek düşürüyorum
        case 2:
            cout << "- Gümüş rozet" << endl;
            [[fallthrough]];  // Bilerek düşürüyorum
        case 1:
            cout << "- Bronz madalya" << endl;
            break;
        default:
            cout << "- Katılım belgesi" << endl;
            break;
    }

    return 0;
}

Seviye 3 olan oyuncu üç ödülün hepsini alır, seviye 2 olan ikisini, seviye 1 olan sadece bronz madalyayı alır. [[fallthrough]] derleyiciye "bu bilerek yapılmış, uyarma" der.

💡 İpucu: [[fallthrough]] kullanımı ender olmalı. Çoğu durumda fall-through kafa karıştırır. Ama ödül sistemi, log seviyeleri gibi kümülatif durumlarda mantıklı olabilir.


switch ile enum Kullanımı

switch en güzel enum'larla kullanılır. Enum değerleri tam sayı sabitleri olduğu için switch ile mükemmel uyum sağlar.

#include <iostream>
using namespace std;

enum class Renk {
    Kirmizi,
    Yesil,
    Mavi,
    Sari
};

int main() {
    Renk secilen = Renk::Yesil;

    switch (secilen) {
        case Renk::Kirmizi:
            cout << "Dur!" << endl;
            break;
        case Renk::Yesil:
            cout << "Geç!" << endl;
            break;
        case Renk::Mavi:
            cout << "Bilgi" << endl;
            break;
        case Renk::Sari:
            cout << "Dikkat!" << endl;
            break;
    }

    return 0;
}

enum class (scoped enum) kullandığında, derleyici tüm enum değerlerini case olarak yazıp yazmadığını kontrol edebilir. Eğer bir değeri atlarsan uyarı verir — bu çok değerli bir güvenlik ağı.

// Derleyici uyarısı: Renk::Sari ele alınmamış!
switch (secilen) {
    case Renk::Kirmizi: /* ... */ break;
    case Renk::Yesil:   /* ... */ break;
    case Renk::Mavi:    /* ... */ break;
    // Sari yok — derleyici uyarır (eğer -Wall açıksa)
}

Bu yüzden enum ile switch kullanırken default yazmamak bazen daha iyi olabilir — böylece yeni bir enum değeri eklendiğinde derleyici seni uyarır ve unuttuğun yeri bulursun.


switch vs if-else if — Hangisi Ne Zaman?

DurumTercih
Bir değişkeni birçok sabit değerle karşılaştırmaswitch
Aralık kontrolü (x > 10 && x < 50)if-else if
String karşılaştırmasıif-else if
Karmaşık koşullar (a > b && c != d)if-else if
Enum değerleri üzerinde dallanmaswitch
2-3 basit koşulif-else (daha kısa)

Genel kural: Bir değişkeni belirli sabit değerlerle karşılaştırıyorsan switch kullan, karmaşık mantıksal ifadeler gerekiyorsa if-else if kullan.


Pratik Örnek — Basit Hesap Makinesi

#include <iostream>
using namespace std;

int main() {
    double sayi1, sayi2;
    char islem;

    cout << "İlk sayı: ";
    cin >> sayi1;
    cout << "İşlem (+, -, *, /): ";
    cin >> islem;
    cout << "İkinci sayı: ";
    cin >> sayi2;

    switch (islem) {
        case '+':
            cout << "Sonuç: " << sayi1 + sayi2 << endl;
            break;
        case '-':
            cout << "Sonuç: " << sayi1 - sayi2 << endl;
            break;
        case '*':
            cout << "Sonuç: " << sayi1 * sayi2 << endl;
            break;
        case '/':
            if (sayi2 != 0) {
                cout << "Sonuç: " << sayi1 / sayi2 << endl;
            } else {
                cout << "Hata: Sıfıra bölme!" << endl;
            }
            break;
        default:
            cout << "Geçersiz işlem!" << endl;
            break;
    }

    return 0;
}

Bu örnekte char tipini switch ile kullandık. Her işlem karakteri bir case'e karşılık geliyor. Bölme işleminde sıfıra bölme kontrolünü if ile yaptık — switch içinde if kullanmakta hiçbir sorun yok.


switch İçinde Değişken Tanımlama

switch-case içinde değişken tanımlarken dikkatli olmak gerekir. Bir case'de tanımlanan değişken, teorik olarak diğer case'lerden de erişilebilir — bu da karışıklık yaratır.

// PROBLEM — derleme hatası verebilir
switch (x) {
    case 1:
        int y = 10;  // y burada tanımlanıyor
        cout << y << endl;
        break;
    case 2:
        cout << y << endl;  // y'ye erişim belirsiz!
        break;
}

// ÇÖZÜM — süslü parantez ile scope oluştur
switch (x) {
    case 1: {
        int y = 10;
        cout << y << endl;
        break;
    }
    case 2: {
        int z = 20;
        cout << z << endl;
        break;
    }
}

Her case'i süslü parantez içine almak iyi bir alışkanlıktır. Böylece her case kendi scope'una sahip olur ve değişken çakışması olmaz.


Özet

  • switch bir ifadeyi birden fazla sabit değerle karşılaştırır — tam sayı ve enum tipleri desteklenir, string desteklenmez

  • break her case'in sonunda olmalıdır — yoksa fall-through gerçekleşir ve bir sonraki case'in kodu da çalışır

  • default hiçbir case eşleşmediğinde çalışır — her zaman eklemek iyi bir alışkanlıktır

  • [[fallthrough]] (C++17) attribute'u bilinçli fall-through'u derleyiciye bildirir ve uyarıyı bastırır

  • enum class ile switch kullanımı en güçlü kombinasyondur — derleyici eksik case'leri yakalar

  • Karmaşık koşullar, aralık kontrolü veya string karşılaştırması gerekiyorsa if-else if tercih et