Input Validation, Stream States ve stringstream
Programın dış dünyayla temas ettiği her nokta bir güvenlik kapısıdır. Kullanıcı klavyeden bir sayı girmeli — ama "abc" yazar. Bir dosyadan veri okuyorsun — ama format beklediğin gibi değil. Bir string'i sayıya çevirmen gerekiyor — ama string boş.
Bunu bir havaalanı güvenlik kontrolüne benzetebilirsin. Yolcuların (verinin) terminale (programına) girmeden önce kontrol edilmesi gerekir. Pasaport geçerli mi? Bagajda yasak madde var mı? Bilet doğru kapıya mı? Eğer bu kontrolleri yapmazsan, uçak kalktıktan sonra sorun çıkar — ve o noktada müdahale etmek çok daha zor.
Bu derste cin'in hata durumlarını, stream state'leri, güvenli girdi okuma kalıplarını, getline inceliklerini ve stringstream ile string-sayı dönüşümlerini detaylıca işleyeceğiz.
cin ve Stream State'leri
Stream Nedir?
C++'ta cin, cout, dosya akışları — hepsi "stream" (akış) kavramının örnekleridir. Bir stream, veri kaynağı ile programın arasında akan bir nehir gibidir. Bu nehrin durumu her an sorgulanabilir: sorunsuz mu akıyor, tıkandı mı, kurudu mu?
Her stream'in dört adet durum bayrağı (state flag) vardır:
| Flag | Anlamı | Ne Zaman Set Edilir? |
|---|---|---|
goodbit | Her şey yolunda | Hata yok, okuma başarılı |
failbit | Mantıksal hata | Sayı bekliyorken harf girildi, format uyuşmazlığı |
badbit | Ciddi hata | Akışın kendisi bozuldu (nadiren olur) |
eofbit | Dosya sonu | Veri kaynağı tükendi (EOF — End of File) |
Bu flag'leri kontrol etmek için stream'in üye fonksiyonlarını kullanırsın:
#include <iostream>
int main() {
int sayi;
std::cout << "Bir sayi girin: ";
std::cin >> sayi;
std::cout << "good: " << std::cin.good() << std::endl; // her sey OK mi?
std::cout << "fail: " << std::cin.fail() << std::endl; // format hatasi mi?
std::cout << "bad: " << std::cin.bad() << std::endl; // ciddi hata mi?
std::cout << "eof: " << std::cin.eof() << std::endl; // dosya sonu mu?
return 0;
}Eğer kullanıcı 42 girerse: good=1, fail=0, bad=0, eof=0. Her şey yolunda.
Eğer kullanıcı abc girerse: good=0, fail=1, bad=0, eof=0. Sayı bekliyorduk, harf geldi — mantıksal hata.
Sayı Bekliyorken Harf Girilince Ne Olur?
Bu, C++ programlamanın en klasik sorunlarından biri. Detaylı olarak ne olduğunu görelim:
cin >> sayiçalışır ve input buffer'dan veri okumaya çalışır.Buffer'da
abc\nvar (kullanıcının girdiği).cin,akarakterini görür ve "bu bir sayı değil" der.failbitset edilir.sayideğişkeni değişmez — eski değeri (tanımsız veya önceki değer) kalır.Kritik:
abc\nbuffer'da kalır. Kimse onu oradan almadı.Bir sonraki
cin >>çağrısı da başarısız olur — çünkü hemfailbithâlâ set, hemabchâlâ buffer'da.
İşte bu yüzden programlar sonsuz döngüye girer. cin sürekli aynı geçersiz veriyi okumaya çalışır, sürekli başarısız olur, ve kullanıcıya tekrar sorma şansı vermez.
#include <iostream>
int main() {
int sayi;
// TEHLIKE: Sonsuz döngü riski!
// Kullanıcı harf girerse, cin sürekli başarısız olur
// ve bu döngü asla bitmez
for (int i = 0; i < 3; ++i) {
std::cout << "Sayi girin: ";
std::cin >> sayi;
if (std::cin.fail()) {
std::cout << "HATA: fail durumunda!" << std::endl;
// Burada bir şey yapmazsak, sonraki okumalar da başarısız olur
} else {
std::cout << "Okunan: " << sayi << std::endl;
}
}
return 0;
}Kullanıcı abc girerse, üç iterasyon da "HATA" basar — çünkü buffer temizlenmedi.
cin.clear() + cin.ignore() Pattern'i
Kurtarma Operasyonu
Stream'in hata durumundan kurtulması için iki adımlı bir operasyon gerekir. Bu iki adım her zaman birlikte kullanılır — birini unutmak sorunu çözmez.
Adım 1: `cin.clear()` — Hata bayraklarını sıfırla. Bu, stream'e "tamam, hata oldu ama şimdi tekrar çalışmaya hazırsın" demektir. Ama dikkat: buffer'daki çöp veri hâlâ orada!
Adım 2: `cin.ignore(...)` — Buffer'daki kalan veriyi at. Genellikle satır sonuna (\n) kadar her şeyi silmek istersin.
#include <iostream>
#include <limits> // numeric_limits için
int main() {
int sayi;
std::cout << "Bir sayi girin: ";
std::cin >> sayi;
if (std::cin.fail()) {
std::cout << "Gecersiz girdi!" << std::endl;
// Adim 1: Hata flag'lerini temizle
std::cin.clear();
// Adim 2: Buffer'daki çöpü at
// numeric_limits<streamsize>::max() = "mümkün olan en büyük sayı"
// '\n' = satır sonuna kadar at
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// Şimdi tekrar okuma yapabiliriz
std::cout << "Tekrar deneyin: ";
std::cin >> sayi;
if (!std::cin.fail()) {
std::cout << "Bu sefer oldu: " << sayi << std::endl;
}
} else {
std::cout << "Okunan: " << sayi << std::endl;
}
return 0;
}numeric_limits<streamsize>::max() ne yapıyor? cin.ignore(n, delim) fonksiyonu "en fazla n karakter at veya delim karakterini görene kadar at" der. Biz n yerine mümkün olan en büyük sayıyı veriyoruz, yani "satır sonuna kadar ne kadar çöp varsa hepsini at" diyoruz.
⚠️ Dikkat:
cin.clear()olmadancin.ignore()çağırırsan,ignoreda başarısız olur — çünkü stream hâlâ hata durumunda ve hiçbir okuma/atlama işlemi çalışmaz. Her zaman önceclear(), sonraignore().
Güvenli Sayı Okuma Döngüsü
Sağlam Girdi Okuma
Gerçek programlarda kullanıcıdan güvenli bir şekilde sayı okumanın standart kalıbı şudur:
#include <iostream>
#include <limits>
int main() {
int sayi;
std::cout << "Bir tam sayi girin: ";
while (!(std::cin >> sayi)) {
std::cout << "Gecersiz! Lutfen bir sayi girin: ";
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
std::cout << "Girdiginiz sayi: " << sayi << std::endl;
return 0;
}Bu kalıbı satır satır açıklayalım:
cin >> sayiifadesi, başarılıysa stream'in kendisini döndürür — ve stream boolean'a dönüştürüldüğündetrueolur.Başarısızsa (harf girildi mesela),
falseolur.!(cin >> sayi)→ "okuma başarısız mı?" demek.Başarısızsa: hata mesajı yaz, flag temizle, buffer temizle, döngü başa dön.
Başarılıysa: döngüden çık,
sayi'da geçerli bir değer var.
Aralık Kontrolü Ekleyelim
Sadece sayı olması yetmez — genellikle belirli bir aralıkta olmasını da istersin:
#include <iostream>
#include <limits>
int guvenliSayiOku(int min, int max, const std::string& mesaj) {
int sayi;
while (true) {
std::cout << mesaj;
if (std::cin >> sayi) {
// Okuma başarılı, aralık kontrolü yap
if (sayi >= min && sayi <= max) {
return sayi; // her şey tamam
}
std::cout << "Sayi " << min << "-" << max
<< " araliginda olmali!" << std::endl;
} else {
// Okuma başarısız, temizle
std::cout << "Gecersiz girdi!" << std::endl;
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
}
int main() {
int yas = guvenliSayiOku(0, 150, "Yasinizi girin (0-150): ");
std::cout << "Yasiniz: " << yas << std::endl;
int puan = guvenliSayiOku(0, 100, "Puaninizi girin (0-100): ");
std::cout << "Puaniniz: " << puan << std::endl;
return 0;
}Bu guvenliSayiOku fonksiyonunu bir kere yazarsın, her yerde kullanırsın. Kullanıcı ne girerse girsin — harf, özel karakter, aralık dışı sayı — program çökmez. Profesyonel bir dokunuş.
getline İncelikleri
cin >> Sonrası getline Sorunu
Bu, C++ ile uğraşan herkesin er ya da geç çarptığı bir duvar. cin >> ile bir sayı okuduktan sonra getline kullanırsan, getline boş bir string okur ve atlar. Neden?
#include <iostream>
#include <string>
int main() {
int yas;
std::string isim;
std::cout << "Yasiniz: ";
std::cin >> yas; // Kullanıcı "25\n" girer
// cin "25"yi okur, "\n" buffer'da KALIR
std::cout << "Isminiz: ";
std::getline(std::cin, isim); // "\n"yi okur ve boş string döner!
std::cout << "Yas: " << yas << ", Isim: '" << isim << "'" << std::endl;
// Çıktı: Yas: 25, Isim: '' ← isim boş!
return 0;
}Sorun şu: cin >> yas sayıyı okur ama satır sonu karakterini (\n) buffer'da bırakır. getline ise satır sonuna kadar okur — ve hemen orada bir \n bulur, "tamam, satır bitti" der ve boş string döndürür.
Çözüm: Araya cin.ignore() Koy
#include <iostream>
#include <string>
#include <limits>
int main() {
int yas;
std::string isim;
std::cout << "Yasiniz: ";
std::cin >> yas;
// Buffer'daki kalan \n karakterini temizle
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "Isminiz: ";
std::getline(std::cin, isim); // Artık düzgün çalışır
std::cout << "Yas: " << yas << ", Isim: '" << isim << "'" << std::endl;
// Çıktı: Yas: 25, Isim: 'Ahmet Yilmaz' ✓
return 0;
}💡 İpucu: Basit bir kural:
cin >>ile okuma yaptıktan sonragetlinekullanacaksan, araya mutlakacin.ignore()koy. Bu kadar. Bu kuralı ezberle ve her zaman uygula.
Custom Delimiter ile getline
getline'ın üçüncü parametresi ile satır sonu yerine farklı bir ayırıcı (delimiter) belirleyebilirsin:
#include <iostream>
#include <string>
int main() {
std::string parca;
std::cout << "Virgülle ayrılmış isimler girin (örn: Ali,Veli,Ayse):" << std::endl;
// Virgülü delimiter olarak kullan
// Kullanıcı: Ali,Veli,Ayse\n
std::getline(std::cin, parca, ','); // parca = "Ali"
std::cout << "1: " << parca << std::endl;
std::getline(std::cin, parca, ','); // parca = "Veli"
std::cout << "2: " << parca << std::endl;
std::getline(std::cin, parca); // parca = "Ayse" (varsayılan \n)
std::cout << "3: " << parca << std::endl;
return 0;
}Custom delimiter çoğu durumda doğrudan getline ile kullanılmaz — genellikle stringstream ile birlikte kullanılır. Birazdan o kısma geleceğiz.
stringstream: String ile Stream Arasında Köprü
Nedir?
stringstream, bir string'i tıpkı cin veya cout gibi kullanmanı sağlar. <sstream> header'ından gelir. Üç çeşidi var:
`istringstream` — String'den okuma (input). Tıpkı
cingibi, ama kaynak klavye değil, bir string.`ostringstream` — String'e yazma (output). Tıpkı
coutgibi, ama hedef ekran değil, bir string.`stringstream` — Her ikisi birden (input + output).
String'den Sayı Çıkarma (istringstream)
#include <iostream>
#include <sstream>
#include <string>
int main() {
std::string veri = "42 3.14 Merhaba";
std::istringstream akis(veri);
int tamSayi;
double ondalik;
std::string kelime;
akis >> tamSayi >> ondalik >> kelime;
std::cout << "Tam sayi: " << tamSayi << std::endl; // 42
std::cout << "Ondalik: " << ondalik << std::endl; // 3.14
std::cout << "Kelime: " << kelime << std::endl; // Merhaba
return 0;
}istringstream, tıpkı cin gibi boşlukları (whitespace) ayırıcı olarak kullanır ve sırayla okur. cin'den farkı: veri kaynağı klavye yerine bir string. Bu özellik, özellikle dosyadan okunan satırları parse ederken çok işe yarar.
Sayıdan String Oluşturma (ostringstream)
#include <iostream>
#include <sstream>
#include <string>
#include <iomanip>
int main() {
std::ostringstream akis;
int gun = 20, ay = 2, yil = 2026;
double sicaklik = 23.567;
akis << std::setfill('0');
akis << std::setw(2) << gun << "/"
<< std::setw(2) << ay << "/"
<< yil;
std::string tarih = akis.str(); // "20/02/2026"
std::cout << "Tarih: " << tarih << std::endl;
// Yeni bir akış oluştur ya da str("") ile sıfırla
std::ostringstream akis2;
akis2 << std::fixed << std::setprecision(1) << sicaklik << " °C";
std::string sicaklikStr = akis2.str(); // "23.6 °C"
std::cout << "Sicaklik: " << sicaklikStr << std::endl;
return 0;
}ostringstream, formatlı string oluşturmak için harika. Özellikle << operatörü ile her türlü veriyi bir araya getirip, sonunda .str() ile string'e çevirebilirsin. C++20'de std::format gelene kadar, bu en temiz string formatlama yöntemiydi.
stoi/stod vs stringstream
C++11 ile birlikte gelen stoi, stod, stol gibi fonksiyonlar string-sayı dönüşümünü daha kolay hale getirdi. Peki ne zaman hangisini kullanmalı?
#include <iostream>
#include <sstream>
#include <string>
#include <stdexcept>
int main() {
std::string s1 = "42";
std::string s2 = "3.14";
std::string s3 = "abc";
// --- stoi/stod yaklaşımı ---
try {
int a = std::stoi(s1); // 42
double b = std::stod(s2); // 3.14
std::cout << "stoi: " << a << ", stod: " << b << std::endl;
int c = std::stoi(s3); // exception fırlatır!
} catch (const std::invalid_argument& e) {
std::cout << "stoi hatasi: " << e.what() << std::endl;
} catch (const std::out_of_range& e) {
std::cout << "stoi taşma: " << e.what() << std::endl;
}
// --- stringstream yaklaşımı ---
std::istringstream akis(s1);
int d;
if (akis >> d) {
std::cout << "stringstream: " << d << std::endl; // 42
} else {
std::cout << "stringstream: donusum basarisiz" << std::endl;
}
return 0;
}`stoi/stod` avantajları: Daha kısa ve okunabilir. Tek bir dönüşüm için ideal. Exception ile hata yönetimi.
`stringstream` avantajları: Birden fazla değeri sırayla okuyabilir. >> operatörü ile format esnekliği. Hata durumunu fail() ile kontrol edebilirsin (exception gerektirmez).
Genel kural: tek bir dönüşüm yapacaksan stoi/stod, bir satırda birden fazla değer parse edeceksen stringstream.
CSV Satırı Parse Etme
stringstream + getline kombinasyonu, CSV (Comma-Separated Values) parse etmek için biçilmiş kaftan:
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
struct Ogrenci {
std::string isim;
int yas;
double not_ort;
};
Ogrenci csvSatirParse(const std::string& satir) {
Ogrenci ogr;
std::istringstream akis(satir);
std::string temp;
// isim,yas,not_ort formatında
std::getline(akis, ogr.isim, ','); // virgüle kadar oku → isim
std::getline(akis, temp, ','); // virgüle kadar oku → yas (string)
ogr.yas = std::stoi(temp); // string → int
std::getline(akis, temp); // satır sonuna kadar oku → not (string)
ogr.not_ort = std::stod(temp); // string → double
return ogr;
}
int main() {
std::vector<std::string> satirlar = {
"Ahmet Yilmaz,21,3.45",
"Elif Kaya,20,3.78",
"Burak Demir,22,2.90"
};
std::cout << "Ogrenci Listesi:" << std::endl;
std::cout << "----------------------------" << std::endl;
for (const auto& satir : satirlar) {
Ogrenci ogr = csvSatirParse(satir);
std::cout << ogr.isim << " | Yas: " << ogr.yas
<< " | Not: " << ogr.not_ort << std::endl;
}
return 0;
}Bu pattern çok yaygın: dosyadan getline ile satır oku, istringstream'e ver, virgülle ayrılmış parçaları getline(akis, parca, ',') ile çıkar. Gerçek dünyada CSV dosyaları genellikle böyle parse edilir (tırnak içindeki virgüller gibi özel durumları saymıyorum — o zaman bir kütüphane kullan).
Stream State ile Dönüşüm Kontrolü
stringstream ile Güvenli Dönüşüm
stringstream, string'in tamamının geçerli bir sayı olup olmadığını kontrol etmek için de kullanılabilir:
#include <iostream>
#include <sstream>
#include <string>
bool stringToInt(const std::string& str, int& sonuc) {
std::istringstream akis(str);
// Sayıyı oku
if (!(akis >> sonuc)) {
return false; // okuma başarısız
}
// Geride bir şey kaldı mı kontrol et
char kalan;
if (akis >> kalan) {
return false; // "42abc" gibi — sayıdan sonra çöp var
}
return true; // temiz dönüşüm
}
int main() {
int sayi;
std::cout << std::boolalpha; // true/false yazsın
std::cout << "\"42\" -> " << stringToInt("42", sayi) << " (" << sayi << ")" << std::endl;
std::cout << "\"abc\" -> " << stringToInt("abc", sayi) << std::endl;
std::cout << "\"42abc\" -> " << stringToInt("42abc", sayi) << std::endl;
std::cout << "\"\" -> " << stringToInt("", sayi) << std::endl;
std::cout << "\" 42 \" -> " << stringToInt(" 42 ", sayi) << " (" << sayi << ")" << std::endl;
return 0;
}Bu fonksiyon, stoi'den daha titiz: stoi("42abc") başarılı olur ve 42 döndürür (gerisini görmezden gelir), ama stringToInt("42abc") false döndürür. Hangisini kullanacağın senaryoya bağlı.
Pratik Örnek: Güvenli Menü Sistemi
Tüm kavramları birleştiren bir örnek yapalım. Bu, gerçek bir programda görebileceğin tarzda bir menü sistemi:
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <limits>
#include <iomanip>
// ---- Yardımcı fonksiyonlar ----
int guvenliTamSayiOku(const std::string& mesaj, int min, int max) {
int sayi;
while (true) {
std::cout << mesaj;
if (std::cin >> sayi && sayi >= min && sayi <= max) {
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
return sayi;
}
std::cout << "Gecersiz! " << min << "-" << max
<< " arasi bir sayi girin." << std::endl;
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
double guvenliOndalikOku(const std::string& mesaj) {
double sayi;
while (true) {
std::cout << mesaj;
if (std::cin >> sayi) {
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
return sayi;
}
std::cout << "Gecersiz! Bir sayi girin." << std::endl;
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
std::string guvenliStringOku(const std::string& mesaj) {
std::string girdi;
while (true) {
std::cout << mesaj;
std::getline(std::cin, girdi);
if (!girdi.empty()) {
return girdi;
}
std::cout << "Bos girdi kabul edilmez!" << std::endl;
}
}
// ---- Öğrenci yönetimi ----
struct Ogrenci {
std::string isim;
int yas;
double not_ort;
};
void ogrenciEkle(std::vector<Ogrenci>& liste) {
Ogrenci ogr;
ogr.isim = guvenliStringOku("Ogrenci adi: ");
ogr.yas = guvenliTamSayiOku("Yas (15-65): ", 15, 65);
ogr.not_ort = guvenliOndalikOku("Not ortalamasi: ");
liste.push_back(ogr);
std::cout << "Ogrenci eklendi!" << std::endl;
}
void listeGoster(const std::vector<Ogrenci>& liste) {
if (liste.empty()) {
std::cout << "Liste bos." << std::endl;
return;
}
std::cout << std::left << std::setw(20) << "Isim"
<< std::setw(8) << "Yas"
<< std::setw(10) << "Not Ort." << std::endl;
std::cout << std::string(38, '-') << std::endl;
for (const auto& ogr : liste) {
std::cout << std::left << std::setw(20) << ogr.isim
<< std::setw(8) << ogr.yas
<< std::fixed << std::setprecision(2) << ogr.not_ort
<< std::endl;
}
}
void csvAktar(const std::vector<Ogrenci>& liste) {
if (liste.empty()) {
std::cout << "Aktarilacak veri yok." << std::endl;
return;
}
std::ostringstream csv;
csv << "isim,yas,not_ortalamasi" << std::endl;
for (const auto& ogr : liste) {
csv << ogr.isim << "," << ogr.yas << ","
<< std::fixed << std::setprecision(2) << ogr.not_ort
<< std::endl;
}
std::cout << "\n--- CSV Ciktisi ---" << std::endl;
std::cout << csv.str();
std::cout << "--- Bitti ---" << std::endl;
}
void csvIceAktar(std::vector<Ogrenci>& liste) {
std::cout << "CSV satirlari girin (bos satir ile bitirin):" << std::endl;
std::cout << "Format: isim,yas,not_ort" << std::endl;
std::string satir;
int eklenen = 0;
while (std::getline(std::cin, satir) && !satir.empty()) {
std::istringstream akis(satir);
Ogrenci ogr;
std::string temp;
if (std::getline(akis, ogr.isim, ',') &&
std::getline(akis, temp, ',')) {
try {
ogr.yas = std::stoi(temp);
std::getline(akis, temp);
ogr.not_ort = std::stod(temp);
liste.push_back(ogr);
eklenen++;
} catch (...) {
std::cout << " Hatali satir: " << satir << std::endl;
}
} else {
std::cout << " Hatali format: " << satir << std::endl;
}
}
std::cout << eklenen << " ogrenci eklendi." << std::endl;
}
// ---- Ana program ----
int main() {
std::vector<Ogrenci> ogrenciler;
while (true) {
std::cout << "\n==== Ogrenci Yonetim Sistemi ====" << std::endl;
std::cout << "1. Ogrenci Ekle" << std::endl;
std::cout << "2. Listeyi Goster" << std::endl;
std::cout << "3. CSV Olarak Aktar" << std::endl;
std::cout << "4. CSV'den Ic Aktar" << std::endl;
std::cout << "5. Cikis" << std::endl;
int secim = guvenliTamSayiOku("Seciminiz (1-5): ", 1, 5);
switch (secim) {
case 1: ogrenciEkle(ogrenciler); break;
case 2: listeGoster(ogrenciler); break;
case 3: csvAktar(ogrenciler); break;
case 4: csvIceAktar(ogrenciler); break;
case 5:
std::cout << "Cikiliyor..." << std::endl;
return 0;
}
}
}Bu örnekte neredeyse bu dersin tüm konuları bir arada:
cin.clear()+cin.ignore()ile güvenli sayı okumacin >>sonrasıgetlineuyumu (ignoreile)ostringstreamile CSV formatında string oluşturmaistringstream+getline(akis, parca, ',')ile CSV parse etmestoi/stodile string-sayı dönüşümü ve exception handlingStream state kontrolü ile hata yönetimi
⚠️ Dikkat: Gerçek projelerde kullanıcı girdisi doğrulama sadece ilk savunma hattıdır. Veritabanına yazılan, ağ üzerinden gönderilen veya dosyaya kaydedilen her veri ek doğrulamalardan geçmelidir. "Kullanıcıya güvenme" prensibi güvenliğin temelidir.
Ekstra: Yaygın Hatalar ve Çözümleri
Hata 1: ignore'u Unutmak
// YANLIS — cin >> sonrası getline'a geçerken ignore unutulmuş
int yas;
std::string isim;
std::cin >> yas;
std::getline(std::cin, isim); // boş string okur!
// DOGRU
std::cin >> yas;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::getline(std::cin, isim); // düzgün çalışırHata 2: clear'sız ignore
// YANLIS — fail durumunda ignore çalışmaz
if (std::cin.fail()) {
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // çalışmaz!
// clear olmadan stream hâlâ hata durumunda
}
// DOGRU
if (std::cin.fail()) {
std::cin.clear(); // önce flag temizle
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // sonra buffer temizle
}Hata 3: stoi Hatasını Yakalamamak
// YANLIS — exception yakalanmazsa program çöker
std::string girdi = "abc";
int sayi = std::stoi(girdi); // terminate çağrılır!
// DOGRU
try {
int sayi = std::stoi(girdi);
std::cout << "Sayi: " << sayi << std::endl;
} catch (const std::invalid_argument&) {
std::cout << "Gecersiz sayi formati" << std::endl;
} catch (const std::out_of_range&) {
std::cout << "Sayi cok buyuk/kucuk" << std::endl;
}Özet
Stream state flags (
goodbit,failbit,badbit,eofbit) stream'in durumunu bildirir. Sayı bekliyorken harf girildiğindefailbitset edilir ve stream kilitlenir.`cin.clear()` + `cin.ignore()` ikilisi stream'i kurtarmanın standart yoludur. Önce
clear()ile flag'leri sıfırla, sonraignore()ile buffer'daki çöpü at. İkisi her zaman birlikte kullanılır.Güvenli okuma döngüsü
while (!(cin >> sayi))kalıbı ile yazılır. Kullanıcı geçerli bir değer girene kadar tekrar sorar — program asla çökmez.`cin >>` sonrası `getline` kullanacaksan araya
cin.ignore()koy. Aksi halde buffer'da kalan\nyüzündengetlineboş string okur.`stringstream` string ile stream dünyası arasında köprü kurar:
istringstreamstring'den okumak,ostringstreamstring oluşturmak için. CSV parse etme, formatlı string üretme gibi işlerde vazgeçilmez.`stoi`/`stod` tekil dönüşümler için kısa ve pratiktir, ama hata durumunda exception fırlatır —
try-catchile sar. Birden fazla değer parse edeceksenstringstreamdaha uygun.
AI Asistan
Sorularını yanıtlamaya hazır