Splitting a string into integers using istringstream in C++
Asked Answered
F

3

21

I'm trying to use istringstream to split a simple string into a series of integers:

#include <string>
#include <iostream>
#include <sstream>
#include <vector>

using namespace std;

int main(){

    string s = "1 2 3"; 
    istringstream iss(s);   

    while (iss)
    {
        int n;
        iss >> n;
        cout << "* " << n << endl;
    } 
}

And i get:

* 1
* 2
* 3
* 3

Why is the last element always coming out twice? How to fix it?

Forensics answered 2/3, 2011 at 14:16 Comment(0)
K
35

It's coming out twice because your looping is wrong, as explained (indirectly) at http://www.parashift.com/c++-faq-lite/input-output.html#faq-15.5 (while (iss) is not dissimilar from while (iss.eof()) in this scenario).

Specifically, on the third loop iteration, iss >> n succeeds and gets your 3, and leaves the stream in a good state. The loop then runs a fourth time due to this good state, and it's not until the next (fourth) iss >> n subsequently fails that the loop condition is broken. But before that fourth iteration ends, you still output n... a fourth time.

Try:

#include <string>
#include <iostream>
#include <sstream>
#include <vector>

using namespace std;

int main()
{
    string s = "1 2 3"; 
    istringstream iss(s);   
    int n;

    while (iss >> n) {
        cout << "* " << n << endl;
    } 
}
Kaye answered 2/3, 2011 at 14:19 Comment(4)
how can we do this in for() loop?Noto
@SumitKandoi: What do you mean? Why would you?Kaye
actually, i was tried it in while() loop. i was thinking can we do this in for() loop alsoNoto
@SumitKandoi: Sure. But why? for (int n; iss >> n; ) { ... }Kaye
M
1

Hope this helps:
iss : 1 2 3
Iteration 1
iss : 1 2 3 (Initially)
n=1
iss : 2 3
//* 1 is printed
Iteration 2:
iss : 2 3 (Initially)
n=2
iss : 3
//* 2 is printed
Iteration 3
iss : 3
n=3
iss : ''
Iteration 4
iss : ''
n not changed//Flag set for eof of iss as no further input from stream
iss : ''

And as rightly mentioned by the above post while (iss) is not dissimilar from while (iss.eof()).
Internally, the function(istream::operator>>) accesses the input sequence by first constructing a sentry object (with noskipws set to false[This means that space is separator and your list will be 1,2,3]). Then (if good[here eof not reached]), it calls num_get::get [Get the next integer] to perform both the extraction and the parsing operations, adjusting the stream's internal state flags accordingly. Finally, it destroys the sentry object before returning.

Refer : http://www.cplusplus.com/reference/istream/istream/operator%3E%3E/

Monicamonie answered 4/11, 2013 at 11:11 Comment(0)
K
0

The common case is to split into a vector directly using an iterator, avoiding the messy while loop and EOF gotchas entirely (see this answer which elaborates nicely on why OP's code doesn't work):

#include <iostream>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>

int main() {
    std::string s = "1 2 3"; 
    std::istringstream iss(s);
    const std::vector<int> values{std::istream_iterator<int>(iss),
                                  std::istream_iterator<int>()};

    for (const int n : values) {
        std::cout << n << "\n";
    }
}
Kleenex answered 13/2 at 17:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.