127

I am trying to learn C++ since yesterday and I am using this document: http://www.cplusplus.com/files/tutorial.pdf (page 32). I found a code in the document and I ran it. I tried inputting Rs 5.5 for price and an integer for quantity and the output was 0. I tried inputting 5.5 and 6 and the output was correct.

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

What exactly does the mystring command do? Quoting from the document:

"In this example, we acquire numeric values from the standard input indirectly. Instead of extracting numeric values directly from the standard input, we get lines from the standard input (cin) into a string object (mystr), and then we extract the integer values from this string into a variable of type int (quantity)."

My impression was that the function will take an integral part of a string and use that as input.

  • 22
    This example is kinda weird, I've never seen `stringstream` used that way. I usually load the line, convert it and then extract by parts, however this obviously has little advantage here because `cin` *is* an input stream already... So `cin >> price >> quantity;` would be by far simpler. That would be a good reason **NOT** to use cplusplus.com tutorials. – Bartek Banachewicz Dec 15 '13 at 12:32
  • 7
    Funny that that tutorial was my first exposure to C++. In hindsight, it's pretty poor and incomplete. I'd suggest a [good book](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) instead. – jrok Dec 15 '13 at 12:37
  • @BartekBanachewicz Maybe they just needed to come up with example to show how `stringstream` works. It is a bizarre one probably even a bad one =) But it shows you can treat string as a stream. – luk32 Dec 15 '13 at 12:39
  • If it's not an introduction to more advanced uses of `stringstream` then it's definitely a wrong example. And even if it is then it should be written differently. – j_kubik Dec 15 '13 at 12:45
  • From [this page](http://www.cplusplus.com/reference/sstream/stringstream/): it's essentially a string buffer that can be used as a stream. – Trojan Dec 15 '13 at 12:49
  • @trojansdestroy You linked to the page we've just concluded is basically either wrong or obfuscated. Are you even reading? – Bartek Banachewicz Dec 15 '13 at 12:58
  • @BartekBanachewicz Is that definition incorrect? I said nothing of the examples on that page. Furthermore, not to disrespect anybody here, but is a list of 25 books a better link? Because I'm sure OP would rather read a few sites, hoping one isn't confusing, than choose a book at random and hope their investment is worthwhile. If it suits you, I'll delete my comment to remove the wrong and obfuscated information. – Trojan Dec 15 '13 at 22:15
  • @trojansdestroy Why would anyone read "a few sites" instead of books written by respected authors and reviewed by the community is beyond my imagination. – Bartek Banachewicz Dec 15 '13 at 22:20
  • 1
    @BartekBanachewicz Accessibility. This is a short-term task: understand stringstream. It's easier, cheaper, and faster to read online than to buy a book. Peer-reviewed books are priceless, but better suited for long-term/larger-scope learning. – Trojan Dec 15 '13 at 22:31
  • 1
    @trojansdestroy You can't understand stringstream without understanding all the primitives it's based on, so I don't see how reading a tutorial helps in that regard. – Bartek Banachewicz Dec 15 '13 at 22:40

4 Answers4

187

Sometimes it is very convenient to use stringstream to convert between strings and other numerical types. The usage of stringstream is similar to the usage of iostream, so it is not a burden to learn.

Stringstreams can be used to both read strings and write data into strings. It mainly functions with a string buffer, but without a real I/O channel.

The basic member functions of stringstream class are

  • str(), which returns the contents of its buffer in string type.

  • str(string), which set the contents of the buffer to the string argument.

Here is an example of how to use string streams.

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

The result is dec: 15 hex: f.

istringstream is of more or less the same usage.

To summarize, stringstream is a convenient way to manipulate strings like an independent I/O device.

FYI, the inheritance relationships between the classes are:

string stream classes

glhrmv
  • 1,712
  • 1
  • 16
  • 23
richard.g
  • 3,585
  • 4
  • 16
  • 26
28

From C++ Primer:

The istringstream type reads a string, ostringstream writes a string, and stringstream reads and writes the string.

I come across some cases where it is both convenient and concise to use stringstream.

case 1

It is from one of the solutions for this leetcode problem. It demonstrates a very suitable case where the use of stringstream is efficient and concise.

Suppose a and b are complex numbers expressed in string format, we want to get the result of multiplication of a and b also in string format. The code is as follows:

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

case 2

It is also from a leetcode problem that requires you to simplify the given path string, one of the solutions using stringstream is the most elegant that I have seen:

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

Without the use of stringstream, it would be difficult to write such concise code.

jdhao
  • 24,001
  • 18
  • 134
  • 273
20

To answer the question. stringstream basically allows you to treat a string object like a stream, and use all stream functions and operators on it.

I saw it used mainly for the formatted output/input goodness.

One good example would be c++ implementation of converting number to stream object.

Possible example:

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

Maybe it's a bit complicated but it is quite complex. You create stringstream object ss, modify its flags, put a number into it with operator<<, and extract it via str(). I guess that operator>> could be used.

Also in this example the string buffer is hidden and not used explicitly. But it would be too long of a post to write about every possible aspect and use-case.

Note: I probably stole it from someone on SO and refined, but I don't have original author noted.

luk32
  • 15,812
  • 38
  • 62
  • 3
    Note: the use of `ret` is unnecessary, one could write `return ss.str();`. – Matthieu M. Dec 15 '13 at 12:57
  • @MatthieuM. I think I wasn't sure if RVO would kick-in if it was written like that, or if object returned by ss.str() would survive exit point. This way I know I am making a copy, and RVO will work. But you are most probably right. – luk32 Dec 15 '13 at 13:03
  • Actually, there are 2 forms of RVO: URVO (for unnamed, that is temporaries) and NRVO (for named); most compilers implement RVO, but some restrict it to only URVO (depending on build options). In general, though, there are plenty of other factors to take into account, so you should just write the cleanest code possible and not worry too much about whether RVO will kick in. – Matthieu M. Dec 15 '13 at 13:24
  • NRVO is common (as is URVO) however it's a non-issue due to move constructors. – Rapptz Dec 15 '13 at 13:29
2

You entered an alphanumeric and int, blank delimited in mystr.

You then tried to convert the first token (blank delimited) into an int.

The first token was RS which failed to convert to int, leaving a zero for myprice, and we all know what zero times anything yields.

When you only entered int values the second time, everything worked as you expected.

It was the spurious RS that caused your code to fail.

firelynx
  • 30,616
  • 9
  • 91
  • 101
ilocos joe
  • 21
  • 1