Home > other >  Could I use `std::cin` for another input if I've exited it using `Ctrl D`(EOF)?
Could I use `std::cin` for another input if I've exited it using `Ctrl D`(EOF)?

Time:09-09

I have this exercise from Programming principles and practice using C by B. Stroustrup:

  1. 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).

Here I show the part that causes the problem only for the brevity sake:

std::istream& Name_pairs::read_names(std::istream& in){
    for(std::string str; in >> str; )
        name.push_back(str);
    in.clear();
    in.ignore(std::numeric_limits<std::streamsize>::max(), '\n');


 // the following lines are added just for testing the stream state
    int x;
    std::cout << "x: ";
    std::cin >> x;
    std::cout << x << '\n';

    return in;
}

Now if I call the member function:

 Name_pairs{}.read_names(std::cin);

I get prompted to enter names until I hit EOF (Ctrl D). At that moment I follow it by clear and ignore to reset the input buffer. But I am not prompted to input x!!?

  • I've seen some suggestions that I should trigger a constant string as an exit mark like std::string quit = "quit; if(str == quit) break; but I don't want this; I want to use Ctrl d then get input again. In other words can I use the input stream after pressing Ctrl D?

  • I've tried the very program on windows 10 and Code::blocks for windows and it worked fine! I press Ctrl D; the loop breaks then I am prompted to input x.

  • So how could I fix the problem? thanks

CodePudding user response:

There is no standard way to reuse a closed/terminated stream, including cin.

Once cin is closed/terminated, it can't be reused by standard means. However, there may be non-standard, platform-specific ways to reopen it. Check your compiler/platform documentation.

That being said, nothing in the requirements you have shown will prevent you from prompting the user for the number of names to enter and then using an ordinary for loop, or simply asking the user to enter a termination string to stop reading. Rather than relying on Ctrl-D/Ctrl-Z to stop the reading, which is very platform-specific behavior.

CodePudding user response:

It works on Windows because Ctrl D isn't the EOF key combo on Windows, it's the end-of-text character. Ctrl Z (plus Enter) is the EOF marker on Windows.

If cin actually hits EOF, it's done. Your code only works on Windows because you didn't actually hit EOF on Windows.

CodePudding user response:

The most common (and obnoxious, IMHO) way is to first ask how many.

std::vector <std::string> names;
int n;
std::cout << "How many names? ";
std::cin >> n;
std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );

while (n--)
{
  std::string name;
  getline( std::cin, name );
  names.push_back( name );
}

The way I prefer is to simply terminate on the first empty line:

std::vector <std::string> names;
std::cout << "Enter names, one per line. Press ENTER twice to finish.\n";
while (true)
{
  std::cout << "name? ";
  std::string name;
  getline( std::cin, name );
  if (name.empty()) break;
  names.push_back( name );
}  

Now that you have a vector of names, you can ask for an age to go with each one:

std::vector <int> ages;
for (auto name : names)
{
  std::cout << name << "’s age? ";
  int n;
  std::cin >> n;
  ages.push_back( n );
}
std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );

Another common way, which is a variation of the “empty line” method I just showed you, is to use a sentinel value to terminate the input. It can be anything, like having the user enter “done” as the final name, or “-1” or something. You can guess my opinion on that nonsense.

As always, make sure you are reading your assignment correctly. If unsure, email your professor and ask clarification. Remember to ask an intelligent question, which shows your professor you aren’t just begging for an answer.

  • Related