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ıncabreakHata 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:
whiledöngüsündecontinuekullanırken sayacı artırmayı unutma!continuegö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
| Özellik | break | continue |
|---|---|---|
| Ne yapar | Döngüyü tamamen bitirir | Mevcut turu atlar |
| Döngü devam eder mi | Hayır | Evet, sonraki turdan |
| Kullanım | Arama, 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
gotokullanmak 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
gotoveya 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
| Mekanizma | Ne Yapar | Kapsamı | Ne Zaman Kullan |
|---|---|---|---|
break | Döngüyü sonlandırır | En içteki döngü | Arama, erken çıkış |
continue | Mevcut turu atlar | En içteki döngü | Filtreleme |
goto | Etikete atlar | Fonksiyon geneli | Neredeyse hiç (iç içe döngü hariç) |
return | Fonksiyondan çıkar | Tüm döngüler | İç içe döngüden çıkma (en temiz) |
| Bayrak | Koş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ı unutmagoto 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
returnkullanmaktırBayrak değişkeni basit iç içe yapılarda işe yarar ama kodu kalabalıklaştırabilir
breakvecontinuebirlikte kullanıldığında güçlü filtreleme ve erken çıkış kalıpları oluşturur
AI Asistan
Sorularını yanıtlamaya hazır