Stringstream odd behaviour

Hi,

I'm puzzled, could somebody explain it to me why the following behaviour of stringstream?

I consider the following programme:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream> 
#include <sstream> 

using namespace std; 

int main() {
  char c;
  string str;
  stringstream ss;

  while(1){
    ss.str("");
    ss.clear();
    getline(cin,str);
    ss << str;
    while(!ss.eof()){
       ss >> c;
       if(c=='\0'){cout << "null" << endl;}
    }
  }
 
  return 0; 
}


I run it, and at the prompt I hit return few times, no other key. Each time I hit return, I get null printed out.

Now I code the code within the while-loop as a different function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream> 
#include <sstream> 

using namespace std; 

void f(stringstream& ss){
  char c;
  ss >> c;
  if(c=='\0'){cout << "null" << endl;}
}

int main() {
  string str;
  stringstream ss;

  while(1){
    ss.str("");
    ss.clear();
    getline(cin,str);
    ss << str;
    while(!ss.eof()){
      f(ss);
    }
  }

  return 0; 
}


and when I run it, I only get "null" printed out the first time I hit the return key. Why?

PS: I'm using g++ i686-apple-darwin9-g++-4.0.1 (GCC) 4.0.1 (Apple Inc. build 5465) 4.0.1 on an Intel Mac.



Well...you aren't ever changing or defining 'c' which is probably why c is always \0.
Last edited on
But then why is c not always \0 in the second code? The conditional in the function f is only fulfilled the first time f is called from main.

What I don't understand is why the second code is not equivalent to the first.
You are mixing things up quite thoroughly. You need to be careful how you use things.

Firstly, the value of c is always random, since you never assign it any value. The fact that it was null once then something else later is just pure happenstance. It could be anything.

Next, watch how you use your streams. EOF will only be signaled after you have made at least one attempt to read past it.
So, using the first code as example, if I type "hello" then it will read 'h', 'e', 'l', 'l', and 'o' without any problem, but EOF was still not discovered. The next time through the loop you try to read it, and regardless of whether or not you have hit it you print c again, which still has an 'o' from the last loop. Then you loop again, discover the EOF, and quit.


When using stringstreams it is usually a good idea to generate them as temporaries when you need them, then destroy them when you are done with them.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <sstream>
#include <string>

using namespace std;

int main()
  {
  char c;

  while (true)
    {
    cout << "Please enter a string. Ctrl-C to quit.\n";
    string s;
    getline( cin, s );

    stringstream ss( s );  // note 1
    for (int i = 0; ss >> c; i++)  // note 2
      {
      cout << "Letter: " << i << " is '" << c << "'\n";
      }
    }
  return 0;
  }

You'll notice that whitespace is ignored when you cin >> c;
In the above example, the stringstream (and the string) are local to the loop, so they are both created and destroyed once per loop.

[edit] Oh yeah, it isn't particularly obvious, but the inner loop is basically a while (ss >> c). See why this works here:
http://www.parashift.com/c++-faq-lite/input-output.html#faq-15.4

Hope this helps.
Last edited on
Topic archived. No new replies allowed.