Ce face mai exact stringstream? (Programare, C++, Sstream)

user3104350 a intrebat.

Încerc să învăț C++ de ieri și folosesc acest document:http://www.cplusplus.com/files/tutorial.pdf (pagina 32) . Am găsit un cod în document și l-am rulat. Am încercat să introduc 5,5 rupii pentru preț și un număr întreg pentru cantitate și rezultatul a fost 0. Am încercat să introduc 5,5 și 6 și rezultatul a fost corect.

// 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; 
}

Întrebare: Ce face mai exact comanda mystring? Citez din document:

„În acest exemplu, achiziționăm valori numerice de la intrarea standard în mod indirect. În loc să extragem valorile numerice direct de la intrarea standard, obținem liniile de la intrarea standard (cin) într-un obiect de tip șir de caractere (mystr), iar apoi extragem valorile întregi din acest șir într-o variabilă de tip int (quantity).”

Impresia mea a fost că funcția va lua partea integrală a unui șir de caractere și o va folosi ca intrare.

(Nu știu exact cum să pun o întrebare aici. Sunt și eu începător în programare)Mulțumesc.

Comentarii

    20

  • Exemplul ăsta e cam ciudat, nu am văzut niciodată stringstream folosit în acest mod. De obicei încarc linia, o convertesc și apoi extrag pe părți, însă acest lucru evident că nu prea are avantaje aici, deoarece cin este un flux de intrare deja… Deci cin >> price >> quantity; ar fi de departe mai simplu. Acesta ar fi un motiv întemeiat NU să folosiți tutorialele cplusplus.com. –  > Por Bartek Banachewicz.
  • Ciudat că acel tutorial a fost prima mea expunere la C++. Privind retrospectiv, este destul de slab și incomplet. Aș sugera o carte bună în schimb. –  > Por jrok.
  • @BartekBanachewicz Poate că trebuiau doar să vină cu un exemplu pentru a arăta cum stringstream funcționează. Este unul bizar, probabil chiar unul rău =) Dar arată că poți trata șirul de caractere ca pe un flux. –  > Por luk32.
  • Dacă nu este o introducere la utilizări mai avansate ale lui stringstream atunci cu siguranță este un exemplu greșit. Și chiar dacă este, atunci ar trebui să fie scris diferit. –  > Por j_kubik.
  • @trojansdestroy Nu poți înțelege stringstream fără să înțelegi toate primitivele pe care se bazează, așa că nu văd cum te ajută în această privință citirea unui tutorial. –  > Por Bartek Banachewicz.
4 răspunsuri
richard.g

Uneori este foarte convenabil să folosești stringstream pentru a converti între șiruri de caractere și alte tipuri numerice. Utilizarea lui stringstream este similară cu utilizarea lui iostream, deci nu este o povară de învățat.

Stringstreams poate fi utilizat atât pentru a citi șiruri de caractere, cât și pentru a scrie date în șiruri. Funcționează în principal cu un buffer de șiruri de caractere, dar fără un canal de I/O real.

Funcțiile membre de bază ale clasei stringstream sunt

  • str(), care returnează conținutul bufferului său în tip șir de caractere.

  • str(string), care setează conținutul bufferului la argumentul string.

Iată un exemplu de utilizare a fluxurilor de șiruri de caractere.

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

Rezultatul este dec: 15 hex: f.

istringstream are mai mult sau mai puțin aceeași utilizare.

Pentru a rezuma, stringstream este o modalitate convenabilă de a manipula șirurile de caractere ca pe un dispozitiv independent de I/O.

Pentru informarea dumneavoastră, relațiile de moștenire dintre clase sunt:

jdhao

De la Abecedar C++:

The istringstream citește un șir de caractere, ostringstream scrie un șir de caractere, și stringstream citește și scrie șir de caractere.

Am întâlnit unele cazuri în care este atât convenabil cât și concis să folosesc stringstream.

Cazul 1

Este din una dintre soluții pentru această problemă leetcode. Ea demonstrează un caz foarte potrivit în care utilizarea de stringstream este eficientă și concisă.

Să presupunem că a și b sunt numere complexe exprimate în format string, dorim să obținem rezultatul înmulțirii dintre a și b tot în format șir de caractere. Codul este următorul:

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() 

cazul 2

Este, de asemenea, de la un problemă leetcode care vă cere să simplificați șirul de căi dat, una dintre soluțiile care utilizează stringstream este cea mai elegantă pe care am văzut-o:

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; 
 }

Fără utilizarea stringstream, ar fi dificil de scris un cod atât de concis.

luk32

Pentru a răspunde la întrebare. stringstream vă permite, în principiu, să tratați un string ca pe un obiect stream, și de a utiliza toate stream funcțiile și operatorii pe acesta.

Am văzut că este folosit în principal pentru bunătățile de ieșire/intrare formatate.

Un exemplu bun ar fi c++ implementarea conversiei unui număr în obiect stream.

Exemplu posibil:

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;
};

Poate că este un pic complicat, dar este destul de complex. Se creează stringstream obiect ss, modificați-i steagurile, introduceți un număr în el cu operator<<, și îl extrageți prin str(). Presupun că operator>> ar putea fi utilizat.

De asemenea, în acest exemplu string este ascuns și nu este utilizat în mod explicit. Dar ar fi o postare prea lungă pentru a scrie despre toate aspectele și cazurile de utilizare posibile.

Notă: Probabil că am furat-o de la cineva de pe SO și am rafinat-o, dar nu am notat autorul original.

Comentarii

  • Notă: utilizarea de ret este inutilă, se poate scrie return ss.str();. –  > Por Matthieu M..
  • @MatthieuM. Cred că nu eram sigur dacă RVO ar fi intrat în funcțiune dacă era scris așa, sau dacă obiectul returnat de ss.str() ar fi supraviețuit punctului de ieșire. În acest fel, știu că fac o copie și RVO va funcționa. Dar cel mai probabil aveți dreptate. –  > Por luk32.
  • De fapt, există două forme de RVO: URVO (pentru unnamed, adică temporare) și NRVO (pentru named); majoritatea compilatoarelor implementează RVO, dar unele îl limitează doar la URVO (în funcție de opțiunile de compilare). În general, însă, există o mulțime de alți factori de luat în considerare, așa că ar trebui să scrieți cel mai curat cod posibil și să nu vă faceți prea multe griji dacă RVO va intra în funcțiune. –  > Por Matthieu M..
  • NRVO este comun (la fel ca URVO), însă nu este o problemă datorită constructorilor de mutare. –  > Por Rapptz.
ilocos joe

Ați introdus un alfanumeric și un int, delimitat de spații libere în mystr.

Ați încercat apoi să convertiți primul token (delimitat de blank) într-un int.

Primul simbol a fost RS, care nu a reușit să fie convertit în intlăsând un zero pentru myprice, iar noi știm cu toții ce înseamnă zero ori orice.

Când ați introdus doar valori int a doua oară, totul a funcționat așa cum vă așteptați.

Codul dvs. a eșuat din cauza unui RS fals.

Tags:,