Jerax
Jerax

Reputation: 21

cin reads zero after an unsuccessful attempt to read

I want user to enter values for vector<double> a_ until no double value would be read. And I want to make a vector of doubles called b_ which its size depends on a_'s size, actually it is exactly the same. Initialization of b_ have to be near a_ init. But there is some problem with b_, which I don't get. All values of b_ are set to 0.

Code:

#include <iostream>
#include <vector>

using namespace std;

int main() {
    vector<double> a_, b_;
    double tmp;
    while(cin >> tmp) {
        a_.push_back(tmp);
    }
    cout << "A size = " << a_.size() << endl;
    for(int i = 0; i < a_.size(); i++) {
        cin >> tmp;
        b_.push_back(tmp);
    }
    for(int i = 0; i < a_.size(); i ++) { 
        cout << "a[" << i <<"] = " <<a_[i];
        cout << " " <<"b[" << i <<"] = " <<b_[i] << endl;
    }
    return 0;
}

Input is:

4
5
6
e
7
8
9

Output is:

A size = 3
a[0] = 4 b[0] = 0
a[1] = 5 b[1] = 0
a[2] = 6 b[2] = 0

Upvotes: 2

Views: 306

Answers (3)

Fenix Lin
Fenix Lin

Reputation: 1

cin use a "fail" flag to mark input failures inside, to return a null pointer so that "while" can notice it. So you need to use cin.clear() after first cin>>tmp to reset the "fail" flag of cin.

you shouldn't use cin>>tmp in "for" loop, as you wish to read numbers once a time.

Here's a working code:

#include <iostream>
#include <vector>

using namespace std;

int main() {
    vector<double> a_, b_;
    double tmp;
    while(cin >> tmp) {
        a_.push_back(tmp);
    }
    cin.clear();
    cout << "A size = " << a_.size() << endl;
    for(int i = 0; i < a_.size(); i++) {
        do {tmp = cin.get();} while (tmp=='\n');
        b_.push_back(tmp);
    }
    for(int i = 0; i < a_.size(); i ++) { 
        cout << "a[" << i <<"] = " <<a_[i];
        cout << " " <<"b[" << i <<"] = " <<b_[i] << endl;
    }
    return 0;
}

Then for input

4
5
6
a
b
c

You will get

A size = 3
a[0] = 4 b[0] = 97
a[1] = 5 b[1] = 98
a[2] = 6 b[2] = 99

Upvotes: 0

songyuanyao
songyuanyao

Reputation: 172994

I added some explanations by comment:

while(cin >> tmp) {
    a_.push_back(tmp); // read 4, 5, 6 and push_back them
}                      // the loop ends when extraction fails for reading e

...

for(int i = 0; i < a_.size(); i++) {
    cin >> tmp;        // extraction fails for reading e everytime, 
                       // and tmp will be set to 0.0
    b_.push_back(tmp); // push_back 0.0 everytime
}

Note that according to the behaviour of std::basic_istream::operator>>,

If extraction fails, zero is written to value and failbit is set. If extraction results in the value too large or too small to fit in value, std::numeric_limits::max() or std::numeric_limits::min() is written and failbit flag is set.

After failbit is set, if you want read further, you need to clear the failbit and discard character(s) which causing the error. Such as:

// ...
cin.clear();
cin.ignore();
for(int i = 0; i < a_.size(); i++) {
    cin >> tmp;
    b_.push_back(tmp);
}
// ...

Then for the input:

4
5
6
e
7
8
9

You'll get

A size = 3
a[0] = 4 b[0] = 7
a[1] = 5 b[1] = 8
a[2] = 6 b[2] = 9

LIVE

Upvotes: 1

Zeta
Zeta

Reputation: 105925

As soon as a formatted extraction fails, cin.fail() will return true. Any further extraction will also fail, unless you .clear() the failbit.

Also, since the erroneous value is still in the input stream, you need to .ignore() it:

cout << "A size = " << a_.size() << endl;

std::cin.clear();
std::cin.ignore();

for(int i = 0; i < a_.size(); i++) {
    cin >> tmp;
    b_.push_back(tmp);
}

Upvotes: 0

Related Questions