Stringstream tam olarak ne yapar?


107

Dünden beri C ++ öğrenmeye çalışıyorum ve şu belgeyi kullanıyorum: http://www.cplusplus.com/files/tutorial.pdf (sayfa 32). Belgede bir kod buldum ve çalıştırdım. Fiyat için Rs 5.5 ve miktar için bir tam sayı girmeyi denedim ve çıktı 0 idi. 5.5 ve 6'yı girmeyi denedim ve çıktı doğruydu.

// stringstreams
#include <iostream> 
#include <string> 
#include <sstream> 

using namespace std; 

int main () 
{ 
  string mystr; 
  float price = 0; 
  int quantity = 0; 

  cout << "Enter price: "; 
  getline (cin,mystr); 
  stringstream(mystr) >> price; 
  cout << "Enter quantity: "; 
  getline (cin,mystr); 
  stringstream(mystr) >> quantity; 
  cout << "Total price: " << price*quantity << endl; 
  return 0; 
}

Soru: mystring komutu tam olarak ne yapıyor? Belgeden alıntı yapmak:

"Bu örnekte, dolaylı olarak standart girdiden sayısal değerler alıyoruz. Sayısal değerleri doğrudan standart girdiden çıkarmak yerine, standart girdiden (cin) bir dizi nesnesine (mystr) satırlar alıyoruz ve sonra tamsayıyı çıkarıyoruz bu dizeden değerler int (miktar) türünde bir değişkene. "

Benim izlenimim, işlevin bir dizenin ayrılmaz parçasını alacağı ve bunu girdi olarak kullanacağıydı.

(Burada nasıl soru soracağımı tam olarak bilmiyorum. Programlamada da yeniyim) Teşekkürler.


19
Bu örnek biraz tuhaf, stringstreambu şekilde kullanıldığını hiç görmedim . Genellikle, çizgi yüklemek dönüştürmek ve sonra çünkü ancak bu Açıkçası burada biraz avantaja sahip bölümleri tarafından ayıklamak cin olan bir giriş akışı zaten ... Yani cin >> price >> quantity;çok basit tarafından olurdu. Bu, cplusplus.com eğitimlerini KULLANMAMANIZ için iyi bir neden olacaktır .
Bartek Banachewicz

6
Bu öğreticinin C ++ ile ilk karşılaşmam olması komik. Geriye dönüp bakıldığında, oldukça zayıf ve eksik. Onun yerine iyi bir kitap öneririm .
jrok

@BartekBanachewicz Belki de nasıl stringstreamçalıştığını göstermek için bir örnek bulmaları gerekiyordu . Tuhaf bir durum, muhtemelen kötü de olsa =) Ama dizgeyi bir akım olarak ele alabileceğinizi gösterir.
luk32

Daha gelişmiş kullanımlara giriş değilse, stringstreamkesinlikle yanlış bir örnektir. Ve öyle olsa bile farklı yazılmalıdır.
j_kubik

1
@trojansdestroy Temel aldığı tüm ilkelleri anlamadan stringstream'i anlayamazsınız, bu yüzden bir öğretici okumanın bu konuda nasıl yardımcı olduğunu anlamıyorum.
Bartek Banachewicz

Yanıtlar:


163

Bazen dizeler ve diğer sayısal türler arasında dönüştürme yapmak için dizge akışını kullanmak çok uygundur. 'Nin kullanımı, stringstreamkullanımına benzer iostream, bu nedenle öğrenmek için bir yük değildir.

Stringstreams, hem dizeleri okumak hem de dizelere veri yazmak için kullanılabilir. Esas olarak bir dizi arabelleği ile çalışır, ancak gerçek bir G / Ç kanalı olmadan çalışır.

Stringstream sınıfının temel üye fonksiyonları

  • str(), tamponunun içeriğini dize türünde döndürür.

  • str(string), tamponun içeriğini dizge bağımsız değişkenine ayarlayan.

Dize akışlarının nasıl kullanılacağına dair bir örnek aşağıda verilmiştir.

ostringstream os;
os << "dec: " << 15 << " hex: " << std::hex << 15 << endl;
cout << os.str() << endl;

Sonuç dec: 15 hex: f.

istringstream aşağı yukarı aynı kullanımdadır.

Özetlemek gerekirse, stringstream, bağımsız bir I / O cihazı gibi dizeleri manipüle etmenin uygun bir yoludur .

Bilginize, sınıflar arasındaki miras ilişkileri şunlardır:

dize akışı sınıfları


19

Soruyu cevaplamak için. stringstreamtemelde bir stringnesneye a gibi davranmanıza ve üzerindeki streamtüm streamişlevleri ve işleçleri kullanmanıza izin verir .

Genelde biçimlendirilmiş çıktı / girdi iyiliği için kullanıldığını gördüm.

c++Numarayı akış nesnesine dönüştürmenin uygulanması iyi bir örnek olabilir .

Olası örnek:

template <class T>
string num2str(const T& num, unsigned int prec = 12) {
    string ret;
    stringstream ss;
    ios_base::fmtflags ff = ss.flags();
    ff |= ios_base::floatfield;
    ff |= ios_base::fixed;
    ss.flags(ff);
    ss.precision(prec);
    ss << num;
    ret = ss.str();
    return ret;
};

Belki biraz karmaşık ama oldukça karmaşık. stringstreamNesne yaratır ss, bayraklarını değiştirir, içine bir sayı koyar operator<<ve onu kullanarak çıkarırsınız str(). Sanırım bu operator>>kullanılabilir.

Ayrıca bu örnekte stringarabellek gizlidir ve açıkça kullanılmamaktadır. Ancak olası her yön ve kullanım durumu hakkında yazmak çok uzun bir gönderi olurdu.

Not: Muhtemelen SO'daki birinden çaldım ve rafine ettim, ancak orijinal yazarım yok.


3
Not: kullanımı retgereksizdir, yazılabilir return ss.str();.
Matthieu M.

@MatthieuM. Sanırım böyle yazılırsa RVO'nun devreye girip girmeyeceğinden veya ss.str () tarafından döndürülen nesnenin çıkış noktasından sağ çıkıp çıkmayacağından emin değildim. Bu şekilde bir kopya oluşturduğumu biliyorum ve RVO çalışacak. Ama büyük ihtimalle haklısın.
luk32

Aslında, 2 RVO biçimi vardır: URVO (adsızlar için, yani geçiciler için) ve NRVO (adlandırılmışlar için); çoğu derleyici RVO uygular, ancak bazıları bunu yalnızca URVO ile sınırlar (derleme seçeneklerine bağlı olarak). Genel olarak, dikkate alınması gereken birçok başka faktör vardır, bu nedenle mümkün olan en temiz kodu yazmalı ve RVO'nun devreye girip girmeyeceği konusunda çok fazla endişelenmemelisiniz.
Matthieu M.

NRVO yaygındır (URVO'da olduğu gibi), ancak kurucuları hareket ettirme nedeniyle sorun teşkil etmez.
Rapptz

18

Gönderen C ++ Primer :

İstringstream tipi bir okur dize , ostringstream bir yazar dize ve stringstream okur ve yazar dize .

Stringstream'i kullanmanın hem uygun hem de özlü olduğu bazı durumlarla karşılaşıyorum .

dava 1

Bu dan çözümlerinden birinin yönelik bu leetcode sorunu . Stringstream kullanımının verimli ve özlü olduğu çok uygun bir durumu gösterir .

Varsayalım ave bdize biçiminde ifade edilen karmaşık sayılar, biz çoğalması sonucunu almak istiyorum ave bdize biçiminde de. Kod aşağıdaki gibidir:

string a = "1+2i", b = "1+3i";
istringstream sa(a), sb(b);
ostringstream out;

int ra, ia, rb, ib;
char buff;
// only read integer values to get the real and imaginary part of 
// of the original complex number
sa >> ra >> buff >> ia >> buff;
sb >> rb >> buff >> ib >> buff;

out << ra*rb-ia*ib << '+' << ra*ib+ia*rb << 'i';

// final result in string format
string result = out.str() 

durum 2

Ayrıca, verilen yol dizesini basitleştirmenizi gerektiren bir leetcode probleminden , stringstream kullanan çözümlerden biri gördüğüm en zarif çözümdür :

string simplifyPath(string path) {
    string res, tmp;
    vector<string> stk;
    stringstream ss(path);
    while(getline(ss,tmp,'/')) {
        if (tmp == "" or tmp == ".") continue;
        if (tmp == ".." and !stk.empty()) stk.pop_back();
        else if (tmp != "..") stk.push_back(tmp);
    }
    for(auto str : stk) res += "/"+str;
    return res.empty() ? "/" : res; 
 }

Dizge akışı kullanılmadan, bu kadar kısa kod yazmak zor olurdu.


2

Alfasayısal ve tamsayı girdiniz, boşluklarla ayrılmış mystr.

Daha sonra ilk belirteci (boşlukla ayrılmış) bir int.

İlk belirteç, dönüşümü başaramayan int, fiyatım için sıfır bırakan RS'ti ve hepimiz sıfır çarpı ne kadar bir şey getirdiğini biliyoruz.

Yalnızca ikinci kez int değerleri girdiğinizde, her şey beklediğiniz gibi çalıştı.

Kodunuzun başarısız olmasına neden olan sahte RS idi.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.