Consider the following C++ program:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main (void)
{
string l1, l2;
int n1, n2;
stringstream ss;
getline(cin, l1);
getline(cin, l2);
cerr << l1 << " " << l2 << endl;
ss.str(l1);
ss >> n1;
ss.str(l2);
ss >> n2;
cerr << n1 << " " << n2 << endl;
return 0;
}
Sample input:
2
3
Corresponding output:
2 3
2 0
But I was expecting:
2 3
2 3
If I insert a call ss.clear() before the second call to ss.str(), the output is what I expected. Is this really necessary? And why?
It is necessary, because the first input from the stringstring hits end of file. Calling str() does not clear any error flags that are already set on the stringstream.
ss.str(l1);
ss >> n1; // Reads the entire buffer, hits the end of buffer and sets eof flag
ss.str(l2); // Sets the string, but does not clear error flags
ss >> n2; // Fails, due to at EOF
You can use clear before the second str() or after, just as long as it's before you attempt to read more data.
Related
I am trying to read a string of three number using sstream but when I try to print them, I am getting a wrong output with four numbers.
Code:
#include <iostream>
#include <sstream>
using namespace std;
int main() {
string a("1 2 3");
istringstream my_stream(a);
int n;
while(my_stream) {
my_stream >> n;
cout << n << "\n";
}
}
Output:
1
2
3
3
Why I get four numbers in the output compared to three numbers in input string?
Here
while ( my_stream )
my_stream is convertible to bool and returns true if there's no I/O error.
See: https://en.cppreference.com/w/cpp/io/basic_ios/operator_bool
So, after the last reading, there's no I/O error yet, so it iterates again and there's an error and nothing is read into n in this statement:
my_stream >> n;
And, std::cout prints the last extracted value again i.e. 3.
The solution could be to directly check I/O error after reading in while (preferred):
while ( my_stream >> n )
{
std::cout << n << '\n';
}
or, print only if the reading is successful using an if:
while ( my_stream )
{
if ( my_stream >> n ) // print if there's no I/O error
{
std::cout << n << '\n';
}
}
Example (live):
#include <iostream>
#include <sstream>
int main()
{
std::string a { "1 2 3" };
std::istringstream iss{ a };
int n {0};
while ( iss >> n )
{
std::cout << n << '\n';
}
return 0;
}
Output:
1
2
3
Relevant: Why is "using namespace std;" considered bad practice?
You are printing the data before checking if readings are successful.
while(my_stream) {
my_stream >> n;
should be
while(my_stream >> n) {
Related (doesn't seem duplicate because eof() isn't used here):
c++ - Why is iostream::eof inside a loop condition (i.e. while (!stream.eof())) considered wrong? - Stack Overflow
I would like to print integer values in a file by reading it.
The code:
int temp;
char* trainname;
trainname="dfg.txt";
ifstream trainfile;
trainfile.open(trainname);
if(!trainfile){
cout<<"Cannot open file!"<<'\n';
exit(1);
}
while(trainfile >> temp)
cout << temp << " ";
trainfile.close();
dfg.txt: 1 2 we er rf 5
output: 1 2
The problem is that it does not print 5.
Read to a temporary string first and then use std::stoi to try to parse an integer from it, and if it succeeds, output it:
std::string temp;
while(trainfile >> temp) {
try {
std::cout << std::stoi(temp) << " ";
}
catch(const std::invalid_argument&) {
// not a valid number
}
}
while(trainfile >> temp)
cout << temp << " ";
The above sets the failbit on trainfile on encountering any character that isn't whitespace or a digit. That terminates the loop. This is one reason I tend not to use formatted I/O that can fail on a input stream. I find it better to read text as text (not numbers) and then process the string that was just read. For example, see zenith's answer.
If you insist on doing everything from the input stream, you'll need an outer loop that clears the stream's failbit. For example,
while (! std::cin.eof())
{
while (std::cin >> temp)
{
std::cout << temp << " ";
}
std::cin.clear();
std::cin.ignore();
}
Given an input file containing 1 2 we er rf 5, the above will print 1 2 5. If the input file contains 1 2 abc345def 6, the above will print 1 2 345 6. Note that zenith's approach will print 1 2 6. Whether that 345 sandwiched between abc and def counts as an integer is up to you.
I'd recommend using zenith's solution over mine.
Update:
The above interprets abc345def as representing the integer 345. Both Zenith's solution and the above interpret 345def as representing the integer 345. To me, both abc345def and 345def should be rejected as representing an integer. So should 6.1 , but there's nothing wrong with 0x abc345def. There's nice tool in the C standard library, strtol, that nicely parses integers. It also indicates what made the parse stop. For a valid integer, it should stop at the end of the input string. With that,
#include <iostream>
#include < fstream>
#include <string>
#include <cstdlib>
int main ()
{
std::ifstream trainfile("dfg.txt");
if (!trainfile)
{
std::cerr << "Cannot open file!\n";
exit(1);
}
std::string s;
while(trainfile >> s)
{
char* end;
long num = std::strtol (s.data(), &end, 0);
if (!*end)
{
std::cout << num << " ";
}
}
trainfile.close();
std::cout << "\n";
}
string temp;
if( '0' <= temp[0] && temp[0]<='9' )
cout << temp << " ";
it will work i suppose.
Here is another way you can consider-
#include <iostream>
#include <sstream>
#include <fstream>
using namespace std;
int main()
{
ifstream trainname("dfg.txt",ios::in);
string temp;
getline(trainname,temp);
stringstream str;
str<<temp;
int extract_int;
while(getline(str, temp,' '))
{
if(stringstream(temp)>>extract_int)
cout<<extract_int<<" ";
}
return 0;
}
Or according to David Hammen's answer, you can solve it the following way-
#include <iostream>
#include <sstream>
#include <fstream>
using namespace std;
int main()
{
int temp;
char* trainname;
trainname="dfg.txt";
ifstream trainfile;
trainfile.open(trainname);
if(!trainfile){
cout<<"Cannot open file!"<<'\n';
exit(1);
}
while (!trainfile.eof())
{
while (trainfile>>temp)
cout<<temp<< " ";
trainfile.clear();
trainfile.ignore();
}
return 0;
}
I have a text file with words and integers. The task is to read only integers from it ignore words. This is an example of such file:
seven 7
I declare an int variable and try to read the ifstream into it (echoing the state of ifstream):
#include <iostream>
#include <fstream>
int main() {
int num = -1;
std::ifstream ifs("file.in");
std::cout << ifs << std::endl;
ifs >> num;
std::cout << ifs << std::endl;
if ( ifs.fail() )
ifs.clear();
std::cout << ifs << std::endl;
ifs >> num;
std::cout << ifs << std::endl;
std::cout << num << std::endl;
return 0;
}
To which I get an output:
1
0
1
0
-1
It's obvious that 'ifs' fails when trying to read a word into an int variable. My question is why does it fail the second time after being cleared?
The first failure doesn't advance the stream position, so the second tries again with exactly the same results. You'll need to skip over the unwanted word, either reading it into a string or using ignore.
For example:
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main() {
int num = 10;
string str;
stringstream toString;
toString << num;
toString >> str;
cout << str << "\n"; //10
int num2 = 20;
string str2;
toString << num2;
toString >> str2;
cout << str2 << "\n"; //str2 is empty
return 0;
}
I know that I must clear this like:
toString.str("");
toString.clear();
But why doesn't it clear automatically after using operator >>?
If I do toString >> a >> b >> c and the first one fails, I don't want the flag to be cleared so that the final state appears to have succeeded.
After the first read toString >> str;. then the rdstate() of toString is std::ios_base::eofbit, because during the reading of str the end of the string has been reached.
Then the line toString << num2; does not modify the string stored in toString but sets the failbit of toString. That is the standard behavior of all formatted output.
The line toString >> str2; does nothing: the failbit is already set, and no reading is performed: str2 stays empty.
The clear() function resets the rdstate() of toString to std::ios_base::goodbit.
The reasons why the >> must not call clear() are:
in case there is an error, then one must be able to test it using the functions bad(), fail(), eof() (or rdstate() directly),
and one can use the operator >> several times:
#include <iostream>
#include <sstream>
int main() {
std::stringstream sstr("10 20");
int i, j;
sstr >> i >> j;
if(!sstr.fail()) {
std::cout << i << " " << j << "\n";
return 0;
}
return 1;
}
my program ignores second loop and I can't fill vector v2
vector<int> v1;
vector<int> v2;
int elem1,elem2;
cout<<"Insert v1: ";
while(cin>>elem1){
v1.push_back(elem1);
}
cout<<"Insert v2: ";
while(cin>>elem2){
v2.push_back(elem2);
}
cin keeps going until all output is done, your 2nd loop is never gonna get hit unless you break from your first loop somehow. I would recommend you have some sort of exit condition on the first loop (such as some input marker like 'DONE' or something and once you read that you should break).
I'm guessing that you were expecting the first loop to end when you hit enter or something. but that's not what you coded. You coded 'fill up v1 until there is no input left', so it's not surprising that nothing ever gets put in v2.
Perhaps you could try the following, this reads one line, and put the contents in v1, it then reads a second line and puts the contents in v2. It uses getline to read a single line of text, then put that line into a string stream where you can read from one number at a time.
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
void fill_vector_from_one_line(vector<int>& v)
{
string str;
if (getline(cin, str))
{
istringstream iss(str);
int elem;
while (iss >> elem)
v.push_back(elem);
}
}
int main()
{
cout << "Insert v1: ";
fill_vector_from_one_line(v1);
cout << "Insert v2: ";
fill_vector_from_one_line(v2);
}
Apologies for any errors, I haven't checked this.
Reset standard input. See below.
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v1;
std::vector<int> v2;
int elem;
std::cout << "Insert v1: ";
while (std::cin >> elem) {
v1.push_back (elem);
}
// Reset std::cin.
std::cin.clear();
std::cin.seekg(0, std::ios::beg);
std::cout << "Insert v2: ";
while (std::cin >> elem) {
v2.push_back (elem);
}
// Just to show that it works.
std::cout << "\nv1 elements:\n";
for (unsigned int ii = 0; ii < v1.size(); ++ii) {
std::cout << "v1[" << ii << "] = " << v1[ii] << "\n";
}
std::cout << "\nv2 elements:\n";
for (unsigned int ii = 0; ii < v2.size(); ++ii) {
std::cout << "v2[" << ii << "] = " << v2[ii] << "\n";
}
return 0;
}
Note that the std::cin.clear(); std:cin.seekg(); calls will have different behaviors depending on the nature of std::cin.
If std::cin is tied to the terminal it will have exactly the behavior that the OP is seeking.
If std::cin is reading from a file, vector v2 will be a carbon copy of vector v1.
If std::cin is reading from a pipe, vector v2 will be empty. You can't seekg() on a pipeline.