← Kursa Dön
📄 Text · 10 min

break, continue ve goto

Döngüler güzeldir ama bazen döngünün tam ortasında "dur, yeter!" demek istersin. Ya da "bu turu atla, sonrakine geç" dersin. Hatta nadiren "her şeyi bırak, şuraya zıpla" demen gerekir. İşte break, continue ve goto bu üç farklı ihtiyaca cevap verir.

Bir koşu bandı düşün. break koşu bandını tamamen durdurmak, continue bir adımı atlamak ama koşmaya devam etmek, goto ise koşu bandından atlayıp odanın başka bir köşesine gitmek gibi.


break — Döngüden Çık

break ifadesi, içinde bulunduğu döngüyü anında sonlandırır. Döngünün koşulu hâlâ doğru olsa bile çıkar. Program, döngüden sonraki satırdan devam eder.

#include <iostream>
using namespace std;

int main() {
    // İlk negatif sayıyı bulunca dur
    int sayilar[] = {5, 12, 8, -3, 7, 15};

    for (int i = 0; i < 6; i++) {
        if (sayilar[i] < 0) {
            cout << "Negatif sayı bulundu: " << sayilar[i]
                 << " (indeks: " << i << ")" << endl;
            break;  // Döngüden çık
        }
        cout << "Kontrol edilen: " << sayilar[i] << endl;
    }

    cout << "Döngü bitti." << endl;
    return 0;
}

Çıktı:

Kontrol edilen: 5
Kontrol edilen: 12
Kontrol edilen: 8
Negatif sayı bulundu: -3 (indeks: 3)
Döngü bitti.

-3 bulunduğu anda break çalışır ve döngü sonlanır. 7 ve 15 hiç kontrol edilmez.

break'in Kullanım Alanları

  • Arama: Aranan elemanı bulunca döngüyü sonlandır

  • Sonsuz döngüden çıkış: while(true) içinde koşul sağlanınca break

  • Hata durumu: Beklenmeyen bir durumla karşılaşınca döngüyü kes

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

int main() {
    // Sonsuz döngü + break ile komut satırı
    string girdi;

    while (true) {
        cout << "Komut girin (q = çık): ";
        getline(cin, girdi);

        if (girdi == "q" || girdi == "quit") {
            cout << "Çıkılıyor..." << endl;
            break;
        }

        cout << "Çalıştırılıyor: " << girdi << endl;
    }

    return 0;
}

continue — Bu Turu Atla

continue ifadesi, döngünün mevcut turunu atlar ve bir sonraki tura geçer. Döngüyü sonlandırmaz — sadece o anki iterasyonun geri kalanını pas geçer.

#include <iostream>
using namespace std;

int main() {
    // Tek sayıları atla, çift sayıları yazdır
    for (int i = 1; i <= 10; i++) {
        if (i % 2 != 0) {
            continue;  // Tek sayıysa atla
        }
        cout << i << " ";
    }
    cout << endl;
    // Çıktı: 2 4 6 8 10

    return 0;
}

i tek sayı olduğunda continue çalışır, cout satırı atlanır ve döngü i++ ile bir sonraki tura geçer. Döngü durmaz, sadece o tur kısa kesilir.

for vs while'da continue Davranışı

for döngüsünde continue çalıştığında artış ifadesi (i++) yine de çalışır — çünkü artış, gövdeden bağımsızdır. Ama while döngüsünde dikkatli ol:

#include <iostream>
using namespace std;

int main() {
    // for'da sorun yok — i++ her turda çalışır
    for (int i = 0; i < 5; i++) {
        if (i == 2) continue;
        cout << i << " ";
    }
    cout << endl;
    // Çıktı: 0 1 3 4

    // while'da DİKKAT — sonsuz döngü riski!
    int j = 0;
    while (j < 5) {
        if (j == 2) {
            j++;       // Bu satırı unutursan sonsuz döngü!
            continue;
        }
        cout << j << " ";
        j++;
    }
    cout << endl;
    // Çıktı: 0 1 3 4

    return 0;
}

⚠️ Dikkat: while döngüsünde continue kullanırken sayacı artırmayı unutma! continue gövdenin geri kalanını atladığı için sayaç artışı da atlanabilir — bu sonsuz döngüye yol açar.


break vs continue — Karşılaştırma

Özellikbreakcontinue
Ne yaparDöngüyü tamamen bitirirMevcut turu atlar
Döngü devam eder miHayırEvet, sonraki turdan
KullanımArama, erken çıkışFiltreleme, atlama
#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> veriler = {3, 7, -1, 5, 0, 8, 4};

    // continue: negatif olanları atla
    cout << "Pozitif sayılar: ";
    for (auto v : veriler) {
        if (v <= 0) continue;
        cout << v << " ";
    }
    cout << endl;
    // Çıktı: Pozitif sayılar: 3 7 5 8 4

    // break: 0 görünce dur
    cout << "0'a kadar: ";
    for (auto v : veriler) {
        if (v == 0) break;
        cout << v << " ";
    }
    cout << endl;
    // Çıktı: 0'a kadar: 3 7 -1 5

    return 0;
}

goto — Etiketli Atlama

goto bir etiket (label) tanımlayıp programın akışını oraya yönlendirir. C++ dilinde var ama neredeyse hiç kullanılmaz. Sebebi basit: kodu takip edilmesi zor, bakımı imkânsız "spagetti kod"a dönüştürür.

#include <iostream>
using namespace std;

int main() {
    int i = 1;

tekrar:                        // Etiket tanımı
    cout << i << " ";
    i++;
    if (i <= 5) goto tekrar;   // Etikete atla

    cout << endl;
    // Çıktı: 1 2 3 4 5

    return 0;
}

Bu kodu for döngüsü ile yazmak çok daha temiz:

for (int i = 1; i <= 5; i++) {
    cout << i << " ";
}

Neden goto'dan Kaçınmalı?

  • Okunabilirlik: Kod akışı yukarı-aşağı sıçrar, takip etmek zorlaşır

  • Bakım: Başka birisi (veya gelecekteki sen) kodu anlayamaz

  • Yapısal bozulma: Döngü ve koşul yapılarını devre dışı bırakır

  • Bug riski: Değişken tanımlamalarını atlayabilir, tanımsız davranışa yol açabilir

⚠️ Dikkat: Modern C++ kodunda goto kullanmak ciddi bir anti-pattern'dir. Kod review'da anında reddedilir. Tek meşru kullanım yeri aşağıda açıklanıyor.

goto'nun Meşru Kullanım Yeri: İç İçe Döngüden Çıkış

gotonun kabul edilen neredeyse tek kullanım yeri, çok katlı iç içe döngülerden tek seferde çıkmaktır. break sadece en içteki döngüyü kırar — dış döngüleri kırmaz.

#include <iostream>
using namespace std;

int main() {
    // 2 boyutlu bir arama — hedefi bul ve tüm döngülerden çık
    int matris[3][3] = {
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9}
    };
    int hedef = 5;

    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            if (matris[i][j] == hedef) {
                cout << hedef << " bulundu: ["
                     << i << "][" << j << "]" << endl;
                goto bulundu;  // Her iki döngüden de çık
            }
        }
    }
    cout << "Bulunamadı." << endl;

bulundu:
    cout << "Arama tamamlandı." << endl;
    return 0;
}

Ama bu durumda bile goto yerine alternatifler var — bir sonraki bölümde onlara bakacağız.


Nested Loop'tan Çıkma Stratejileri

İç içe döngülerden çıkmak yaygın bir sorundur. break sadece en içteki döngüyü kırar. İşte birkaç strateji:

Strateji 1: Bayrak (Flag) Değişkeni

#include <iostream>
using namespace std;

int main() {
    int matris[3][3] = {
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9}
    };
    int hedef = 5;
    bool bulundu = false;

    for (int i = 0; i < 3 && !bulundu; i++) {
        for (int j = 0; j < 3 && !bulundu; j++) {
            if (matris[i][j] == hedef) {
                cout << hedef << " bulundu: ["
                     << i << "][" << j << "]" << endl;
                bulundu = true;
            }
        }
    }

    if (!bulundu) {
        cout << "Bulunamadı." << endl;
    }

    return 0;
}

Bayrak değişkeni hem iç hem dış döngünün koşulunda kontrol edilir. Elemanı bulunca bayrak true olur ve her iki döngü de durur.

Strateji 2: Fonksiyona Taşı + return

Bu genellikle en temiz çözümdür. Döngüyü bir fonksiyona koy ve return ile çık.

#include <iostream>
using namespace std;

struct Pozisyon {
    int satir, sutun;
    bool bulundu;
};

Pozisyon bul(int matris[][3], int boyut, int hedef) {
    for (int i = 0; i < boyut; i++) {
        for (int j = 0; j < 3; j++) {
            if (matris[i][j] == hedef) {
                return {i, j, true};  // Anında çık
            }
        }
    }
    return {-1, -1, false};
}

int main() {
    int matris[3][3] = {
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9}
    };

    auto sonuc = bul(matris, 3, 5);
    if (sonuc.bulundu) {
        cout << "Bulundu: [" << sonuc.satir
             << "][" << sonuc.sutun << "]" << endl;
    }

    return 0;
}

💡 İpucu: Çoğu durumda "fonksiyona taşı + return" en iyi stratejidir. Kod temiz kalır, tek sorumluluk ilkesi uygulanır ve goto veya bayrak değişkenine gerek kalmaz.

Strateji 3: Lambda ile Yerinde Çözüm (C++11+)

Ayrı bir fonksiyon yazmak istemiyorsan, lambda kullanabilirsin:

#include <iostream>
using namespace std;

int main() {
    int matris[3][3] = {
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9}
    };
    int hedef = 5;

    auto ara = [&]() {
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (matris[i][j] == hedef) {
                    cout << hedef << " bulundu: ["
                         << i << "][" << j << "]" << endl;
                    return;  // Lambda'dan çık
                }
            }
        }
        cout << "Bulunamadı." << endl;
    };

    ara();  // Lambda'yı çağır
    return 0;
}

Lambda'yı ilerideki derslerde detaylı öğreneceksin. Şimdilik bu kalıbı bilmek yeterli.


Karşılaştırma Tablosu

MekanizmaNe YaparKapsamıNe Zaman Kullan
breakDöngüyü sonlandırırEn içteki döngüArama, erken çıkış
continueMevcut turu atlarEn içteki döngüFiltreleme
gotoEtikete atlarFonksiyon geneliNeredeyse hiç (iç içe döngü hariç)
returnFonksiyondan çıkarTüm döngülerİç içe döngüden çıkma (en temiz)
BayrakKoşulu değiştirirİstediğin kadar döngüBasit iç içe yapılarda

Gerçek Dünya Örneği — Log Dosyası İşleme

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

int main() {
    vector<string> loglar = {
        "INFO: Sistem başlatıldı",
        "INFO: Kullanıcı giriş yaptı",
        "WARNING: Disk alanı azalıyor",
        "ERROR: Veritabanı bağlantısı kesildi",
        "INFO: Yeniden bağlanılıyor",
        "FATAL: Kurtarılamaz hata"
    };

    cout << "=== Hata taraması ===" << endl;

    for (const auto& log : loglar) {
        // INFO loglarını atla
        if (log.substr(0, 4) == "INFO") {
            continue;
        }

        cout << log << endl;

        // FATAL görünce taramayı durdur
        if (log.substr(0, 5) == "FATAL") {
            cout << "FATAL hata tespit edildi, tarama durduruluyor!"
                 << endl;
            break;
        }
    }

    return 0;
}

Bu örnekte continue ile INFO loglarını filtreliyor, break ile FATAL hatada taramayı durduruyoruz. İkisi birlikte güçlü bir kontrol mekanizması oluşturur.


Özet

  • break döngüyü tamamen sonlandırır — sadece en içteki döngüyü etkiler

  • continue mevcut turu atlar ve sonraki tura geçer — while'da sayaç artışını unutma

  • goto etiketli atlama yapar ama kodu spagettiye çevirir — modern C++ kodunda kullanma

  • İç içe döngüden çıkış için en temiz yol fonksiyona taşıyıp return kullanmaktır

  • Bayrak değişkeni basit iç içe yapılarda işe yarar ama kodu kalabalıklaştırabilir

  • break ve continue birlikte kullanıldığında güçlü filtreleme ve erken çıkış kalıpları oluşturur