Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

stringstream duplicates last word

Tags:

c++

I'm trying to split a string using stringstream :

#include <fstream>
#include <iostream>
#include <sstream>
#include <string>

using namespace std;

int main(){
    ifstream fp;
    string name;

    fp.open("in.txt");
    while (fp){
        string line;
        getline(fp, line);
        cout << line << endl;
        istringstream line_stream(line);

        while (line_stream){
            line_stream >> name;
            cout << name << " ";
        }
    }

    return 0;
}

Here's in.txt :

cat bat rat sat

Here's the output I'm getting :

cat bat rat sat
cat bat rat sat sat

The line retrieved from getline() function is right, but in the process of splitting I'm getting the last word twice. I'm not sure why is this happening.

like image 850
Kartik Anand Avatar asked Jul 23 '13 10:07

Kartik Anand


2 Answers

You are using the results of getline without checking whether it succeeded. This is the first error (and probably results in an extra empty line with the code you show). Similarly, you use the results of line_stream >> name without checking whether it succeeded; in this case (because name is not newly constructed each time through), you may end up with the previously read value (but in both cases, the contents of the string are unspecified).

You must never use the results of input without first testing whether it succeeded. The most common way of doing this (but certainly not the only way) is to do the input in the condition of the loop:

while ( std::getline( fp, line ) ) ...

and

while ( line_stream >> name ) ...

If you still want to limit the scope of the variable to the loop, you'd have to write:

while ( fp ) {
    std::string line;
    if ( std::getline( fp, line ) ) {
        //  rest of loop
    }
}

If you have (understandably) something against modifying global state in a condition, you'd have to write:

std::getline( fp, line );
while ( fp ) {
    //  ...
    std::getline( fp, line );
}

While I think that there are strong arguments in favor of this, the while ( std::getline( fp, line ) ) idiom is ubiquitous, to the point where anything else will cause the reader to wonder why.

like image 196
James Kanze Avatar answered Sep 23 '22 20:09

James Kanze


Instead of saying:

while (fp){
    string line;
    getline(fp, line);
    ...

You should say:

string line;
while(getline(fp, line)) { ...

This is because when fp gets into eof state, getline fails (and sets fp to eof state). You do not check the result of the getline so for the last step you use the previously read value.

like image 34
utnapistim Avatar answered Sep 23 '22 20:09

utnapistim