3

I want to take input from the user in a string and insert those values into a vector using stringstream
my code looks like this :

#include <iostream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
int main (){
    string s;
    getline(cin ,s);
    vector<int>vec;
    istringstream iss{s};
   while(iss){
        int temp;
        iss>>temp;
        vec.push_back(temp);
    }
    for (auto val:vec){
        cout << val<<" ";
    }
    return 0;
}

I am inserting 1 2 3 in the string but the output is 1 2 3 3 . this method is inserting the last
element 2 times.
but the following is working fine :

#include <iostream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
int main (){
    string s;
    getline(cin ,s);
    vector<int>vec;
    istringstream iss{s};
    do{
        int temp;
        iss>>temp;
        vec.push_back(temp);
    }while(!iss.eof());
    
    for (auto val:vec){
        cout << val<<" ";
    }
    return 0;
}

can anyone tell why the first method is taking the last input twice?

cigien
  • 57,834
  • 11
  • 73
  • 112
  • On a side-note, if you learn about [`std::istream_iterator`](https://en.cppreference.com/w/cpp/iterator/istream_iterator) you can simplify your code quite considerably: `std::vector vec(std::istream_iterator(iss), std::istream_iterator());` The first loop isn't needed. There's a corresponding [`std::ostream_iterator`](https://en.cppreference.com/w/cpp/iterator/ostream_iterator) which can be used together with [`std::copy`](https://en.cppreference.com/w/cpp/algorithm/copy) to omit the second loop also, but your explicit loop is more clear and understandable so keep it. – Some programmer dude Aug 27 '21 at 05:37
  • where is this method written there –  Aug 27 '21 at 05:43

1 Answers1

4

It's inserting twice because you don't check if extraction from the stream works. Do this instead:

int temp;
while(iss >> temp) {
    vec.push_back(temp);
}

You could use a for loop if you want to keep the scope of temp to a minimum:

for(int temp; iss >> temp;) {
    vec.push_back(temp);
}

Lets pretend that there is only one int in iss and walk through what happens in your loop:

while(iss) {              // 1.   4.   7.
    int temp;
    iss>>temp;            // 2.   5.
    vec.push_back(temp);  // 3.   6.
}
  1. iss is in a good state, the condition is true.
  2. Extracting an int into temp works.
  3. The newly extracted int is stored.
  4. iss is still in a good state, the condition is true.
  5. Extracting an int into temp fails and sets iss in a failed state and leaves temp uninitialized
  6. The previously extracted int is stored1
  7. The condition is now false.

1Reading uninitialized values makes your program have undefined behavior. In this case it happens to give you the value stored in the temp from the previous loop - presumably because each temp created in the loop shares the same memory address.

Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108