Today our Data Structure class asked us to implement Horner's Rule. I made it at last, but there is a small bug that upsets me very much. I use a while loop to read and save the coefficients of the polynomial, and I used another cin to read the value of the variable called x. The thing is, after I reach EOF to terminate reading the coefficients, the following cin part that reads the variable x does not execute. This puzzles me very much.
while(std::cin>>n){
coeff.append(n);
}
std::cout<<"Now enter the value";
std::cin>>x;
The program is correct in syntax, but it just skips the second cin which reads the variable x.
After you have terminated the stream, nothing more is added to it and there is nothing more to read.
You need a different "end of coefficients" marker.
The simplest way is to require all coefficients to be entered on one line:
std::string line;
if (std::getline(std::cin, line))
{
std::istringstream is(line);
int n = 0; // or whatever type you're using.
while (is >> n)
{
coeff.append(n);
}
std::cout << "Enter the value: ";
std::cin >> x;
// Evaluation code here.
}
else
{
// Possibly handle error
}
Other options include defining a "magic" coeffient as the marker, or take some invalid (i.e. non-numeric) input and then clear() the stream before continuing.
Related
I have this exercise from Programming principles and practice using C++ by B. Stroustrup:
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
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.
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.
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.
In my c++ book, there is this loop:
vector<double> temps; // temperatures
for (double temp; cin>>temp; ) // read and put into temps
temps.push_back(temp);
This appears to loop forever. I can't stop this loop. What purpose does this serve?
The operator>> will return the stream (cin) which itself can be converted to a bool that represents if the stream is still valid or not. That will loop until something causes cin's read to fail (end of file, a letters instead of numbers, etc).
This is similar to:
int num;
while(cin.good()) //could also use while(cin)
{
cin >> num;
cout << num << endl;
}
Where you continuously read a number and print it. Inputting a non-number causes the input stream to fail hence cin.good() becomes false.(stream is good no more)
This might sound silly, but it's my first time solving programming contests on line. The problem is usually described as:
Input:
First line indicates the number of test cases t.For the next 't' lines the data is entered.
I've written the following program (with the correct headers included):
vector<string> read_strings(int t_cases) {
vector<string> ip_vec;
string line, str;
int cnt = 0;
while (cnt != t_cases-1) {
std::getline(std::cin, line);
++cnt;
}
std::istringstream iss(line);
while (iss >> str) {
ip_vec.push_back(str);
}
return ip_vec;
}
But this program always gets stuck in an input loop. I've also tried to parse the line as soon as it's entered by putting iss in the first while loop. If anyone could provide me a pointer on how to solve this problem, I will be able to finally test the rest of the program.
Thanks.
You need to add the lines to the vector as they are read. The first while loop is reading through all the test cases, but is not saving them somewhere. Then next while loop tries to reads line, which is the last test case read. Try the following:
vector<string> ip_vec;
string line, str;
for (int cnt = 0; cnt < t_cases; cnt++) {
std::getline(std::cin, line);
ip_vec.push_back(line);
}
Since you're starting to learn how programming contests work, I wouldn't recommend you to store all the input given. In general, you can store the number of inputs t and for each test case, the program outputs the answer for that test before reading the next test case. For example:
for (int i = 1; i <= t; i++) {
cin >> input;
// Some computations specific to the problem
cout << output << endl; // Pay attention on how the problem wants the output to be printed.
}
If the problem doesn't give you the number of test cases, you can simply change the loop to:
while (cin >> input) {
// Computations...
cout << output << endl;
}
It's usually how I solve problems from programming contests.
EDIT: As noted by #AnkitKulshrestha, if there's more than one input that you have to read for each test case, you can simply read them like this (with three inputs, for example):
while (cin >> a >> b >> c) {
// Computations...
cout << output << endl;
}
I have been trying to implement a simple code which takes a sentence as an input from the user, stores it in a string and displays it back.
Here are the issues:
1. When T = 1, the program exits immediately.
2. When T>1, the loop runs for only T-1 times.
I think the usage of cin to store the value of T is an issue here. Is the value of T entered being stored as a string due to some buffer capacity of cin?
#include <iostream>
#include <string>
int main()
{
int T;
std::cin >> T;
while (T--)
{
std::string song;
getline(std::cin, song);
std::cout << song << std::endl;
}
return 0;
}
How do you terminate the input that becomes T? With a newline. What happens with that newline after you read into T? It's still left in the input buffer. What will happen when you next call std::getline, what is the first character it will read? The newline, and what happens next? The loop iterates and then T is zero (for the first case where T was originally 1) and the loop and then the program exits.
The solution to this problem is to ignore characters up to and including the newline.
Add a getchar after cin as the \n after the input of T stays in buffer.
std::cin >> T;
getchar();
This is a strange way to do it. So you ask the user to tell the program, before any other input, how many lines will follow? Why not simply:
std::string s;
while (getline(std::cin, s)) {
std::cout << s << std::endl;
}
(This will simply echo every line (press enter to end the line) until end-of-file (Ctrl-d).
Either way, the problem with your code is the while (T--): so why don't you try to see what your T is, and what your getline gives you on each iteration? (I will let you figure it out on your own). Why not use the idiomatic:
for (int i = 0; i < T; ++i)
?
P.S. If you want to read sentences, and not lines, you might want to consider reading up to a delimiter (for example .). getline will do that for you, too:
getline(std::cin, s, '.');
For some weird reason my input line cin.getline(oneLine, 80); is completely ignored when I put it in this else if block. I can't understand why because when I move it somewhere else in the program, it works.
else if (choice == "user-id")
{
cout << endl << "Enter a full name e.g. John Smith ";
char oneLine[80];
cin.getline(oneLine, 80);
cout << oneLine;
}
Here's the rest of my code. I'm new to C++ so I'm sure a lot of my conventions may be questionable at best.
int main( )
{
while (true)
{
int pause;
string choice = "proceed";
string nameGiven;
string userIdGiven;
string result;
using namespace std ;
while ((choice != "name") && (choice != "user-id"))
{
cout << "Would you like to search for a name or user-id? ";
cin >> choice;
if ((choice != "name") && (choice != "user-id"))
cout <<"Please enter a valid choice (name or user-id)" << endl;
}
if (choice == "name")
{
string dataType = "int";
while (true)
{
cout << endl << "Enter a valid user id (4 digit maximum) ";
cin >> userIdGiven;
if (valid(userIdGiven))
break;
else
cout << endl << "Not a valid number. " << endl;
continue;
}
result = findData(userIdGiven, dataType);
cout << "name: " << result;
}
else if (choice == "user-id")
{
cout << endl << "Enter a full name e.g. John Smith ";
char oneLine[80];
std::getline(oneLine, 80);
cout << oneLine;
}
string ans;
cout << endl << "Would you like to play again? (yes/no) " << endl;
cin >> ans;
if ( (ans == "yes") || (ans == "Yes") || (ans == "Y") || (ans == "y") )
continue;
else
break;
cin >> pause;
}
return 0;
}
Your std::cin object is in a bad state (std::cin.good() == false) from a previous input operation. For example, you might have tried to read a number, but there were only nun-numeric characters in the input buffer.
Always check for input success before continuing using a std::istream.
Note: Don't use the old input functions operating with char*, as they are more complicated and less safe to use than the new ones operating on std::string. In your case, use std::getline(std::istream&, std::string&, char = '\n').
twsaef's comment's substantively correct... you're streaming a string into choice, which consumes the characters up until but excluding the next whitespace character - you're probably typing a newline to terminate your input, so it's left in the buffer. Then you use getline which sees that newline and reads an empty string.
Easiest solution is to call getline() to read the initial string too, then check if choice is "name\n" or "user-id\n". Better - write a "trim" function to remove the whitespace from the line before comparison (boost string library has this already). Otherwise, you could use read and ignore characters from std::cin until you get a '\n'. Or even read a line then put in into a stringstream and read a string from there.... Lots of choices.
And, please check your stream state! Try to use:
if (std::cin >> x)
// x was parsed from stream... use it
else
// print an error so you know where things failed!
FWIW, I guessed what the problem would be (it's stupidly common) before seeing the update, and chuckled to myself at the other guesses (although they make very good points even if they missed the OP's problem).
The line of code is working correctly and as advertised. It doesn't happen to be working the way you want it to.
When you read from std::cin, that does not pause the program and wait for input. What causes the pause is the lack of sufficient input data for the read operation.
Input is fed to your program a line at a time. Remember, the console window is a program, too. It is responsible for translating the user's key-presses into text characters (bytes, really), handling things like the backspace key, and gathering it all up into lines.
So say you read an int with operator>>, and then read a line with getline. The program will not see an int until the user hits the Return key, because that triggers the console to feed a line of input to your program.
operator>> will skip leading whitespace, read the integer, and leave trailing whitespace alone. Newline characters are whitespace. There is a newline character in the input (at the end of the line, obviously).
getline() will not skip any leading whitespace, and read until the next newline. The very next character happens to be a newline, so getline() happily reads an empty line and the program proceeds with that.
So how do you fix that? Chances are, if you're reading all your input from cin, that you want the program to pause every time you come to a reading operation. The way to do that is to ensure that there is never any available data at that point, and the way to do that is to read everything that's available - i.e., the whole line - every time that you read something.
So, always read a full line from cin. As noted by wilx, please use the free function std::getline for this. Do not use the .getline member function of the stream. Use std::string to represent strings of text. That's what it's there for. It will make your life much, much easier. That also means that if you're expecting an integer and the user types "76 trombones", you get rid of the "trombones" data (and can decide whether you want to just throw it away, or yell at the user and make him re-enter a number without any funny commentary).
But then what? You just have a string, where you may have wanted an int. Fortunately, there is a simple solution for that. We can treat the string as a source of stream data, using the standard library class std::stringstream. We just construct a stringstream from the string, and then use it just like std::cin - i.e. we can read from it with operator>>, check the stream state to see if reading was successful, etc.
As noted by sbi, always check whether reading succeeded! If you try to read an int and the stream contains text like "hi mom", then (a) the int variable will not be altered (so if it was uninitialized it is still uninitialized, a very dangerous state to be in), and (b) the stream will go into a "failed" state and will not read any more until you clear it, and (c) even if you clear it, the data will still be there, which can trigger an infinite loop if you're not careful.
Fortunately, with the separate stringstream, we avoid all kinds of complications. If reading fails, then all those things happen to the stringstream object - not to std::cin. The getline operation will always succeed on std::cin unless perhaps the user explicitly indicates an end-of-file (control-D character on Linux, or control-Z on Windows). We can easily check if the stringstream is in the failed state, loop and just create another one - the old one will automatically get cleaned up.
We can even make a helper function like:
template <typename T>
// Attempt to read into to_read, and return whether successful.
bool read_primitive_from_input(std::istream& input, T& to_read) {
std::string line;
std::getline(std::cin, line);
std::istringstream iss(line);
return iss >> to_read;
}
std::stringstream is provided by the standard library header <sstream>. std::string comes from <string>, of course.