0

I've seen other people reporting this problem with cin.ignore() and getline(). I understand it's some problem involving newlines, but I'm not entirely sure how to debug this with >>. I'm trying to implement a gradebook that takes in a student name and test grades and outputs their name (and eventually, course grade) [from Chapter 4 of Accelerated C++]. I'm having trouble even outputting the names properly, though.

// Student.cpp
#include "Student.h"
#include <iostream>
#include <vector>

istream& read(istream& in, Student& s) {
   in >> s.name >> s.midterm;
   read_hw(in, s.homework);
   return in;
}

istream& read_hw(istream& in, vector<double>& hw) {
    if (in) {
       hw.clear();

       double x;
       while (in >> x)
           hw.push_back(x);

       in.clear();
    }
    return in;
}

And here I try to test it with my main function:

int main() {
    vector<Student> students;
    Student curr_student;

    while (read(cin, curr_student)) {
        cout << curr_student.name;
        students.push_back(curr_student);
        cout << students.size() << endl;
    }

    cout << students.size() << endl;
    for (int i = 0; i < students.size(); i++) {
        cout << students[i].name << endl;
    }
    return 0;
}

When I input something into the command line, though, the output of the student names after the first one are cut off:

Input in terminal:

 Alice 50 50 50 50 (<enter>)
 Bob 100 100 100 100 (<enter>)
 Carl 50 50 50 50 (<enter>)
 (<Ctrl-D>)

And then it outputs:

 Alice
 ob
 rl
Jess
  • 1,515
  • 3
  • 23
  • 32
  • Take a look at answer 1 option 2: [Read file line by line](https://stackoverflow.com/questions/7868936/read-file-line-by-line). It will make your life much easier. – user4581301 Jul 09 '17 at 07:18
  • cin doesnt take space characters , you probably need to input stream reader function , you should probably write a loop for taking the rest of the mark values . – paws Jul 09 '17 at 07:24
  • 1
    I am unable to [reproduce your problem.](http://ideone.com/jWoG74) However in order to make the attempt, I have had to move a few things around and fill in some blanks, so clearly the code I have run is not the same as yours. I recommend producing a [mcve] so we out here don't have to guess what we're doing differently from you. – user4581301 Jul 09 '17 at 07:33

1 Answers1

1

From the look of the result the grades are read using hex format: B, C, and a are vaild hex digits. That shouldn't be happen according to your cide, though.

In any case note that formatted reading will normally skip all leading white space, including newlines. There are a few approaches to deal with line ends. The usual one is to resd lines into a std::string and use the string to initialize an std::istringstream.

An alternative approach would be the use of a custom definition of line ends by specializing the std::ctype<char> facet to not consider newline a space character. Another approach is using a manipulator which consumes whitespace but sets std::ios_base::failbit upon encountering a newline. For example:

std::istream& skip(std::istream& in) {
    if (std::istream::sentry kerberos{in, true}) {
        std::istreambuf_iterator<char> it(in), end;
        if (end != (it = std::find_if(it, end, [](unsigned char c){
                return !std::isspace(c) || char(c) == '\n'; }))
            && *it == '\n') {
            ++it;
            in.setstate(std::ios_base::failbit);
         }
    }
    return in;
}
// ...
if (in) {
    while (in >> skip >> x) {
        hw.push_back(x);
    }
    if (!hw.empty()) {
        in.clear();
    }
}

While I don't think I'd be able that the original code actually reproduces the problem I'm fairly sure that the above approach does fix it!

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380