Just wondering what this line does/means to the computer - c++

int value(0);
while (!(std::cin >> value)) { //THIS LINE RIGHT HERE IS BUGGING ME(am really a noob)
cout << "you entered a non-digit character\n";
cin.clear();
cin.ignore();
}
this just stops people from entering letters instead of a number but i wanna know HOW it does it

Treating cin as a Boolean value tells you whether it's in a failure state. if ( cin ) is shorthand for if ( cin.ok() ). So the loop continues as long as the input stream is not OK, after taking some input.
Getting bad input is one way to get to a failure state. To get out of the state, call clear(), and to ignore the offending input, call ignore(). Then you can try again, as in this loop.

If what cin received's data type isn't compatible with value, then basically it returns as false.

cin >> value returns the cin object as a result. And it evaluates as false if the user-entered type doesn't match the specific overload (in your code, it's int), or cannot be implicitly converted to it.

cin is an object of class istream that represents the standard input stream. It corresponds to the cstdio stream stdin.
operator >> overload for streams returns a reference to the same stream and this can be evaluated in a boolean condition to true or false based on internal state of stream through a conversion operator. cin provides formatted stream extraction.
The operation
int value;
!(std::cin >> value)
will fail if numeric value is
entered and will return true if non-numeric value is entered.
cin.clear(); // will reset the state of stream
cin.ignore(); // ignore one or more characters

Related

Cin getting skipped after being used in for loop

Just wrote 3-4 lines to reproduce the problem. After using cin >> inside a "for loop" to repeatedly take input, all the next cin >> (s) always get skipped.
Anything/Everything other than cin works fine.(just want to know why this happens and what shall I do to be able to use cin further in the program)
for(int x;cin >> x;){
cout << x <<endl;
}
int a;
cin >>a;
No error message.
Whatever you're doing to make cin >> x fail (to break the loop) will just affect cin >> a too, as it's the same dang command!
The object cin doesn't "know" about your loop logic, and neither does your operating system/terminal, neither could it in general know that you intended for some sort of "reset" to happen once the loop was broken. You'd have to signal that yourself. However, it's likely you can't just patch that in because:
If you hit Ctrl+C to end the program, then the program has ended.
If you hit Ctrl+D (Linux/macOS) or Ctrl+Z (Windows), then you gave the stream the "end of file" condition and it won't accept any more. The std::cin object will have the EOF flag set on it, and this persists. (Sometimes you can clear this manually but I wouldn't recommend doing so, as you can get into confusion on the sending side, depending on your platform…)
You will have to find another way to break your loop, either with some "magic reserved number", by having a more sophisticated input protocol, by only reading some number n of initial inputs, or some other means that depends on what you're trying to do.
The second expression in the for header is the loop condition; the loop will continue running as long as this is true. Your condition is always true, so the loop is never exited.
You could add some code inside your loop to exit it, e.g. if (x == 0) break;
However, I would suggest redesigning the loop. Your loop condition is very unusual, and will give most people a bit of head-scratching before they figure out what's going on. Perhaps you can put the reading operation inside the loop body?
How >> works
For std::basic_istream (std::cin is one of these), the >> operator is overridden to implement formatted data extraction, and it's designed to be chainable (e.g. cin >> a >> b >> c). This works because:
>> is left-associative, so it groups as ((cin >> a) >> b) >> c)
>> returns a reference to the stream object, so you can keep adding more >> as much as you like.
Also, a std::basic_istream can be converted to bool, and will be true as long as no error has occurred. Thus, your loop condition is always cin, and since you're presumably not getting errors, is always true.

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.

Why does this do while loop repeat infinitely?

I want to prompt the user to input an integer, but if the user enters a non-integer, the program should keep demanding an integer until the user complies.
int getInteger(){
int input;
do{
std::cout << "Enter an integer: ";
std::cin >> input;
} while(!(std::cin));
return input;
}
If the user enters an integer, the function returns it.
But if the user enters something like "Hello," the function goes on an infinite, cout-ing "Enter an integer: ".
How do I fix this?
!(std::cin)
will evaluate to true if std::cin is in a bad state, e.g. after an input operation failed. Then, all subsequent input operations will fail immediately and not change cin's error state, thus the infinite loop.
To get the behavior you want, you may use something like
while (!(std::cin >> input)) {
std::cout << "Try again\n";
// Clear away the error state
std::cin.clear();
// Ignore what ever garbage is still in the stream
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
In the real world, you may want to handle the (generally not recoverable) failures eof (someone sent an End of File character) and bad (cin is broken, should not happen) different than fail which happens after invalid input. This is, for example, shown on this reference page for ignore. However, this should not bite you in toy programs like yours seems to be.
Streams convert to true while there is none of the failure bits is set. Once a stream entered the failure state, i.e., std::ios_base::failbit (or std::ios_base::badbit) is set for the stream, it stays in that state until the failure bit is cleared using clear(). In addition to clearing the stated you'd also need to get rid of the offending character(s) causing it to get into this state, e.g., using ignore().

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.

Why cin.fail() doesn't return false when entering a number followed by character?

I wrote this simple code:
#include <iostream>
using namespace std;
int main()
{
double s;
cin >> s;
if (cin.fail())
cout<<"Error";
return 0;
}
When I enter 12.03, cin.fail() returns false, and that's good.
And when I enter sd234, cin.fail() returns true, which is also good.
But if I enter 234.abcd, for example, or any number followed by a characters, cin.fail() returns true although I didn't enter a numerical to the double variable through the cin.
What am I missing?
std::istream::operator>>() reads characters as long as it fits to the current type (e.g. digits and . for double). Following characters are left in the input buffer for another extraction operator. If the characters read can satisfy the current type, no error is signaled.
Because it reads '234.', and that's a valid number.
The rest of the stuff that you've entered, 'abcd' is waiting for the next read.
The input asked for, i.e., a double coukd be satisfied, i.e., the read operation was successful. If you want to check that the stream continues with something you'd expect you need to read this. Alternatively you can check if the next character in the stream is of a certain kind.