I need help with input validator, whenever the console gets a wrong input, it does the job to determine whether the input is valid or not but here I have a problem where if I put a wrong input first, I have to re-enter the next input twice for it to go to Enter operator line.
#include <iostream>
#include <windows.h>
using namespace std;
main()
{
// Declaring variables
float num1;
char user_operator;
// Code Structure
cout << "Junie's C++ Calculator v.1" << endl << endl;
cout << "Enter first number >> ";
// Error checking + Input
while (! (cin >> num1))
{
system("CLS");
cout << "Junie's C++ Calculator v.1\n\n";
// Clear the input
cin.clear();
cin.ignore();
// Ask for the input again
cout << "(!) Enter first number >> ";
cin >> num1;
}
cout << "Enter operator >> ";
}
I have to re-enter the next input twice
That is because you are asking for input twice:
while (! (cin >> num1))
{
...
// Ask for the input again
cout << "(!) Enter first number >> ";
cin >> num1; // <--
}
If the user enters bad input, !(cin >> num1) is true, so the loop is entered, and then cin >> num1 gets executed twice, once at the end of the current loop iteration, and then again in the while condition of the next loop iteration. The next loop iteration will only evaluate the 2nd input.
So, you need to remove the cin >> num1 at the end of the loop:
while (! (cin >> num1))
{
...
// Ask for the input again
cout << "(!) Enter first number >> ";
// cin >> num1; // <-- remove this!
}
On a separate note:
cin.ignore(); ignores only 1 character, but more times than not you need to ignore more characters than that. It is customary to use this instead:
cin.ignore(numeric_limits<streamsize>::max(), '\n');
Which will ignore all characters up to the next Enter entered by the user. Using numeric_limits<streamsize>::max() as the number of characters to ignore is handled as a special-case:
https://en.cppreference.com/w/cpp/io/basic_istream/ignore
ignore behaves as an UnformattedInputFunction. After constructing and checking the sentry object, it extracts characters from the stream and discards them until any of the following conditions occurs:
count characters were extracted. This test is disabled in the special case when count equals std::numeric_limits<std::streamsize>::max()
end of file conditions occurs in the input sequence, in which case the function calls setstate(eofbit)
the next available character c in the input sequence is delim, as determined by Traits::eq_int_type(Traits::to_int_type(c), delim). The delimiter character is extracted and discarded. This test is disabled if delim is Traits::eof()
This is basically telling ignore() to not keep track of the count at all, just keep ignoring everything until another condition tells it to stop. If you specify any other value for the count, ignore() will have to keep track of how many characters it has ignored and then exit when that count has been reached. And there is no standard to how many characters constitute a line of input. Different console implementations have different limits on line input.
Related
I have an infinite while loop, where the user is asked for a number.
My problem is very simple: If the input is a string, I want to re-ask user for input, outputting the message "Enter a valid choice: ".
I searched, and looks like I should check for cin.fail(), then call cin.clear() and cin.ignore().
Here's my code:
int main() {
int choice;
bool failed = false;
while (true) {
if (failed) cout << "Enter a valid choice: ";
else cout << "Enter a number: ";
cin >> choice;
if (cin.fail()) {
cin.clear();
cin.ignore();
failed = true;
}
}
return 0;
}
However, this doesn't really fix my problem. Of course, it isn't printing infinitely, but for each letter extra letter , it prints another "Enter a valid choice:"
Seems like I need to call cin.ignore() for each extra letter.
Any other way of doing this?
You have an infinite loop because you are not breaking the loop even when valid input is enter. Is that what you really want? If so, at the least, you are not resetting the failed flag in valid input.
More importantly, when invalid input is entered, you are not ignoring everything that was enteted, you are only ignoring 1 char at a time. That is why you see extra prompts.
Try this instead :
int main() {
int choice;
while (true) {
cout << "Enter a number: ";
while (!(cin >> choice)) {
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "Enter a valid choice: ";
}
}
return 0;
}
The reason it is printing so many times is because you are only clearing the state of cin, but aren't clearing the input buffer. You can do so in multiple ways:-
Use fflush(stdin) to clear the input buffer.This is the C method and can be done by including cstdio header.
Use the cin.ignore to ignore all characters in the current input stream. You can do this by replacing the line cin.ignore() which ignores a single character by this code cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n') which ignores the entire line. For this you need the limits header.
Finally you can do the same with a simple loop like while (cin.get() != '\n'){continue;} which ignores all characters till new line.
Also another approach to the same problem is to take the input in form of a string and use the strtol() or the isdigit() functions to check if the input is valid.
By the way the infinite loop is because you have not used the break statement to terminate the loop. So you can avoid this by adding
if(!failed)
break;
Also you need to change the state of Failed at the entry of each loop by adding
failed=false;
at the start of the loop body.
I tried to run the following code but after one input, the rest of the input is initialized to zero and is displayed on the screen automatically. where did I go wrong?
#include<iostream>
#define N 50
using namespace std;
struct movies_t
{
char title[60];
int year;
}user[N];
void printmovie(movies_t);
int main()
{
for(int i = 0; i < N; i++)
{
cout << "Enter title: ";
cin.get(user[i].title, 60);
cout << "Enter year: ";
cin >> user[i].year;
}
cout << "\nYou have entered these movie: \n";
for(int i = 0; i < N; i++)
printmovie(user[i]);
return 0;
}
void printmovie(movies_t m)
{
cout << m.title;
cout << " (" << m.year << ")\n";
}
The problem is that when you press enter after inputting the year for the first movie, that enter (newline) is still in the input buffer, so when you next call cin.get(...) it will read that newline and think you entered an empty line.
You need to tell cin to ignore the rest of the line including the newline.
After execution of
cin >> user[i].year;
the newline character is still left in the input stream.
The next time you execute
cin.get(user[i].title, 60);
the first character encountered is the newline character. When that happens, failbit of cin is set. Here's some info from http://en.cppreference.com/w/cpp/io/basic_istream/get (emphasis mine):
4) Reads characters and stores them into the successive locations of the character array whose first element is pointed to by s. Characters are extracted and stored until any of the following occurs:
n-1 characters have been stored
end of file condition occurs in the input sequence (setstate(eofbit) is called)
the next available input character c equals delim, as determined by Traits::eq(c, delim). This character is not extracted (unlike basic_istream::getline())
If no characters were extracted, calls setstate(failbit). In any case, if count>0, a null character (CharT() is stored in the next successive location of the array.
After the failbit of cin is set, nothing is read from cin until the state is cleared by an explicit call to cin.clear().
Since you don't have any code to check the state of cin and clear the state when appropriate, nothing is read in the loop after the first iteration.
One way to fix the problem is add a line to ignore the contents of the stream after the year is read.
cin >> user[i].year;
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
Also, it is a good practice to always check the state of a stream after an IO operation to make sure that you don't overlook any errors.
for(int i = 0; i < N; i++)
{
cout << "Enter title: ";
cin.get(user[i].title, 60);
if ( !cin )
{
cout << "Error reading title.\n";
exit(1);
}
cout << "Enter year: ";
cin >> user[i].year;
if ( !cin )
{
cout << "Error reading name.\n";
exit(1);
}
// Ignore everything up to and including the newline character.
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
The code below should check every input once and display "Not a number" whenever the input is not a number.
int input;
while (1 == 1){
cout << "Enter a number: ";
try{
cin.exceptions(istream::failbit);
cin >> input;
}catch(ios::failure){
cout << "Not a number\n";
input = 0;
}
}
The problem is that when the catch is called (when it is not a number) it displays "Invalid number" endlessly like if the while() loop was executed several times but without asking for any new input.
while(true) or while(1) [or for(;;)] are customary ways to make a "forever loop".
You need to "clean up" the input that isn't acceptable within the cin stream.
The typical approach is to call cin.ignore(1000, '\n'); which will ignore all input until the next newline [up to 1000 characters - you can choose a bigger number, but usually a 1000 is "enough to get to a newline].
You will almost certainly also (thanks Potatoswatter) need to call cin.clear(); on the input, to remove the failed state, so that next input can succeed. [And cin.ignore() is further input, so it needs to go before that - just to be clear].
Though you failed to extract characters from the stream into an int, those characters remain in the stream so that you can attempt to extract them as something else, instead.
To skip them entirely, run std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); inside your catch block.
Then, whatever the user enters next will be the first thing in the stream. And perhaps that'll be a number, so your next attempt to extract into an int succeeds.
Well yeah. Your try-catch statement is inside the loop. So you try something, it fails and throws an exception, then you catch the exception, and you never exit or return from the loop so you do the same thing all over again.
But since your input wasn't processed the first time (throwing an exception instead), it's not going to be processed the second time, or the third time, or any time.
To advance, handle the exception by ignoring the input until the next space:
int input;
while (1 == 1){
cout << "Enter a number: ";
try{
cin.exceptions(istream::failbit);
cin >> input;
}catch(ios::failure){
cout << "Not a number\n";
input = 0;
//the line below ignores all characters in cin until the space (' ')
//(up to 256 characters are ignored, make this number as large as necessary
cin.ignore(256, ' ');
}
}
By the way, as a general rule: exceptions should be for something that is truly exceptional, particularly since there is overhead for handling the exception. There is debate about whether invalid user input is exceptional.
As an alternative, you can make a much more compact, equally correct loop without exceptions like the following:
int input;
while (true){ //outer while loop that repeats forever. Same as "while(1 == 1)"
cout << "Enter a number: ";
//The following loop just keeps repeating until a valid value is entered.
//The condition (cin >> input) is false if e.g. the value is a character,
//or it is too long to fit inside an int.
while(!(cin >> input)) {
cout << "Not a number" << endl;
input = 0;
}
}
I am a beginner programmer learning c++. I am having a nagging issue with the cin command.
In the program section below, if I enter a wrong type at the 1st cin command, the program will not execute any of the following cin commands at all, but will execute the rest of the program.
//start
#include <iostream>
using namespace std;
int main()
{
int x=0;
cout << endl << "Enter an integer" << endl;
//enter integer here. If wrong type is entered, goes to else
if (cin >> x){
cout << "The value is " << x << endl;
}
else {
cout << "You made a mistake" << endl; //executes
cin.ignore();
cin.clear();
}
cout << "Check 1" << endl; //executes
cin >> x; //skips
cout << "Check 2" << endl; //executes
cin >> x; //skips
return 0;
}
//end
Instead of the if else, if i put the same concept in a loop
while (!(cin >> x))
the program goes into an infinite loop upon enterring a wrong input.
Please help me explain this phenomenon, as the text book i am following says the code typed above should work as intended.
Thank you
cin is an input stream. If an error occurs cin goes into a let's call it "error occured" state. While in this state no character input can be made, your request to collect a character from the input stream will be ignored. With clear() you clear the error and the input stream stops ignoring you.
Here is the ignore function prototype
istream& ignore ( streamsize n = 1, int delim = EOF );
This function gets characters from the input stream and discards them, but you can't get any character if your stream is ignoring you, so you have to first clear() the stream then ignore() it.
Also, a note on the side: If someone inputs, for example "abc", on the first input request your cin gets only one character that is 'a' and "bc" stays in the buffer waiting to be picked up, but the next call to cin gets the 'b' and 'c' stays in the buffer, so you again end up with an error.
The problem with this example is that the cin.ignore() if no arguments are handed to it only ignores 1 character after you clear(). and the second cin gets 'c' so you still have a problem.
A general solution to this problem would be to call
cin.ignore(10000, '\n');
The first number just has to be some huge number that you don't expect someone would enter, I usually put in 10000.
This call makes sure that you pick up all the characters from the false input or that you pick up every character before the enter was pressed so your input stream doesn't get into the "error occurred" state twice.
You may also want to try
if ( std::cin.fail() )
as a backup to prevent a crash due to input of the wrong type when prompted
I call a function from a function in C++ that has the line getline(cin,name) where name is a string. the first time through the loop, the program does not wait for input. It will on all other passes through the loop. Any ideas on why?
void getName (string& name)
{
int nameLen;
do{
cout << "Enter the last Name of the resident." << endl << endl
<< "There should not be any spaces and no more than 15"
<< " characters in the name." << endl;
getline(cin,name);
cout << endl;
nameLen = name.length();// set len to number of characters input
cout << "last" << name << endl;
}
while (nameLen < LastNameLength);
return;
}
Make sure there isn't left overs since the last time you read something from cin, like:
In an earlier point in your program:
int number;
cin >> number;
The input you give:
5
Later in the program:
getline(cin,name);
and getline will seem to not be called, but rather it collected the newline from the last time you took input because when you use cin >> it leaves new lines.
It may be because of the input stream. The getline function stops reading input after is receives the first newline char. If for example there are multiple newlines within the buffer of std::cin - the getline will return every time it encounters one.
Check the input you are expecting.
Do you have any:
cin << variableName;
lines of code? I ran into getline() skipping run-time errors when I was using:
cin << intvariable and subsequently getline(cin, variable).
This is because the cin stream object holds a buffer of input. When you enter the newline character I assume it is trunacated from the stream going to the variable asisgnment, yet is still contained within the cin object instance itself.
One workaround I used is cin.ignore(); after the cin << integer statement.
Another user mentioned parsing all input from getline into integers, floats - not root beer -, and strings. Good luck and check your code for the dual use of cin & getline().