I am trying to read all the numbers a line of text, one by one.
Here is a minimal reproducible example of my code:
#include <iostream>
#include <sstream>
int main() {
std::string line = "1 2"; // This value represents the next input line
std::stringstream lineStream(line);
for (char nextChar = lineStream.peek(); nextChar != EOF; nextChar = lineStream.peek()) {
int n;
lineStream >> n;
std::cout << "n==" << n << "," << std::flush;
}
return 0;
}
This works when line == "1 2" (prints "n==1,n==2,") or line == "1" (prints "n==1").
However, when line has trailing whitespace, for example when line == "1 2 " (note the "space" character after the digit), the last number somehow gets read twice. In this example, the program prints "n==1,n==2,n==2,". I think the reason this happens is that the variable n is stored at the same memory address every iteration, and since I didn't initialize it, it uses the value of n from the previous iteration.
To test this, I have modified the for loop:
for (char nextChar = lineStream.peek(); nextChar != EOF; nextChar = lineStream.peek()) {
int n = 0;
lineStream >> n;
std::cout << "n==" << n << "," << std::flush;
}
And just as I suspected, now having line == "1 2 " prints "n==1,n==2,n==0,".
From that I deduce that I have an extra iteration in the case of an input with trailing whitespace. However, I am not sure how to fix it; I can't just break out of the loop when nextChar is whitespace, since there are whitespace characters between every two numbers.
So my question is:
How can I avoid the extra iteration of the for loop in the case of a trailing whitespace? Note that I have to read the input one line at a time, so using std::cin directly isn't an option to my understanding.
I am using C++17.
As 463035818_is_not_an_ai said in the comments, you should also check the the state of the stream after the assignment, rather that only checking for EOF.
One way to do this is changing the loop body like so:
If
line == "1 2 ", this will print"1,2,"` as expected.As Hatted Rooster written in this SO answer:
An invalid input is considered an error, so
linestream >> nwill returnfalsein this case. After trying to assign the trailing whitespace into anintand failing,falsewill be returned and the loop will stop before using the invalid value.You can also use the input stream's
fail()method, which like the>>operator, will return "trueif an error has occurred,falseotherwise". So you can also write your code like so:If
line == "1 2 ", this will print"n==1,n==2,(invalid input),"`.