PPP exercise, failing to read input with cin

I'm new to programming, and I'm working through Programming - Principles and Practice Using C++ and I'm having some trouble with one of the exercises in chapter nine.

With the below code, the program asks for and records names first as it should, but then after prompting for age input afterward, it fails to actually take any input, and just runs to the end. It's as if cin >> age_of; gets skipped. I'm sure I could fix this by writing read_ages() differently, but I'd like to know what's actually going wrong here.

Here's std_lib_facilities.h: http://ix.io/1vSn

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
/*
 * 2. Design and implement a Name_pairs class holding (name,age) pairs where
 * name is a string and age is a double. Represent that as a vector<string>
 * (called name) and a vector<double> (called age) member. Provide an
 * input operation read_names() that reads a series of names. Provide a
 * read_ages() operation that prompts the user for an age for each name.
 * Provide a print() operation that prints out the (name[i], age[i]) pairs
 * (one per line) in the order determined by the name vector.
 * Provide a sort() operation that sorts the name vector in alphabetical order
 * and reorganizes the age vector to match. Implement all "operations" as
 * member functions. Test the class (of course: test early and often).
 */

#include "../../std_lib_facilities.h"

class Name_pairs {
    public:
        void read_names();
        void read_ages();
        void print() const;
        void sort();
    private:
        vector<string> name;
        vector<double> age;
};

void Name_pairs::read_names() {
    string first_name, last_name;

    cout << "Enter a first name, followed by a last name:\n";

    while (cin >> first_name >> last_name) {
        name.push_back(first_name + " " + last_name);
    }
    cout << endl;
}

void Name_pairs::read_ages() {
    double age_of = 0;

    for (unsigned int i = 0; i < name.size(); i++) {
        cout << "Age of " << name[i] << ": ";
        cin >> age_of;
        age.push_back(age_of);
    }
}

void Name_pairs::print() const {
    if (name.size() != age.size()) {
        error("Mismatched number of names and ages.");
    }
    else {
        for (unsigned int i = 0; i < name.size(); i++) {
            cout << name[i] << ": " << age[i] << endl;
        }
    }
}

int main() {
    Name_pairs np1;
    np1.read_names();
    np1.read_ages();
    np1.print();

    return 0;
}

Just add cin.clear() after the while loop to fix the problem. This will clear the buffer of any error flags.

Also, if you want to read in both first and last names, I would suggest using getline with one string variable rather than 2 separate cin's on two separate strings (and then doing the expensive execution of concatenating them together).
If you insist on solely using std::cin, then not only do you have to clear std::cin's error flags (like Arslan suggested), but you will also have to use the std::cin.ignore() member function to purge any potential delimiter characters left over in the stream. Here is one way of writing it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <iostream>
#include <limits>

namespace utility {

	namespace input {

		/*
		'clear' sets the internal state flag to 'goodbit' if the stream isn't 'good'.
		It also purges any remaining characters in the stream's buffer.
		*/
		void clear(std::istream& stream = std::cin) {
			if (!(stream.good())) {
				stream.clear();
			}

			auto count = std::numeric_limits<std::streamsize>::max();
			auto delim = '\n';
			stream.ignore(count, delim);
		}


		/*
		'get' is basically our 'std::cin' wrapper.
		*/
		template<typename Type>
		Type get(std::istream& stream = std::cin) {
			Type object = Type();
			while (true) {
				if (stream >> object) {
					break;
				}
				utility::input::clear(stream);
				//Print "Try again" message
			}
			return object;
		}

	}

}

int main() {

	using Integer = int;

	std::cout << "Enter an integer:\t";
	Integer integer = utility::input::get<Integer>();

	return 0;
}
Last edited on
Thanks! Adding cin.clear() fixed it. The book shows that using cin >> something as the condition for a loop will work, but I don't recall it ever saying that would leave an error behind in cin. Anyway, I looked getline up and that does seem to be the way to go for this, so thanks for that too.

xismn, thanks but if I'm being honest, being new and all, I can't make heads or tails of quite a lot of that. I'll come back to it once I've gotten further along.
Topic archived. No new replies allowed.