Kullanıcı Aletleri

Site Aletleri


tr:cs:cpp:common:basicio

Girdi ve Çıktı Akışları

Girdi ve çıktı işlevselliği C++ dilinin bir parçası olarak tanımlanmaz, bunun yerine C++ standart kütüphanesi aracılığıyla sağlanır.

Birçok C++ kitabı bu işlevselliği temel dilin parçası olmadığından anlatmaz. Ancak bu işlevselliğin C++'ın bir parçası olmaması, C++'ın bu işlevselliği desteklemediği anlamına gelmez. C++'ın bu işlevselliği desteklemesi için C++ standart kütüphanesinin bir parçası olan <iostream> başlık dosyası kullanılır.

Akış Nedir?

En basit haliyle, C++'da girdi ve çıktı, akışlarla gerçekleştirilir. Bir akış sırayla erişilebilen bir bayt dizisidir. Zaman içinde, bir akış potansiyel olarak sınırsız miktarda veri üretebilir veya tüketebilir.

Genellikle 2 tür akış ile ilgileniriz.

Girdi akışları klavye, dosya veya ağ gibi bir veri üreticisinden gelen girdileri tutmak için kullanılır. Örnek olarak kullanıcı, program herhangi bir girdi beklemezken bir tuşa basabilir. Kullanıcının bu eylemini tamamen görmezden gelmek yerine C++ bu girdileri bir akış içerisinde tutar, veriler bir giriş akışına konur ve burada program hazır olana kadar bekler.

Çıktı akışları monitör, dosya veya yazıcı gibi belirli bir veri tüketicisinin çıktısını tutmak için kullanılır. Bir çıktı aygıtına veri yazarken, aygıt henüz bu veriyi kabul etmeye hazır olmayabilir. Örnek olarak, program çıktı akışına veri yazdığında yazıcı hala ısınıyor olabilir. Veriler yazıcı tarafından tüketilmeye başlayana kadar çıktı akışında kalacaktır.

Elbette bazı araçlar, girdi ve çıktı kaynağı olabilirler. Örnek olarka dosyalar ve ağlar.

Programcının öğrenmesi gereken sadece bu akışları nasıl kontrol edeceğidir. Arkaplanda akışların cihazlarla ve dosya, ağ gibi kaynaklarla nasıl etkileşime girdiğini bilmesine gerek yoktur. Bu kısım ortama ve işletim sistemine bağlıdır.

istream sınıfı, giriş akışlarıyla uğraşırken kullanılan birincil sınıftır. Giriş akışlarında, değerleri akıştan çıkarmak için çıkarma operatörü (») kullanılır.

ostream sınıfı, çıktı akışlarıyla uğraşırken kullanılan birincil sınıftır. Çıktı akışlarında, değerleri akışa yerleştirmek için ekleme operatörü («) kullanılır.

iostream sınıfı hem girdi hem de çıktı işleyebilir ve çift yönlü girdi/çıktıya izin verir. Hem istream hem de ostream, ios adlı sınıftan türetilmiştir

Standart Akışlar

Standart akış, bir bilgisayar programına çevresi tarafından sağlanan önceden bağlanmış bir akıştır. C++, kullanımınız için önceden tanımlanmış dört standart akış nesnesi ile birlikte gelir.

  • cin – standart girdiye (tipik olarak klavye) bağlı bir istream nesnesi
  • cout – standart çıktıya (tipik olarak monitöre) bağlı bir ostream nesnesi
  • cerr – standart hataya (tipik olarak monitöre) bağlı, tamponlanmamış çıktı sağlayan bir ostream nesnesi
  • clog – standart hataya (tipik olarak monitöre) bağlı, tamponlanmış çıktı sağlayan bir ostream nesnesi

Tamponlanmamış çıktı genellikle hemen işlenirken, tamponlanmış çıktı genellikle bir blok olarak saklanır ve yazılır. Clog çok sık kullanılmadığından, genellikle standart akışlar listesinden çıkarılır.

istream ile girdi

iostream kütüphanesi çok geniş ve çok çeşitli girdi işlevselliği sağlar. Burada sadece giriş için gerekli bilgilere yer verilmiştir. Çok fazla alt istream fonksiyonu bulunmaktadır. Detaylar için basic_istream adresine bakabilirsiniz.

Çıkarma operatörü

Bir giriş akışından bilgi okumak için çıkarma operatörünü (») kullanabiliriz.

C++ tüm temel veri tipleri için öntanımlı çıkarma operatörüne sahiptir. Ayrıca kendi sınıfsal tiplerimiz için bu operatörü nasıl aşırı yükleyebileceğimizi görmüştük.

Çıkarma operatörü kullanılırken dikkat edilmesi gereken. Girdinin bizim tampon nesnemizi aşması durumudur.

char buf[10];
std::cin >> buf;

Örnek olarak yukarıdaki kodda, eğer kullanıcı 10'dan fazla karakter girerse ne olur? Buffer overflow adı verilen bir durum ortaya çıkar ve tanımsız davranışa sebep olabilir.

Bu gibi durumların önüne geçmek için manipülatör kullanabiliriz.

Manipülatör, çıkarma (») veya ekleme («) operatörleri ile uygulandığında bir akışı değiştirmek için kullanılan bir nesnedir.

#include <iomanip>
char buf[10];
std::cin >> std::setw(10) >> buf;

Yukarıdaki örnekte setw() manipülatörü ile çıkarma operatörünün maksimum 91) karakter almasını sağladık. Diğer kalan girdiler bir sonraki çıkarma işlemine kadar akışta kalacaktır.

Bir diğer bilinmesi gereken ise, çıkarma operatörünün boşlukları göz ardı etmesidir. Bunun önüne geçmek için gene istream sınıfında bulunan get() fonksiyonunu kullanabiliriz.

    char ch;
    while (std::cin.get(ch))
        std::cout << ch;

Aynı şekilde get() fonksiyonunun stringler içinde alternatifi bulunmaktadır. Aşağıdaki örnek, kullanıcıdan 10 karakter uzunluğunda bir string alır. Aynı şekilde kalanlar akışta kalır.

    char strBuf[11];
    std::cin.get(strBuf, 11);
    std::cout << strBuf << '\n';

Bu verilen iki get() örneğinde bilinmesi gereken önemli bir nokta var. Bu fonksiyon \n karakterini okumaz. Bu karaktere denk geldiğinde okuma işlemi bitti sayar. Bu durum için getline() fonksiyonunu kullanabiliriz.

getline() fonksiyonuda aynı şekilde çalışır ek olarak \n karakterini de okur.

    char strBuf[11];
    // 10 karaktere kadar okuma
    std::cin.getline(strBuf, 11);
    std::cout << strBuf << '\n';
 
    // 10 karaktere kadar daha okuyun
    std::cin.getline(strBuf, 11);
    std::cout << strBuf << '\n';

ostream ve ios ile çıktı

Ekleme Operatörü

Ekleme operatörü («), bir çıktı akışına bilgi koymak için kullanılır. C++, tüm yerleşik veri türleri için önceden tanımlanmış ekleme işlemlerine sahiptir

Biçimlendirme

Biçimlendirme değiştirmenin iki yolu vardır bayraklar ve manipülatörler. Bayrakları açılıp kapatılabilen boolean değişkenler olarak düşünebilirsiniz. Manipülatörler, bir akışa yerleştirilen ve nesnelerin giriş ve çıkış şeklini etkileyen nesnelerdir.

Bayrakları değiştirmek için setf() ve unsetf() fonksiyonlarını kullanabiliriz. Örnek olarak, matematikte olduğu gibi c++'da da pozitif sayıların önünde bulunan + işaretini varsayılan olarak yazmayız. std::ios::showpos bayrağı ile yazdırmayı sağlayabiliriz.

std::cout.setf(std::ios::showpos); // std::ios::showpos bayrağını açtık.
std::cout << 27 << '\n';

Birden fazla bayrağı aktifleştirmek için | oparetörünü kullanabiliriz.

std::cout.setf(std::ios::showpos | std::ios::showpoint); // std::ios::showpos ve std::ios::showpoint bayrağını açtık.
std::cout << 27 << '\n';

Aynı şekilde bir bayrağı kapatmak içinde unsetf() fonksiyonunu kullanabiliriz.

std::cout.setf(std::ios::showpos); // std::ios::showpos bayrağını açın
std::cout << 27 << '\n';
std::cout.unsetf(std::ios::showpos); // std::ios::showpos bayrağını kapatın
std::cout << 28 << '\n';

Bayraklar hakkında bilmemiz gereken bir diğer nokta bazı bayraklar belirli gruplara aitlerdir. Bu gruplara format grubu denir ve format grupları benzer işleve sahip bayrakları bir arada tutar. setf() ve unsetf() fonksiyonları bu gruplar halinde bulunan bayrakları işlemede beklendiği kadar akıllı değillerdir.

Örnek olarak basefield adındaki format grubu oct, dec ve hex bayraklarına sahiptir ki bu bayraklar tamsayısal çıktının hangi tabanda işleneceğini belirler. Varsayılan olarak dec bayrağı açıktır.

Biz eğer hex bayrağını açarak hexadecimal olarak yazdırmak istersek. Ayrı olarak dec bayrağını kapatmamız gerekir. Çünkü setf() fonksiyonu biz hex bayrağını açtığımızda akıllılık ederek dec bayrağını kapatmaz. Sonuç olarak dec bayrağı, hex bayrağına göre işlem önceliğine sahip olduğundan kodumuz beklenen şekilde çalışmayacaktır.

std::cout.setf(std::ios::hex); // hex çıkışını açmayı denedik.
std::cout << 27 << '\n';

Kodu bize;

27

Sonucunu verecektir. Çünkü dec bayrağı açık olduğundan 27 sayısını ondalık olarak işleyecektir. Asıl yapmamız gereken ise;

std::cout.unsetf(std::ios::dec); // dec çıkışını kapattık.
std::cout.setf(std::ios::hex); // hex çıkışını açmayı denedik.
std::cout << 27 << '\n';

Bir diğer kolaylık ise setf() fonksiyonunun ikinci parametresidir. İkinci parametreye grubun adını yazarak açtığımız bayrak dışında o gruptaki diğer bayrakları kapatabiliriz.

std::cout.setf(std::ios::hex, std::ios::basefield);
std::cout << 27 << '\n';

Bu şekilde çıktıyı biçimlendirme pek yaygın değildir. C++ bize bize ikinci bir biçimlendirme yöntemi sunar. Bu yöntem manipülatörlerdir. Manipülatörlerin iyi yanı ise ayarlayacağımız bayrağa göre uygun diğer bayrakları kapatmayı akıl edebilmesidir.

std::cout << std::hex << 27 << '\n'; // 27'yi onaltılık olarak yazdır
std::cout << 28 << '\n'; // Hala hex'teyiz.
std::cout << std::dec << 29 << '\n'; // ondalık sisteme geri döndük

Yukarıdaki kod bize ;

1b
1c
29

Sonucunu verecektir.

Peki neden manipülatörler kullanacaksak, bayrakları açıp kapatmayı öğrendik derseniz. Birçok seçenek genellikle manipülatörle yada bayraklarla ayarlanabilir. Ancak bazı ayarlar sadece manipülatörle yada sadece bayrakla ayarlanır. Bu yüzden ikisinide bilmek gerekir.

Diğer Biçimlendiriciler

Genel olarak karşılaşabileceğiniz bayraklar, manipülatörler ve üye fonksiyonlar aşağıda listelenmiştir.

  • Bayraklar std::ios sınıfında barınırlar.
  • Manipülatörler std:: isim alanında barınırlar.
  • Üye fonksiyonlar ise std::ostream sınıfında barınırlar.
  • std::ios::boolalpha bayrağı açıksa bool değerler true veya false olarak yazdırılır. Kapalıysa, bool değerler 1 veya 0 olarak yazdırılır. Varsayılan olarak kapalıdır.
  • std::boolalpha manipülatörü bool değerleri “true” veya “false” yazdırır
  • std::noboolalpha manipülatörü bool değerleri 0 veya 1 yazdırır (varsayılan)
std::cout << true << ' ' << false << '\n';
std::cout.setf(std::ios::boolalpha);
std::cout << true << ' ' << false << '\n';
std::cout << std::noboolalpha << true << ' ' << false << '\n';
std::cout << std::boolalpha << true << ' ' << false << '\n';
  • std::ios::showpos bayrağı açıksa pozitif sayıların önüne + koyar. Kapalıysa koymaz. Varsayılan olarak kapalıdır.
  • std::showpos manipülatörü pozitif sayıların önüne + koyar.
  • std::noshowpos manipülatörü pozitif sayıların önüne + koymaz. (varsayılan)
std::cout << 5 << '\n';
std::cout.setf(std::ios::showpos);
std::cout << 5 << '\n';
std::cout << std::noshowpos << 5 << '\n';
std::cout << std::showpos << 5 << '\n';
  • std::ios::uppercase bayrağı açıksa büyük harfler kullanılır. Varsayılan olarak kapalıdır.
  • std::uppercase manipülatörü ile büyük harfler kullanılır.
  • std::nouppercase manipülatörü ile küçük harfler kullanılır. (varsayılan)
std::cout << 123456.8 << '\n';
std::cout.setf(std::ios::uppercase);
std::cout << 123456.8 << '\n';
std::cout << std::nouppercase << 123456.8 << '\n';
std::cout << std::uppercase << 123456.8 << '\n';
  • std::ios::basefield format grubu;
    • std::ios::dec bayrağı açıksa, değerleri ondalık sistemde yazdırır. (varsayılan)
    • std::ios::hex bayrağı açıksa, değerleri onaltılık olarak yazdırır.
    • std::ios::oct bayrağı açıksa, değerleri sekizlik olarak yazdırır.
  • std::dec manipülatörü değerleri ondalık sistemde yazdırır. (varsayılan)
  • std::hex manipülatörü değerleri onaltılık olarak yazdırır.
  • std::oct manipülatörü değerleri sekizlik olarak yazdırır.
std::cout << 27 << '\n';
std::cout.setf(std::ios::dec, std::ios::basefield);
std::cout << 27 << '\n';
std::cout.setf(std::ios::oct, std::ios::basefield);
std::cout << 27 << '\n';
std::cout.setf(std::ios::hex, std::ios::basefield);
std::cout << 27 << '\n';
std::cout << std::dec << 27 << '\n';
std::cout << std::oct << 27 << '\n';
std::cout << std::hex << 27 << '\n';
  • std::ios::floatfield format grubu;
    • std::ios::fixed bayrağı açıksa, kesirli sayılar için ondalık gösterimi kullanır. (varsayılan)
    • std::ios::scientific bayrağı açıksa, kesirli sayılar için bilimsel gösterimi kullanır.
    • std::ios::showpoint bayrağı açıksa, kesirli değerler için her zaman bir ondalık nokta ve sondaki 0'ları gösterir.
    • Eğer bayrak belirtilmezse, az basamaklı sayılar için sabit, aksi takdirde bilimsel kullanılır.
  • std::fixed manipülatörü ondalık sistemi kullanır. (varsayılan)
  • std::scientific manipülatörü bilimsel gösterim kullanır.
  • std::showpoint manipülatörü kesirli değerler için ondalık noktayı ve sondaki 0'ları gösterir.
  • std::noshowpoint manipülatörü kesirli değerler için ondalık noktayı ve sondaki 0'ları göstermez.
  • std::setprecision(int) manipülatörü kesirli sayıların hassasiyetini ayarlar. (iomanip başlığında bulunur).
  • std::ios_base::precision() üye fonksiyonu, kesirli sayıların geçerli hassasiyetini döndürür.
  • std::ios_base::precision(int) üye fonksiyonu, kesirli sayıların hassasiyetini ayarlar ve eski hassasiyeti döndürür.

Sabit veya bilimsel gösterim kullanılıyorsa, kesirde kaç ondalık basamağın görüntüleneceğini hassasiyet belirler. Hassasiyet, anlamlı basamak sayısından azsa sayının yuvarlanacağını unutmayın.

std::cout << std::fixed << '\n';
std::cout << std::setprecision(3) << 123.456 << '\n';
std::cout << std::setprecision(4) << 123.456 << '\n';
std::cout << std::setprecision(5) << 123.456 << '\n';
std::cout << std::setprecision(6) << 123.456 << '\n';
std::cout << std::setprecision(7) << 123.456 << '\n';
std::cout << std::scientific << '\n';
std::cout << std::setprecision(3) << 123.456 << '\n';
std::cout << std::setprecision(4) << 123.456 << '\n';
std::cout << std::setprecision(5) << 123.456 << '\n';
std::cout << std::setprecision(6) << 123.456 << '\n';
std::cout << std::setprecision(7) << 123.456 << '\n';

Kodu bize;

123.456
123.4560
123.45600
123.456000
123.4560000

1.235e+002
1.2346e+002
1.23456e+002
1.234560e+002
1.2345600e+002

Sonucunu verecektir.

Ne sabit ne de bilimsel bir yöntem kullanılmıyorsa, kaç anlamlı basamağın görüntüleneceğini hassasiyet belirler. Yine hassasiyet anlamlı basamak sayısından az ise sayı yuvarlanacaktır.

std::cout << std::setprecision(3) << 123.456 << '\n';
std::cout << std::setprecision(4) << 123.456 << '\n';
std::cout << std::setprecision(5) << 123.456 << '\n';
std::cout << std::setprecision(6) << 123.456 << '\n';
std::cout << std::setprecision(7) << 123.456 << '\n';

Kodu bize;

123
123.5
123.46
123.456
123.456

Sonucunu verecektir.

showpoint manipülatörünü veya bayrağını kullanarak akışın bir ondalık nokta ve sondaki sıfırları yazmasını sağlayabilirsiniz.

std::cout << std::showpoint << '\n';
std::cout << std::setprecision(3) << 123.456 << '\n';
std::cout << std::setprecision(4) << 123.456 << '\n';
std::cout << std::setprecision(5) << 123.456 << '\n';
std::cout << std::setprecision(6) << 123.456 << '\n';
std::cout << std::setprecision(7) << 123.456 << '\n';

Kodu bize;

123.
123.5
123.46
123.456
123.4560

Sonucunu verecektir.

UCH Viki'den alınmıştır. https://wiki.ulascemh.com/doku.php?id=tr:cs:cpp:common:basicio Çıkarma operatörü başlığında ikinci satırda aşırı yükleme kısmına link verilecek.

1)
Bir adette sonlandırıcı için ayrılmıştır.
tr/cs/cpp/common/basicio.txt · Son değiştirilme: 2025/05/02 21:56 Değiştiren: ulascemh