Can someone explain to me how this code works?(Program to ask for user input again if a numeric value expected and the user enters some other input) - c++

I was reading a book on c++ (c++ primer plus) and found this code.
The purpose of the program is that if a numeric input is expected from the user to read it to ,say an array->
1)Reset cin to new input
2)Get rid of the bad input
3)Prompt the user to try again (exact words of the book)
Here is the code->(exact code copied from the book)
#include <iostream>
const int Max=5;
int main()
{
using namespace std;
//get data
int golf[Max];
cout<<"please enter your golf scores.\n";
cout<<"you must enter "<<Max<<" rounds.\n";
int i;
for(i=0;i<Max;i++) {
cout<<"round #"<<i+1<<": ";
while(!(cin>>golf[i])) {
cin.clear();
while(cin.get()!='\n')
continue;
cout<<"PLease enter a number: ";
}
}
double total=0.0;
for(i=0;i<Max;i++)
total+=golf[i];
cout<<total/Max<<" = average score "<<Max<<" rounds\n";
return 0;
}
The particular part which i don't understand is:
cin.clear();
while(cin.get()!='\n')
continue;
I'm a little unclear about the function of cin.clear() , the need of continue here , and what the while test conidtion does and how does it work.
A test run->
(italic part is the user input)
Please enter your golf scores.
You must enter 5 rounds.
round #1: 88
round #2: 87
round #3: duh
Please enter a number: 103
round #4: 94
round #5: 86
91.6 = average score 5 rounds

while(!(cin>>golf[i]))
{
cin.clear();
while(cin.get()!='\n')
continue;
cout<<"PLease enter a number: ";
}
First let's example the while condition. It seems to check if the value of the expression (cin >> golf[i]) is false. The falue of cin >> golf[i] is cin itself. So how can it be false? If a >> operation fails for the input stream, a flag named fail is set. That's what operator ! checks. So the condition means while after trying to read a number the object cin has fail set, do...
Now, once the fail flag is set, there isn't much you can do with an input stream. You won't be able to continue reading data from the stream unless you reset the fail flag. That's what cin.clear() does.
Then it munches the rest of the bad input line (which was NOT consumed since >> failed) by reading character by character until reaching the end of line.
And finally it prompts the user for new input.

Since golf[i] is an int, cin>>golf[i] will return true (or a value interpreted as true in earlier versions of C++ Standard Library) when the input is an int. Hence, while(!(cin>>golf[i])) will repeat until true is returned.
Inside the while loop you find code that ignores all input until a \n with the loop that stops only after receiving '\n' input:
while(cin.get()!='\n')
continue;
It also clears the flag indicating that cin is in a failure state by calling clear().
Note: This code makes an assumption that cin never ends, which makes it unsafe. If the input is taken from a file with invalid data, this program will be stuck in an infinite loop.

Related

Making sure multiple inputs are numbers (c++)

I was making a program where I asked user for a date and compared it with the current date. All the functionality was there but I couldn't seem to validate the day, month and year were numbers so entering letters crashed the program. Any ideas? (Note: the functions in the do while loop work as intended)
do // This do while loop forces the user to enter a valid date before moving on
{
cout << "Enter the lent date in the format dd/mm/yyyy: " << endl;
cin >> day1 >> buffer >> month1 >> buffer >> year1;
if(cin.fail())
{
continue;
}
}
while (!validateDateSize(day1, month1, year1) || !validateDateIntegrity(day1, month1, year1));
It depends on the definition of your variables. Let's assume:
int day1, month1, year1;
char buffer;
Entering a valid date such as "12/3/2017", "12-3-2017" or even "12.3.2017" would pass the test. Entering invalid dates but with a valid format such as "125.3.2017" would fail the test, and loop to offer the next chance for a correct entry.
So what's the problem ?
But if something goes wrong in the format, for example with "12/A/2017", cin would fail at the first unexpected char (here 'A'). Your code would then continue the loop. Unfortunately, the fail status of cin will remain unchanged, causing any subsequent input to fail and your code to loop forever.
How to correct it ?
You need to clear() the error status, and also ignore() the wrong characters that caused the failure and are still in the input :
if(cin.fail())
{
cin.clear(); //reset error flags
cin.ignore(numeric_limits<streamsize>::max(),'\n'); // and ignore characters until the next newline
continue;
}
Online demo
Before doing any validation, check whether the input received from user is a digit or not.
isdigit(char c)
Checks whether c is a decimal digit character.
Return Value :
A value different from zero (i.e., true) if indeed c is a decimal digit. Zero (i.e., false) otherwise.

How while(!(cin >> x)) works to re-prompt for input

while(!(cin >> ar[i]))
{
cin.clear(); // clears bad input
while(cin.get() != '\n')
continue;
cout << "Invalid input, please enter valid scores";
}
The above code is from a much larger file. I copied this bit of a code from one of my textbooks and I don't really feel comfortable using it as I do not understand how this works.
I am using it as a measure to handle input errors.
So ar is an empty array of integers, if I decide to enter 'k', then
!(cin >> ar[i])
is true.
From here I clear the input buffer (I think that is correct, I'd like someone to confirm or dispute this please). The terminal then prints "Invalid input..."
Now if I just press Enter nothing happens, but isn't Enter the newline char? So shouldn't the code read
while(cin.get() == '\n'
?
while(!(cin >> ar[i]))
This tries to parse a value from cin and store it in ar[i]. By default, >> skips whitespace first, then sees if the characters in cin describe a legal value for whatever the type of ar[i] is. If a legal value is found, then cin stream state remains good, and its operator bool() const will kick in given the boolean not/! operation, such that the while loop will break.
If parsing fails though, the stream state will be set to one or more of:
bad (if there's some unrecoverable stream error, like stdin supplied over a network connection that gets disconnected),
fail (if the characters just didn't form a legal value for the type), or
eof (end of file, for a "proper" shutdown/close of the input, as supplied by ^D in UNIX/Linux, ^Z in Windows, and the end of input when a program's invoked as in echo input | program).
All the above modalities are described under "State Functions" here.
If the loop is entered due to any of the error conditions above...
{
cin.clear(); // clears bad input
...this does NOT clear any input data from the stream, but does clear the bad, eof and fail state flags, after which further input attempts can be made, though a stream that was in bad or eof state is likely to immediately reenter that state when further input is attempted (but not always - some OS may allow successful input after an eof conditions for std::cin if the user types/generates an EOF code then types actual text again...
while(cin.get() != '\n')
continue;
This tries to read characters from the terminal until a newline \n is encountered. The idea's clearly to clear out the rest of the presumed unparse-able input that might have led to a fail condition earlier. Sadly, if the problem was, or becomes, a bad or eof condition then this loop will hang the program, spinning burning CPU to no avail.
cout << "Invalid input, please enter valid scores";
}
If the problem was simply a mistyped value and no bad or eof condition, then the cout will prompt for further input.
Now if I just press enter nothing happens, but isnt enter the newline char?
Whenever the outer loop is executing cin >> ar[i] it will skip whitespace, including any extra newlines you type, until it sees some input (which may need to be a full newline-terminated line to get flushed by the terminal or program feeding it to the program), or a bad or eof condition. The inner while-loop is not there to get rid of empty lines - it's trying to discard the line with presumed non-numeric text in it.
Corrected code:
while (!(std::cin >> ar[i]))
{
if (std::cin.bad() || std::cin.eof())
{
std::cerr << "Fatal error on cin while reading numbers\n";
exit(EXIT_FAILURE);
}
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "Invalid input, please enter valid scores\n: ";
}
The goal of this entire code is to keep printing errors and requesting input until the user enters a valid number before continue further into the program.
The loop that the entire code is enclosed in...
while(!(cin >> ar[i]))
says to loop if the input in the cin stream is invalid. Since ar is an array of integers, the input would be invalid if it is not a number.
cin.clear(); // clears bad input
When the cin stream encounters invalid input, the program begins executing the loop and continues to this line of code. Since the stream encountered invalid input, it has a flag that says there is an error. This requires that you, as the comment puts it, "clear bad input." Basically what this does is get rid of this flag. If this is not done, the flag will remain in the stream and the program will encounter another error next time the cin stream is used, regardless of whether or not the user input is valid.
while(cin.get() != '\n')
continue;
When the program took the input from the user, it took the string, char, whatever was the invalid input, but left the '\n' in the cin stream. To prevent errors the next time the cin stream is used, the program must get rid of that '\n', along with anything else that was lefty behind. cin.get() reads only one char from the cin input stream and returns it. Since the return value of this function is not being assigned to anything, all this does is discard the char that was read. In the case that more than the '\n' was left behind in the stream, this loop checks the value of the read char before disposing of it. This way, the loop keeps executing while the char that is read is NOT '\n'. Or in other words, it loops until the char that is read IS '\n'. The only thing that continue does, is tell the program to skip the rest of the current iteration of the loop and start the next iteration. In this situation, this is equivalent to giving the loop an empty body. You could very well replace continue; with {} and the program would do the exact same thing.
cout << "Invalid input, please enter valid scores";
The program has cleared the flag in cin and has also cleared any data from cin that may have been left behind. Now that all the errors from the invalid input have been handled, there is only one more thing to do. It's time to notify he user that the input was invalid and request new input. If the user enters more invalid input, the loop repeats. If the user enters valid input, the program continues on to the next line of code.

stop inupt if input no double

first of all I'm sorry for my
bad english.
I'm trying to read some numbers and write them into a vector in C++.
This should go as long as the input is a double number and the
loop should be stopped if the user writes an 'a'.
My Question is how can I check if the input is 'a'.
Breaking the loop is not the problem
while(true){
if(!(cin>>userInput)){
//here i want to know if the input is 'a' or some other stuff//
//also i want to do some other stuff like printing everything//
//what already is in the vector//
//when everything is done; break//
}
else
//the input is a valid number and i push it into my vector//
'userInput' is defined as double so the loop will stop.
My Problem is, if the user write 'q' the loop stops but it's instantly stoping the whole program. My try look like this:
while(true){ //read as long as you can
cout<<"Input a number. With 'q' you can stop: "<<endl;
if(!(cin>>userInput)){ //here the progam stops when the input is anything but a number
cout<<"How many numbers do you want to add up?"<<endl; //there are numbers in a vector that should be added up
cin>>numberOfAdditions;
break;
}
So I have a vector with some numbers the users writes down (20,50,90,...)
When the input is equal to 'q' (in this example everything but numbers )
the loop stops and I want to ask the user how many numbers should be added.
The cout-command is displayed but the input is beeing skipped.
So my program is not reading how many valued from the vector I want to add.
I hope you know what I mean and I don't want to use two questions and two variables to save the input but if it's not working without it I'll change my program.
Have a nice Day :)
Because your Input variable is of type double you have to flush the Input from cin before reading again. Otherwise there is still a newline in the buffer.
Consider the following example:
#include <iostream>
using namespace std;
int main(){
double userInput;
int numberOfAdditions;
while(true){ //read as long as you can
cout<<"Input a number. With 'q' you can stop: "<<endl;
if(!(cin>>userInput)){ //here the progam stops when the input is anything but a number
cout<<"How many numbers do you want to add up?"<<endl; //there are numbers in a vector that should be added up
cin.ignore (std::numeric_limits<std::streamsize>::max(), '\n');
cin.clear();
cin.ignore(INT_MAX,'\n');
cin >> numberOfAdditions;
break;
}
}
return 0;
}
The two Statements:
cin.clear();
cin.ignore(INT_MAX,'\n');
are flushing the Input stream until the newline is encountered.
The first answer already explains how to flush the cin stream after the user types in a char.
If you want to determine which character it was, you should define userInput as std::string. If the string is not "q" or "a" or whatever you are looking for, you have to cast the string to a double, just like this:
std::string str;
cin >> str;
if (str == "j")
// User typed in a special character
// ...some code...
else
double d = atof(str.c_str()); // Cast user input to double
Notice that the result of the cast is zero, if the user typed in any other string than the ones you especially look for.

Code Snippet Works in Certain Cases but not as Expected, Why?

I have this code snippet that is supposed to test whether the user enters an integer or not. This works if the user enters letters, but not decimals and I'm left wondering why that is. Here's my code snippet:
Student student;
int id;
while(!(cin >> id))
{
cout << "\nERROR: Please enter a Positive Whole Number" << endl;
cin.clear();
cin.ignore ();
cout << "Enter Student ID: ";
}
Entering A will make it iterate through the while loop, but if I enter 12.5 it drops out of the while loop and keeps going. Isn't it testing whether it will parse to integer or not? Why is it accepting 12.5 but not characters?
cin>>id will succeed as long as it finds something it can convert to an int ("12", in this case). When it reaches something it can't convert, it stops, but if it's read an int already, that counts as success.
To check that everything it read was digits, you might want to do something like using std::getline to read a line of input into a string, then use std::isdigit to test whether those are all digits. Testing a conversion to int (by itself) will only tell you that it found something that could be read as an integer, but won't tell you if that was followed by other things that couldn't be converted to an int.

C++: how do I check if the cin buffer is empty?

How do you check to see if the user didn't input anything at a cin command and simply pressed enter?
When reading from std::cin, it's preferable not to use the stream extraction operator >> as this can have all sorts of nasty side effects. For example, if you have this code:
std::string name;
std::cin >> name;
And I enter John Doe, then the line to read from cin will just hold the value John, leaving Doe behind to be read by some future read operation. Similarly, if I were to write:
int myInteger;
std::cin >> myInteger;
And I then type in John Doe, then cin will enter an error state and will refuse to do any future read operations until you explicitly clear its error state and flush the characters that caused the error.
A better way to do user input is to use std::getline to read characters from the keyboard until the user hits enter. For example:
std::string name;
getline(std::cin, name); // getline doesn't need the std:: prefix here because C++ has ADL.
ADL stands for argument-dependent lookup. Now, if I enter John Doe, the value of name will be John Doe and there won't be any data left around in cin. Moreover, this also lets you test if the user just hit enter:
std::string name;
getline(std::cin, name);
if (name.empty()) {
/* ... nothing entered ... */
}
The drawback of using this approach is that if you want to read in a formatted data line, an int or a double you'll have to parse the representation out of the string. I personally think this is worth it because it gives you a more fine-grained control of what to do if the user enters something invalid and "guards" cin from ever entering a fail state.
I teach a C++ programming course, and have some lecture notes about the streams library that goes into a fair amount of detail about how to read formatted data from cin in a safe way (mostly at the end of the chapter). I'm not sure how useful you'll find this, but in case it's helpful I thought I'd post the link.
Hope this helps!
cin will not continue with the program unless the user enters at least 1 character (enter doesn't count). If the user doesn't give ANY input, cin will just keep waiting for the user to give input and then press enter.
The Simple way >>
{
char X=0; // ASCII( 0 ) means a NULL value
cin>>X;
if(X==0 || X==10) // ASCII( 10 ) means ENTER
cout<<"User din't enter ANYTHING !! ";
}
But a simple problem is....
cin just won't allow you to move further without entering a character
by character here i mean a DIGIT or alphabet or special symbol , not space, enter null etc
Hope this solves your problem, if it doesn't, I'll be glad to help just let me know.
int main(){
string str[100];
std::cout<<"Hello how are you ? \n";
std::cin>>str;
if(str.length() > 0){
// If input is seen
}
else{
// If input is not seen
}
}
Any problem let me know.