While loop skips line - c++

I currently have this function:
double GrabNumber() {
double x;
cin >> x;
while (cin.fail()) {
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "You can only type numbers!\nEnter the number: ";
cin >> x;
}
return x;
}
Its purpose is to check if x is a valid number, returning it if it is valid or repeating cin >> x if it is not.
It's called during this function:
void addition() {
cout << "\nEnter the first number: ";
double a = GrabNumber();
cout << "Enter the second number: ";
double b = GrabNumber();
// rest of code
When I type for example "6+" when it tells me to enter the first number, it accepts it but immediately goes to the second line and calls it an error where I haven't even entered my input.
I assume this is because the first input only accepts "6" while "+" goes to the second input returning an error. Therefore, there must be an issue with the parameters of while.

If your input is immediately successful, you don't ignore the rest of the line, which ends up into the next input. This can be fixed by simply duplicating the cin.ignore call.
double GrabNumber() {
double x;
cin >> x;
cin.ignore(numeric_limits<streamsize>::max(), '\n'); // <--
while (cin.fail()) {
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "You can only type numbers!\nEnter the number: ";
cin >> x;
}
return x;
}
I'll leave DRYing this code as an exercise ;)

To avoid this kind of issue, prefer using getline and stod:
double GrabNumber() {
double x;
bool ok = false;
do
{
std::string raw;
std::getline (std::cin, raw);
try
{
x = stod(raw);
ok = true;
}
catch(...)
{}
} while(!ok);
return x;
}
In general case, it's easier to acquire raw string with getline and to parse it just after. In this way, you can check everything you want: number of characters, sign position, if there are only numerical character, etc.

Related

Undefined behaviour when entering `char` for integer variable with `std::cin`

I have this while loop, just to check if the entered number is 2. If the user entered by accident a letter instead of a number the loop goes to infinity even though I've added isdigit, but didn't fix the loop from going crazy if the input is a character. This is code:
int num1;
bool cond {false};
while(!cond){
cout<<"enter 2:";
cin>>num1;
if (!isdigit(num1)){
cout<<"not a digit:";
cin>>num1;
}
//
if(num1 == 2)
cond = true;
}
I would suggest trying something a little more straightforward instead of your current code:
#include <iostream>
#include <limits>
using namespace std;
int main()
{
int num1;
cout << "Please enter the number 2:";
cin >> num1;
while (num1 != 2)
{
cin.clear(); //Clears the error flag on cin.
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "You did not enter the number 2, Please try again:";
cin >> num1;
}
return 0;
}
Now, cin.ignore(numeric_limits<streamsize>::max(), '\n'); is when it ignores up until '\n' or EOF \n is the delimiter meaning that, that is the character at which cin will stop ignoring.
Furthermore, numeric_limits<streamsize>::max() is basically saying there is no limit to the number of characters to ignore.
You need to use the header file #include<limits> to use this.
I recommend separating the reading of input data from converting it to a number. A good method for this is to use stringstream. Here's a working example:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main()
{
int num1;
string input;
bool cond{ false };
cout << "enter 2:";
while (!cond) {
getline(cin, input);
stringstream ss(input);
ss >> num1;
if( ss.fail() ){
cout << "not a digit:";
continue;
}
//
if (num1 == 2)
cond = true;
else
cout << "enter 2:";
}
return 0;
}
int num1;
bool cond {false};
do{
cout<<"enter 2:";
cin>>num1;
if (cin.good()) {
cond = true;
}else {
cin.clear();
cin.ignore();
cout << "Invalid, please enter 2." << endl;
}
}while(!cond);
While false, execute statements. Also, if you want the user to re-enter a number, cin must be flushed.
Try declaring the variable num1 as char because isdigit(ch) works for char and not for int.
I hope this solves your problem
Why does the loop iterate infinitely?
Let's take this example
int a;
std::cin >> a;
std::cout << "Entered: " << a;
Now let's test it with different inputs
with int
5
Entered: 5
10
Entered: 10
Yes just as we would expect, but what happens when you enter a char?
with char
r
Entered: 0
f
Entered: 0
Why does this happen?
When you declare the variable int, and then do std::cin >> , you are telling the input method that the user will enter an integer, but when it doesn't get what it expected, it will fail. C++ will not implicitly convert the value of char into int. Hence, you get strange results.
How to solve this?
As I have mentioned earlier, it fails. When this fails you can catch it this way
if (!(std::cin >> a))
{
std::cout << "Invalid input ! \n";
}
We're saying, if the input fails, show the message.
let's test this new code.
int a;
if (!(std::cin >> a))
{
std::cout << "Invalid input !\n";
}
else
{
std::cout << "Entered: " << a;
}
5
Entered: 5
r
Invalid input !
How to print char value of the int?
If you want to just print the ASCII value of the entered number, you need to cast the value into char.
You can do
int num = 48;
char character_value = num;
Here C++ will implicitly convert char into int.
But if you need a safer type of conversion, prefer using static_cast<>.
The syntax looks like this
int a = 5;
char character_value = static_cast<char>(a);
Static cast in C++
Type casting in C++
Dealing with invalid input in C++

How to initialize array with object in c++ by user input?

I have the code below, the credit and load successfully saves to the object but the code and title only takes the first letter of the string. I tried course[noOfCourses_].setCode(Code) at first, but it gives me an error:
cannot initialize a parameter type char with lvalue char[7].
Another problem is that the input skips the input prompt for the title and goes directly to credit prompt.
void addCourse() {
Course*course=new Course[MAX_NO_RECS];
char Code[MAX_COURSECODE_LEN];
char title[20];
int credit;
int load;
cout << "Course Code: ";
cin.clear();
cin >> Code;
cin.clear();
course[noOfCourses_].setCode(Code[0]);
cin.clear();
cout << "Course Title: ";
cin.getline(title, 20);
cin.clear();
course[noOfCourses_].setTitle(title[0]);
cin.clear();
cout << "Credits: ";
cin >> credit;
course[noOfCourses_].setCredits(credit);
cout << "Study Load: ";
cin >> load;
course[noOfCourses_].setLoad(load);
noOfCourses_++;
courseList_[noOfCourses_]=course;
}
Your first way was right. You should use course[noOfCourses_].setCode(Code) (by the way: it would be better if the variable Code would not start with a capital letter).
The problem is in your Cource::setCode function. It seems that the parameter is a char. To fix it, you should change it to a char*
void Cource::setCode(char* code) {
...
}

How to make the user enter a positive double variable?

I want the user to enter a positive double variable. If they enter anything else, I want the program to loop and continue to ask them to enter a number instead of getting an error and closing. I made an infinite loop with a conditional statement and a break. For some reason if they enter something other than a positive number it infinitely asks for the the radius. Can someone help me with this?
for(;;) {
cout << "Radius: ";
cin >> radius;
if(radius > 0){
break;
}
}
You can simply check the stream state of cin:
double radius;
for(;;) {
cout<<"Radius: ";
if(!(cin>>radius) || radius < 0.0) {
cout << "Invalid input, please enter a positive double value." << endl;
cin.clear();
std::string dummy;
cin >> dummy; // Read the left invalid input
}
else {
break;
}
}
You need to clear the stream's error flags, otherwise you keep looping, since no more other reads are performed when the stream is in a bad state, and radius keeps its value before the loop. You need to do the following (must #include <limits>):
if(!(cin >> radius)) // we didn't read a number, cin has a "bad" state
{
cin.clear(); // clear the error flags
cin.ignore(numeric_limits<streamsize>::max(), '\n'); // ignore the rest
continue;
}

Read Integer from User

I am trying to read an integer from terminal. Here's my code:
int readNumber()
{
int x;
std::cin >> x;
while(std::cin.fail())
{
std::cin.clear();
std::cin.ignore();
std::cout << "Bad entry. Enter a NUMBER: ";
std::cin >> x;
}
return x;
}
Whenever I run this code I get:
Type in the number for the newsgroup that shall be deleted:
joöä
Bad entry. Enter a NUMBER: Bad entry. Enter a NUMBER: Bad entry. Enter a NUMBER: Bad entry. Enter a NUMBER: Bad entry. Enter a NUMBER: Bad entry. Enter a NUMBER: 8
Why does it write "bad entry" multiple times?
If I remove std::cin.clear(); or std::cin.ignore();, the program just keeps writing
Enter a NUMBER: Bad entry. Can anyone explain why it does that?
This is actually a partial duplicate of an old question, but it is phrased differently enough that I will address it briefly here.
You get infinite printing without those two lines, because cin.clear() is required to clear the error flag that cin.fail() is reading. See the linked question for details.
Why does it still print more than once when those lines are there? When you do std::cin >> x;, your code will read the first character in your input, and attempt to parse it as an int. It will fail, and then in the next iteration of the loop, it will attempt to parse the next character and fail again. For each failure (that is, each character in your input), it will print Bad entry. Enter a NUMBER:. If you type some bad input with fewer characters, you will see what I mean.
There are multiple ways to fix this problem, but one simple fix is to read the entire input into a string, and try to parse it, instead of using cin directly into an int. Here is some sample code which needs to be compiled with one of the various compiler-dependent flags for C++11. I have tested it with your input and it appears to achieve the effect you desire.
#include <iostream>
#include <string>
#include <stdexcept>
bool tryParse(std::string& input, int& output) {
try{
output = std::stoi(input);
} catch (std::invalid_argument) {
return false;
}
return true;
}
int main(){
std::string input;
int x;
getline(std::cin, input);
while (!tryParse(input, x))
{
std::cout << "Bad entry. Enter a NUMBER: ";
getline(std::cin, input);
}
return x;
}
Try this anyway... As I type this directly into stackoverflow might have compilation error
int readNumber()
{
int x=0;
while(true)
{
std::cin >> x;
if(!std::cin.fail()){
break;
}
else{
std::cout << "Bad entry. Enter a NUMBER: " << std::endl;
std::cin.clear();
std::cin.ignore( std::numeric_limits<streamsize>::max(), '\n' );
}
}
}
int main() {
char* input;
std::cin >> input;
int x = std::atoi(input);
while(x == 0 && strcmp(input, "0") != 0) {
std::cout << "Bad entry. Enter a NUMBER: ";
std::cin >> input;
x = std::atoi(input);
}
return x;
}
Notice that when you have 3 non-int chars, it will repeat 3 times, when you have 5, it's repeated 5 times.
It's because cin is tries the first char, fails, try the second char, fails and so on until all your input chars are parsed.
cin.fail() returns true if the last cin command failed, and false otherwise.
Try this instead:
while(1)
{
std::cin >> x;
if (!std::cin.fail()) break;
std::cin.clear();
std::cin.ignore(10000,'\n');
std::cout << "Bad entry. Enter a NUMBER: ";
}

How do I make a C++ program that filter out non-integers?

Something like this
cout << "Enter the number of columns: " ;
cin >> input ;
while( input != int ){
cout << endl <<"Column size must be an integer"<< endl << endl;
cout << "Enter the number of columns: " ;
cin >> input ;
}
cin will do this for you, kind of. cin will fail if it receives something that is not of the same type as input. What you can do is this:
int input;
while(!(cin >> input))
{
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << endl <<"Column size must be an integer"<< endl << endl;
cout << "Enter the number of columns: " ;
}
The cin.clear() clears the error bits, and cin.ignore() clears the input stream. I'm using number_limits to get the maximum size of the stream, that requires that you #include<limits>. Alternatively you can just use a big number or a loop.
You can't do it like that; input has to have some concrete type.
The simplest approach that will work is to read a string from cin, then convert it to an integer in a second step with strtol or one of its relatives, and issue an error message if strtol doesn't consume the whole string.
#include<iostream.h>
using namespace std;
int main()
{
int x;
int input;
while(!0){
cout<<"Enter your option :";
cout<<"1 .Enter Column size :"<<endl;
cout<<"2.Exit "<<endl;
cin>>x;
switch(x)
{
case 1: cout << "Enter the number of columns: "<<endl ;
cin>>input;
if(input>0)
cout << "The number of columns: is "<<input<<endl ;
else
cout << "Enter the number of columns as integer "<<endl ;
case 2:exit(0);
}
};
return 0;
}
Many of the answers here use the cin's built in filter. While these work to prevent a char or string from being entered, they do not prevent a float entry. When a float is entered, it is accepted and the decimal value remains in the buffer. This creates problems with later requests to cin. The following code will check the cin error flag and also prevent float inputs.
*note: The cin.ignore statement may require some tweaking to fully bullet proof the code.
void main()
{
int myint;
cout<<"Enter an integer: ";
intInput(myint);
}
void intInput(int &x)
{
bool valid = true; //flag used to exit loop
do
{
cin>>x;
//This 'if' looks for either of the following conditions:
//cin.fail() returned 'true' because a char was entered.
//or
//cin.get()!='\n' indicating a float was entered.
if(cin.fail() || cin.get()!='\n')
{
cout<<"Error. The value you entered was not an integer."<<endl;
cout<<"Please enter an integer: ";
cin.clear(); //clears cin.fail flag
cin.ignore(256,'\n'); //clears cin buffer
valid = false; //sets flag to repeat loop
}
else valid = true; //sets flag to exit loop
}while(valid == false);
}
This is a very basic solution to your problem that newer programers should find useful for people trying to break their programs. Eventually there are more advanced and efficient ways to do this.
int input;
int count = 1;
while(count == 1){ //this is just a simple looping design
cin >> input;
if(cin.fail()){ //If the input is about to crash your precious program
cin.clear(); //Removes the error message from internal 'fail safe'
cin.ignore(std::numeric_limits<int>::max(), '\n'); //Removes the bad values creating the error in the first place
count = 1; //If there is an error then it refreshes the input function
}
else{
count--; //If there is no error, then your program can continue as normal
}
}
Here is the advanced code: stackoverflow.com/questions/2256527/