arealhumanbean
arealhumanbean

Reputation: 82

Why is cout() chopping off multiple characters?

#include <iostream>
#include <vector>

using std::cin; using std::cout; using std::istream;
using std::vector; using std::endl;

struct Student_info {
    std::string name;
    double midterm;
    double final;
    std::vector<double> homework;
};

istream& read_hw(istream& in, vector<double>& hw)
{
    if (in) {
        hw.clear();
        double x;
        while (in >> x) {
            cout << "double Grade from read_hw(): " <<  x << "\n";
            hw.push_back(x);
        }
        in.clear();
        }
    return in;
}

istream& read(istream& is, Student_info& s)
{
    is >> s.name >> s.midterm >> s.final;
    std::cout << "string Name from read()" << s.name << std::endl;
    read_hw(is, s.homework);  // read and store all the student's homework grades
    return is;
}

int main() {
  Student_info s;
  vector<double> hw;
  while (read(cin, s)) {
    cout << "String name from main()" << s.name << endl;
  }
}

Example input/output: (I typed Jimbo 99 99 99 99, which printed as I expected. Then I typed Failure 5 5 5 5 5, which gave the result you see below.)

String name from main()Jimbo
string Name from read()lure
double Grade from read_hw(): 5
double Grade from read_hw(): 5
double Grade from read_hw(): 5
Failure 10 10 10 10 10 // new input.
String name from main()lure
string Name from read()lure
double Grade from read_hw(): 10
double Grade from read_hw(): 10
double Grade from read_hw(): 10
Jimbo 99 99 99 99 99 // new input again. note it prints Jimbo just fine.
String name from main()lure
string Name from read()Jimbo
double Grade from read_hw(): 99
double Grade from read_hw(): 99
double Grade from read_hw(): 99

I've tried searching already and all I got was stuff about ignore(), which I'm not using. I have a hunch this has to do with using while (cin >> x) which is taking in doubles and then immediately switching to receiving strings with the next read() loop.

Upvotes: 1

Views: 75

Answers (1)

n. m. could be an AI
n. m. could be an AI

Reputation: 120031

You are getting this result because cin >> x will not fail immediately upon seeing a letter. Some letters are permitted within numbers and number-like entities. Incidentally F, A, and I (either case) are among those (they appear within inf and nan strings which designate special floating point IEEE values). So cin >> x will consume "Fai" and only then fail.

On the other hand, J is not such a letter, so upon seeing a J cin >> x will fail immediately, leaving the letter in the stream for the next read.

Mitigation strategies include

  • reading lines and parsing one student record per line
  • reading tokens and recognising whether they are numbers or not (but who says a person's name cannot be a number?)
  • introducing an explicit delimiter between student records, e.g. "|".

Upvotes: 3

Related Questions