C++ istream_iterator doesn't work after initial use [duplicate] - c++

I am new to C++, sorry if this is a silly question. I cannot seem to figure out why this does not work. It copies into the first vector, and seems to skip past the second copy call.
#include <iostream>
#include <vector>
#include <iterator>
using namespace std;
int main ()
{
vector<int> first;
vector<int> second;
copy(istream_iterator<int>(cin),istream_iterator<int>(),back_inserter(first));
cin.clear();
copy(istream_iterator<int>(cin),istream_iterator<int>(),back_inserter(second));
return 0;
}
I want to use the copy function to read istream_iterator input into any number of vectors(one call to copy per vector). In other words: I want to be able to enter "1 2 3 4 5 ctrl+d" into the console and have 1,2,3,4,5 entered into the first vector. Then enter "6 7 8 9 10 ctrl+d" into the console and have 6,7,8,9,10 entered into the second vector.
The problem is that after I enter some input into the first vector and press control+d the istream_iterator for cin remains equal to istream_iterator(), regardless of cin's fail state. This causes every subsequent call to "copy" to fail (because istream_iteratorcin is already equal to istream_iterator() which the program interprets as eof).
So my question is: What do I need to do to "reset" the iterator along with the cin stream? cin.clear() is indeed clearing all the fail bits. However the istream_iterator(cin) is still equal to istream_iterator() regardless. From what I understand, istream_iterators that are bound to a stream should only be equal to the default istream_iterator value when the stream is in a fail state. What am I missing?

The istream_iterator is an input iterator, which means you can only dereference each iterator value once. You are literally reading from a stream, and there's no seeking or going back. So once you hit the end-of-stream, there's nothing more to input and the second range is empty.
Why not just say vector<int> second(first); to make a copy?
Update: After you clarified the question, here's a new answer: You're misunderstanding how stdin works. There is only one input. Ctrl-D isn't anything inherent to C++; rather, it is a convention of your platform, and your platform will terminate the input buffer when you signal Ctrl-D. After that, the input "file" is finished, and no further data can be written to it.
Your approach is a bit unorthodox, though. Usually, you would just read line by line, separated by Enter, and tokenize each line. Using string streams, you get very similar code:
std::string line;
std::vector<int> first, second;
// Read line 1
if (std::getline(std::cin, line))
{
std::istringstream iss(line);
std::copy(std::istream_iterator<int>(iss), std::istream_iterator<int>(), std::back_inserter(first));
}
else { /* error */ }
// Read line 2
if (std::getline(std::cin, line))
{
std::istringstream iss(line);
std::copy(std::istream_iterator<int>(iss), std::istream_iterator<int>(), std::back_inserter(second));
}
else { /* error */ }

Related

Using stringstream object multiple times

I am finding it difficult to wrap my head around working of stringstream. Why the second while loop in the below code does not work? If stream object is getting emptied at the end of the first while loop is there any workaround to restore it back to initial condition?
// input is string of numbers separated by spaces (eg. "22 1 2 4")
std::string input;
std::getline(std::cin, input);
stringstream stream (input);
// print individual numbers
while (stream >> n)
{
cout << n << endl;
}
// print individual numbers again
while (stream >> n)
{
cout << n << endl;
}
stringstream is a subclass of istream, so stream >> n (std::istream::operator>>) returns a reference to istream
stream can be converted to bool (std::ios::operator bool): it converts to false when it no longer has any data (reached end-of-file)
You have finished reading stream in your first loop - it no longer has any data.
If stream object is getting emptied at the end of the first while loop is there any workaround to restore it back to initial condition?
You need to store values on your own and then reuse them - copying streams is not allowed (it doesn't make sense for them really) - Why copying stringstream is not allowed?
It's not emptied, but once you reach the end, you're stuck at the end – just like with other streams.
You need to clear the error flags (stream.clear()) and then either rewind (stream.seekg(0)) or reset the input string (stream.str(input)).
You need to create the stringstream first, in order to make multiple passes over what you have read into input. input itself is just a string not stream. #include <sstream> and then after reading input create the stringstream with:
std::stringstream stream (input);
You can then read with your first while loop, but the second while will not work because the stream position is left at the end of the stringsteam after the first while and eofbit is set.
You need call stream.seekg(0) to "rewind" the file and clear eofbit, see: std::basic_istream::seekg before the second while loop.

sstream not working properly? [duplicate]

This question already has an answer here:
How to clear stringstream? [duplicate]
(1 answer)
Closed 8 years ago.
I am using sstream to parse a string. The string contains an arbitrary number of integers separated by spaces. But sstream is not parsing the input properly. Here's my code-
#include<cstdio>
#include<cstring>
#include<vector>
#include<cstdlib>
#include<sstream>
#include<iostream>
using namespace std;
vector<int> val[10010];
int main(){
int n,i,j,temp;
stringstream stream;
string s;
scanf("%d",&n);
vector<int>::iterator it;
for(i=0; i<n; i++){
getline(cin,s);
stream.str(s);
while(1) {
stream >> temp;
val[i].push_back(temp);
if(!stream)
break;
}
for(it=val[i].begin(); it!=val[i].end(); it++)
printf("%d ",*it);
printf("\n");
}
return 0;
}
Here are the test cases : Code
Not sure if this is your main error, but you have a \n - new line after scanf("%d",&n);, scanf is only grabbing integer, new line is left and getline is not reading your input.
You can ignore this new line with below, just before calling getline:
if ( isspace(cin.peek()) )
cin.ignore();
also, its better to:
if ( stream >> temp ) {
// do something with temp
}
now you always add string with previously parsed value as last element.
Also, you should clear stringstream before using it again, otherwise it stays in error state and you are not able to use it. Add this: stream.clear(); before stream.str(s);.
What's happening is clear. The first line you read is empty
(because you've left the '\n' in the stream when reading the
count), then you parse it with stream, ending with stream in
a failed state. And once stream is in a failed state, it
stays that way, and all further operations are no-ops.
More generally, there are a number of problems with your code:
Don't mix C style IO and iostream, especially not on the same
file. Sometimes it's unavoidable, when you have to deal with
legacy libraries, but don't do it intentionally. In fact,
there's never any reason to use C style IO in C++.
Don't define all of your variables at the top. Don't define
them until you need them. In particular, there's no point in
declaring the string stream until you're in the loop (which
would avoid the problem you're seeing).
Do check that std::getline has succeeded before using the
values you have read.
The idiomatic way of doing something like this would use
a vector of vectors, with push_back:
std::vector<std::vector<int>> val;
// and for the loop...
std::string line;
while ( std::getline( std::cin, line ) ) {
val.push_back( std::vector<int>() );
std::istringstream parse( line );
int i;
while ( parse >> i ) {
val.back().push_back( i );
}
}
Except, perhaps, with more error checking. (Did the parse >>
i in the while fail because it has read all of the line, or
because some one slipped an "abc" in as a number?)
Add cin.get (); after your scanf -- this consumes the \n at the end of your line of input where you're reading in n. After that, you'll stop getting nonsense in your vector. cin.ignore(SOME_BIG_NUMBER) might also work, skipping not just the next char (likely \n) but also spaces preceding it.
There's one other fix you need: in the innermost loop, if(!stream) break; must come before val[i].push_back(temp);, or you'll get an extra copy of the last int on your input line.
I further recommend that you either use stream I/O or C-style I/O (printf, scanf) and not both -- but that's not your problem here.

Error reading and printing a text file with C++

I have a bug with my code (the code at the end of the question). The purpose of my C++ executable is to read a file that contains numbers, copy it in a std::vector and
then just print the contents in the stdout? Where is the problem? (atoi?)
I have a simple text file that contains the following numbers (each line has one number)
mini01:algorithms ios$ cat numbers.txt
1
2
3
4
5
When I execute the program I receive one more line:
mini01:algorithms ios$ ./a.out
1
2
3
4
5
0
Why I get the 6th line in the stdout?
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
void algorithm(std::vector<int>& v) {
for(int i=0; i < v.size(); i++) {
cout << v[i] << endl;
}
}
int main(int argc, char **argv) {
string line;
std::vector<int> vector1;
ifstream myfile("numbers.txt");
if ( myfile.is_open()) {
while( myfile.good() )
{
getline(myfile, line);
vector1.push_back(atoi(line.c_str()));
}
myfile.close();
}
else {
cout << "Unable to open file" << endl;
}
algorithm(vector1);
return 0;
}
You should not use while (myfile.good()), as it will loop once to many.
Instead use
while (getline(...))
The reason you can't use the flags to check for looping, is that they don't get set until after an input/output operation notices the problem (error or end-of-file).
Don't use good() as the condition of your extraction loop. It does not accurately indicate whether the next read will succeed or not. Move your call to getline into the condition:
while(getline(myfile, line))
{
vector1.push_back(atoi(line.c_str()));
}
The reason it is failing in this particular case is because text files typically have an \n at the end of the file (that is not shown by text editors). When the last line is read, this \n is extracted from the stream. Yes, that may be the very last character in the file, but getline doesn't care to look any further than the \n it has extracted. It's done. It does not set the EOF flag or do anything else to cause good() to return false.
So at the next iteration, good() is still true, the loop continues and getline attempts to extract from the file. However, now there's nothing left to extract and you just get line set to an empty string. This then gets converted to an int and pushed into the vector1, giving you the extra value.
In fact, the only robust way to check if there is a problem with extraction is to check the stream's status bits after extracting. The easiest way to do this is to make the extraction itself the condition.
You read one too many lines, since the condition while is false AFTER you had a "bad read".
Welcome to the wonderful world of C++. Before we go to the bug first, I would advise you to drop the std:: namespace resolution before defining or declaring a vector as you already have
using namespace::std;
A second advise would be to use the pre increment operator ++i instead of i++ wherever feasible. You can see more details on that here.
Coming to your problem in itself, the issue is an empty new line being read at the end of file. A simple way to avoid this would be to check the length of line before using it.
getline(myfile, line);
if (line.size()) {
vector1.push_back(atoi(line.c_str()));
}
This would enable your program now to read a file interspersed with empty lines. To be further foolproof you can check the line read for presence of any non numeric characters before using atoi on it. However the best solution as mentioned would be use to read the line read to the loop evaluation.

c++: istringstream

I am creating a simple command parser using c++, and I am trying to use istream >> to check whether I am inputting a number or a character.
input:
a = 10
b = a
parser.cpp:
string inputLine, varLeft, equal, varRight;
double varValue
// please see update below
while(getline(cin, inputLine)){
istringstream stringSplitter(inputLine);
stringSplitter >> varLeft >> equal;
if(!(stringSplitter >> varValue)){
stringSplitter >> varRight;
}
}
The goal is, later in the code, if varRight is empty, I assume that the line of input was a double literal, otherwise, it's a string that denotes a variable. I understand there might be logical errors associated with mixed input starting with digits, but I am assuming that all input is correctly formatted for now. Why is the a in the second line of input discarded? What fix do you propose?
Update
The problem is not with the while loop statement, it is with the if statement at the end of the while code block.
In the actual code, the loop is not actually a while loop; I am using a vector object holding string commands, and iterating through them using a for loop which goes through the vector using iterators. But, in order to please the commenters, I have fixed it above.
If an input function fails, the stream will not allow any more extractions until you clear the failure state. You'll need to do that, after you've checked that the input to varValue failed, with std::basic_ios::clear:
if(!(stringSplitter >> varValue)){
stringSplitter.clear();
stringSplitter >> varRight;
}
I don't know how you're doing /* not end of input */ at the moment (hopefully you're not checking eof()!), but it's recommended that you do:
while (getline(cin, inputLine)) {
// ...
}
This checks that the line input was successful before diving into the loop.

simple istream_iterator question

I am new to C++, sorry if this is a silly question. I cannot seem to figure out why this does not work. It copies into the first vector, and seems to skip past the second copy call.
#include <iostream>
#include <vector>
#include <iterator>
using namespace std;
int main ()
{
vector<int> first;
vector<int> second;
copy(istream_iterator<int>(cin),istream_iterator<int>(),back_inserter(first));
cin.clear();
copy(istream_iterator<int>(cin),istream_iterator<int>(),back_inserter(second));
return 0;
}
I want to use the copy function to read istream_iterator input into any number of vectors(one call to copy per vector). In other words: I want to be able to enter "1 2 3 4 5 ctrl+d" into the console and have 1,2,3,4,5 entered into the first vector. Then enter "6 7 8 9 10 ctrl+d" into the console and have 6,7,8,9,10 entered into the second vector.
The problem is that after I enter some input into the first vector and press control+d the istream_iterator for cin remains equal to istream_iterator(), regardless of cin's fail state. This causes every subsequent call to "copy" to fail (because istream_iteratorcin is already equal to istream_iterator() which the program interprets as eof).
So my question is: What do I need to do to "reset" the iterator along with the cin stream? cin.clear() is indeed clearing all the fail bits. However the istream_iterator(cin) is still equal to istream_iterator() regardless. From what I understand, istream_iterators that are bound to a stream should only be equal to the default istream_iterator value when the stream is in a fail state. What am I missing?
The istream_iterator is an input iterator, which means you can only dereference each iterator value once. You are literally reading from a stream, and there's no seeking or going back. So once you hit the end-of-stream, there's nothing more to input and the second range is empty.
Why not just say vector<int> second(first); to make a copy?
Update: After you clarified the question, here's a new answer: You're misunderstanding how stdin works. There is only one input. Ctrl-D isn't anything inherent to C++; rather, it is a convention of your platform, and your platform will terminate the input buffer when you signal Ctrl-D. After that, the input "file" is finished, and no further data can be written to it.
Your approach is a bit unorthodox, though. Usually, you would just read line by line, separated by Enter, and tokenize each line. Using string streams, you get very similar code:
std::string line;
std::vector<int> first, second;
// Read line 1
if (std::getline(std::cin, line))
{
std::istringstream iss(line);
std::copy(std::istream_iterator<int>(iss), std::istream_iterator<int>(), std::back_inserter(first));
}
else { /* error */ }
// Read line 2
if (std::getline(std::cin, line))
{
std::istringstream iss(line);
std::copy(std::istream_iterator<int>(iss), std::istream_iterator<int>(), std::back_inserter(second));
}
else { /* error */ }