Distinguishing between an int and a double - c++

I've searched for this answer, and no one seems to know how to fix this error. I want the input to be strictly an int. If the input is a double, I want it to send an error.
int creatLegs = 0;
string trash;
bool validLegs = true;
do
{
cout << "How many legs should the creature have? ";
cin >> creatLegs;
if(cin.fail())
{
cin.clear();
cin >> trash; //sets to string, so that cin.ignore() ignores the whole string.
cin.ignore(); //only ignores one character
validLegs = false;
}
if (creatLegs > 0)
{
validLegs = true;
}
if (!validLegs)
{
cout << "Invalid value, try again.\n";
}
} while (!validLegs);
It seems to almost work. It sends the error, but only after moving onto the next loop. How can I fix this? And why is it still showing the error message but still moving on before showing it?

An input can be something else than a representation of an integer or of a floating point number.
Remember that numbers are not their representation(s): 9 (decimal), 017 (octal, à la C), 0b1001 (binary, à la Ocaml), IX (Roman notation), 8+1 (arithmetic expression), neuf (French) are all representations of the same number nine.
So you have to decide if you accept an input like 9 x, or 9 (with several spaces after the digit), ... More generally you have to define what are the acceptable inputs (and if the input is ending at end of line or not, if spaces or punctuation should be accepted, etc...).
You could read an entire line (e.g. with std::getline) and use e.g. sscanf (where the %n control format is useful, and so is the item count returned by sscanf) or std::stol (where you use the end pointer) to parse it
Notice also that the phrasing of your question ("Distinguishing between an int and a double") is wrong. There is no single "int or double" type in C++ (but int is a scalar type, and double is a scalar type in C++, and you could define a class with a tagged union to hold either of them). AFAIU, if you declare int x; then use std::cin >> x; with the user inputting 12.64 the dot and the digits 64 after it won't be parsed and x would become 12.

I think that you should read data as string, and then check it char by char to verify that it is integer - if every char is a digit, then we have integer and we can parse it.
Problem with streams is, that if you're trying to read integer but decimal is passed, it reads the number up to the dot. And this part is a proper integer, so cin.fail() returns false.
Sample code:
#include <iostream>
#include <string>
#include <cctype>
#include <cstdlib>
using namespace std;
int main() {
int creatLegs = 0;
bool validLegs = true;
do
{
cout << "How many legs should the creature have? ";
string input;
getline(cin, input);
validLegs = true;
for (string::const_iterator i = input.begin(); validLegs && i != input.end(); ++i) {
if (!isdigit(*i)) {
validLegs = false;
}
}
if (!validLegs)
{
cout << "Invalid value, try again.\n";
} else {
creatLegs = atoi(input.c_str());
}
} while (!validLegs);
cout << creatLegs << endl;
}
This of course is not a perfect solution. If there any leading or trailing spaces (or any other characters like + or -), the program will fail. But you always can add some code to handle those situations, if you need to.

int creatLegs = 0;
do
{
cout << "How many legs should the creature have? ";
cin >> creatLegs; // trying to get integer
if(!cin.fail()) // if cin.fail == false, then we got an int and leave loop
break;
cout << "Invalid value, try again.\n"; // else show err msg and try once more
cin.clear();
} while (1);

This question already has an accepted answer, however I'll contribute a solution that handles all numbers that are integral, even those that are expressed as a floating point number (with no fractional part) and rejects input that contains anything other than spaces following the number.
Examples of accepted values, these all represent the number 4:
4
4.
4.0
+4
004.0
400e-2
Examples of rejected values:
3.999999
4.000001
40e-1x
4,
#include <iostream>
#include <sstream>
#include <cctype>
#include <string>
using namespace std;
bool get_int( const string & input, int & i ) {
stringstream ss(input);
double d;
bool isValid = ss >> d;
if (isValid) {
char c;
while( isValid && ss >> c ) isValid = isspace(c);
if (isValid) {
i = static_cast<int>(d);
isValid = (d == static_cast<double>(i));
}
}
return isValid;
}
int main( int argc, char *argv[] )
{
int creatLegs = 0;
bool validLegs = false;
do
{
string line;
do {
cout << "How many legs should the creature have? ";
} while (not getline (cin,line));
validLegs = get_int( line, creatLegs );
if (creatLegs <= 0)
{
validLegs = false;
}
if (not validLegs)
{
cout << "Invalid value, try again." << endl;
}
} while (not validLegs);
cout << "Got legs! (" << creatLegs << ")" << endl;
return 0;
}
If you want strictly integers (no decimal period and no scientific notation) then use this simpler get_int function:
bool get_int( const string & input, int & i ) {
stringstream ss(input);
bool isValid = ss >> i;
if (isValid) {
char c;
while(isValid && ss >> c) isValid = isspace(c);
}
return isValid;
}

Related

When I input a number in char type, why i can't get a whole number?

I input a number in char type variable. like 12 or 22. but, console show me a 1 or 2.
How i get a whole number 12 ,22 in console?
#include <iostream>
int main()
{
using namespace std;
char a = 0;
cin >> a;
cout << a << endl;
return 0;
}
Here is console result.
12
1
C:\Users\kdwyh\source\repos\MyFirstProject\Debug\MyFirstProject.exe(프로세스 18464개)이(가) 종료되었습니다(코드: 0개).
이 창을 닫으려면 아무 키나 누르세요...
The reason I don't use int, string and something is because I want to get both number and Character in one variable.
So I want to see the results of combined numbers and character at the same time.
in that process i can't get a whole number.
#include <iostream>
using namespace std;
int index = 0;
constexpr int pagenum = 10;
void chapterlist(void);
void nextlist(void);
void beforelist(void);
void movechapter(char a);
int main(void)
{
char userin = 0;
bool toggle = 0;
cout << "결과를 볼 챕터를 고르시오." << endl;
chapterlist();
cout << "다음 페이지로 이동: n" << endl;
cin >> userin;
if (userin == 'n')
{
backflash:
while(toggle == 0)
{
nextlist();
cin >> userin;
if (userin == 'b')
{
toggle = 1;
goto backflash;
}
else if (userin == 'n')
continue;
else
{
system("cls");
movechapter(userin);
break;
}
}
while(toggle == 1)
{
beforelist();
cin >> userin;
if (userin == 'n')
{
toggle = 0;
goto backflash;
}
else if (userin == 'b')
continue;
else
{
system("cls");
movechapter(userin);
break;
}
}
}
else
{
system("cls");
movechapter(userin);
}
return 0;
}
void chapterlist(void)
{
int x = 0;
for (x = index + 1; x <= index + 10; x++)
cout << "Chapter." << x << endl;
}
void nextlist(void)
{
system("cls");
cout << "결과를 볼 챕터를 고르시오." << endl;
index = index + pagenum;
chapterlist();
cout << "다음 페이지로 이동: n" << endl;
cout << "이전 페이지로 이동: b" << endl;
}
void beforelist(void)
{
system("cls");
cout << "결과를 볼 챕터를 고르시오." << endl;
index = index - pagenum;
chapterlist();
cout << "다음 페이지로 이동: n" << endl;
cout << "이전 페이지로 이동: b" << endl;
}
void movechapter(char a)
{
cout << "선택한 Chapter." << a << "의 결과입니다." << endl;
}
In movechapter(), console show me a is 1 or 2, not 12, 22.
First, you have to understand what achar type is.
Character types: They can represent a single character, such as 'A' or '$'. The most basic type is char, which is a one-byte character. Other types are also provided for wider characters.
To simplify that, char can only hold one character.
Where as with your code, "12" is actually 2 separate characters, '1' and '2', and that's the reason it would not work.
Instead of declaring a as a char type, you could declare it as an int type, which is a type designed to hold numbers. So you would have:
int a = 0;
However, do note that int often has a maximum value of 2^31.
Or you could use std::string to store character strings. However, do note that if you wish to do any calculations to your string type, you would need to convert them to a number type first:
int myInt = std::stoi(myString);
Edit:
So I have re-checked your code after your update, there is nothing wrong with using std::string in your case. You can still check if user have input n or b by:
if (userin == "n")
Note that you would use double quotation mark, or "letter", around the content that you want to check.
On the other hand, you could use:
if(std::all_of(userin .begin(), userin.end(), ::isdigit))
To check if user have input a number.
Although char is just a number, it's presumed to mean "single character" here for input. Fix this by asking for something else:
int a = 0;
You can always cast that to char as necessary, testing, of course, for overflow.
You should be reading characters into a string, and then converting that string into an int. It would also probably make more sense to use something like getline() to read input, rather than cin >> a.
#include <string>
#include <iostream>
#include <stdexcept>
#include <stdio.h>
int main() {
std::string input_string;
/* note that there is no function that will convert an int string
to a char, only to an int. You can cast this to a char if needed,
or bounds check like I do */
int value;
while(1) {
getline(std::cin, input_string);
/* std::stoi throws std::invalid_argument when given a string
that doesn't start with a number */
try {
value = std::stoi(input_string);
} catch (std::invalid_argument) {
printf("Invalid number!\n");
continue;
}
/* You wanted a char, the max value of a `char` is 255. If
you are happy for any value, this check can be removed */
if (value > 255) {
printf("Too big, input a number between 0-255\n");
continue;
}
break;
}
printf("Number is %hhu\n", value);
}

How to check if the input taken by the user doesn't contain decimal?

I am a newbie to C++. I have a situation where the input integer is taken from the user. However, I need to check if the user enters a decimal value. How do I check this?
I have tried cin.good(), cin.fail() but they are detecting only non-digit entries and not decimal numbers. Any help would be appreciated.
#include <iostream>
int main()
{
using namespace std;
int x;
cout << "Enter an integer: " << endl;
cin >> x;
if (cin.good()) {
cout << "input is an integer" << endl;
}
else
cout << "input is not an integer" << endl;
}
Here's my output:
1.
Enter an integer:
1.2
input is an integer
2.
Enter an integer:
a
input is not an integer
float x = 4.2;
if (x == (int) x)
{
// int
}
else
{
// not int
}
You can use std::isdigit for checking your string input next way.
bool is_numeric(const std::string& str)
{
std::string::const_iterator it = str.begin();
if (it != str.end() && *it == '-') ++it;
if (it == str.end()) return false;
while (it != str.end() && std::isdigit(*it)) ++it;
return it == str.end();
}
It's not hard to change it to work with floating points, if needs, but that function will exactly checks what you need.
You receive the input as an int from cin and hence any float entered would already be truncated by the time you get your hands on it. You should receive it as a float or a string to decide on the validity of the input.
Removed the earlier answer since it went down the slippery route of manually parsing the input which is unnecessary and error-prone. The standard library already has multiple ways to check if an input is a valid number. Two ways that I know: C++ streams and the C library function strtof. Here's an example using the latter:
#include <iostream>
#include <string>
#include <cmath>
bool is_int(float f) {
return std::floor(f) == f;
}
int main()
{
std::cout << "Enter an integer: ";
std::string input;
std::cin >> input;
char *e = nullptr;
char const *str = input.c_str();
float const f = strtof(str, &e);
// no conversion was performed or was stopped as disallowed
// characters were encountered: Not A Number
if ((e == str) || (*e != '\0'))
std::cout << "NAN";
else if ((f == HUGE_VALF) || !std::isfinite(f))
std::cout << "too large";
else
std::cout << (is_int(f) ? "integer" : "non-integer");
std::cout << '\n';
}
Live example.
To check if the input is a number, this
float f;
cin >> f;
is possible too, but it will also accept NANs as valid input e.g. 45dsf will be converted to 45. One has to then check if the conversion happened completely and successfully by checking the fail and eof bits of the stream.
See also
Checking if float is an integer
C++ IsFloat function
How to convert a number to string and vice versa in C++

C++ Excluding non-integer user inputs

I am making a number-guessing game where the user is asked to input a four-digit number. It is possible, however, that the user inputs less or more than four digits and/or a non-integer input (i.e. invalid input). My code stores the user input into an integer-type array. I just realized now that my code will still recognize "invalid inputs" as valid since the array where the input is being stored is declared as an integer-type. Below is a portion of my code:
#include <iostream>
using namespace std;
void guess(int num_guess[], int size);
int main(){
int list[4];
guess(list, 4);
for(int i = 0; i < 4; i++){
cout << list[i];
}
cout << endl;
}
void guess(int num_guess[], int size){
int number;
cin >> number;
for(int i = size-1; i >= 0; i--){
num_guess[i] = number%10;
number /= 10;
}
}
cout << list[i]; isn't really part of the original code, but this was how I found out that invalid inputs are still accepted. I encountered a similar problem before when I was making a rational roots calculator program in Python, but it was much easier then to detect and exclude unwanted inputs. My question is, how do I fix my code so that it can detect invalid inputs and output something like "Invalid input" and then proceed to ask the user for another input.
The following is a function to check if a string is a 4 digit positive integer. If the number could be negative, you just need to check if the s[0] == '-'.
bool check(string &s){
if(s.size() != 4) return false;
for(int i=0; i < 4; i++){
if(s[i] < '0' || s[i] > '9') return false;
}
return true;
}
The following is a function to convert a string to an int:
#include <stringstream>
int strToInt(string &s){
stringstream ss(s);
int ans;
ss >> ans;
return ans;
}
To exclude non integer inputs try the following:
void skip_to_int(){
// if is not an integer
if(cin.fail()){
// check character type
cin.clear();
char ch;
while(cin>>ch){
// throw away non digits
if(isdigit(ch)){
// put back if digit to be written
cin.unget();
return;}
}
}
else error ("no input");
}
And your input prompt function will look like this:
cout << "Please enter an integer" << endl;
int n=0;
if(cin>>n){
// integer OK, proceed
}
else{
cout << "That was not a numeric value, try again." << endl;
skip_to_int();}
Here's my solution. Beware, it uses C++11. Certainly not necessary if you use std::stringstream, but this should work pretty well.
I presume you don't want negative numbers. I also presume that any number of 0's in front doesn't make the number a 4-digit number. It will cut off padded 0's, so 01234 is a 4 digit number, but 0123 isn't.
void guess(int num_guess[], int size)
{
int number;
// if the length of the number isn't 4, try again until it is
do {
std::cin >> number;
if(std::to_string(number).length() != size)
std::cout << "You messed up the input. How hard could it be? Try again..." << std::endl;
} while(std::to_string(number).length() != size);
// by now, the size is definitely 4. insert it by digit into num_guess
for(int i = size-1; i >= 0; i++) {
num_guess[i] = number%10;
number /= 10;
}
}
#include <iostream>
#include <limits>
int main() {
int i = 0;
std::cout << "Please enter a number with four digits: ";
while( !(std::cin >> i) || !(i / 1000.0f >= 1.0f) )
{
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "Invalid entry." << std::endl;
std::cout << "Please enter a number with four digits: ";
}
}
the std::cin.clear() clears all errors flags on current stream structure and std::cin.ignore() cleans up the input stream itself. Once we don't know the size of stream 'til this operation I have used the maximum possible value of a stream size to make sure any stream length could be cleaned.
add #include "math.h"
and change guess
void guess(int num_guess[], int size){
int number = 0;
bool firstTime = true;
do
{
if (!firstTime)
cout << " Error, try again " << endl;
firstTime = false;
cin >> number;
} while (number<pow(10, size-1) || number>=pow(10, size));
for(int i = size-1; i >= 0; i--){
num_guess[i] = number%10;
number /= 10;
}
}

C++ cin only accept numeric values

I've written this piece of code that allows the user to choose input either the value 1 or 2. This is working perfectly fine aside from one minor issue:
If the user inputs something like "1asdaosd" the input is recognized only as 1.
I've tried using the isdigit function but I still didn't manage to make this work.
bool validInput;
do
{
cout << "Choose the game type: ";
cin >> gametype;
validInput = true;
if (cin.fail())
{
validInput = false;
cin.clear();
cin.ignore(std::numeric_limits<int>::max(), '\n');
}
if (gametype<1 || gametype>2) {
validInput = false;
}
} while (!validInput);
The expected behaviour should be:
Anything other than "1" or "2" shouldn't be considered a validInput and therefore repeating the cycle. What happens is that "1asdasd" or "2aods" is considered a validInput but I want it to fail.
Below is a method based on stuff I read in one of the early chapters of Stroustrup's Programming: Principles and Practice Using C++ and an answer provided by Duoas at cplusplus.com. It defines a function, get_int_between(), that allows you to do something like this:
int my_variable;
get_int_between(my_variable, min, max, prompt, error_msg);
Which would prompt, validate, and store into my_variable.
Just for fun, I've also included a function, get_int(my_variable, prompt, error_msg), that does the same thing but allows an integer of any value.
#include <iostream>
#include <sstream> // stringstream
void get_int(int& d, std::string prompt, std::string fail);
void get_int_between(int& d, int min, int max, std::string prompt, std::string fail);
int main()
{
int my_number = 1; // initialize my_number
get_int(my_number, "Please enter an integer: ", "Sorry, that's not an integer.\n");
//Do something, e.g.
std::cout << "You entered: " << my_number << "\n";
get_int_between(my_number, 1, 2, "Choose the game type (1 or 2): ", "Sorry, that's not an integer.\n");
//Do something, e.g.:
std::cout << "Let's play Game " << my_number << "!\n";
return 0;
}
void get_int(int& d, std::string prompt, std::string fail)
{
while(1) {
std::cout << prompt;
std::string str;
std::cin >> str;
std::istringstream ss(str);
int val1;
ss >> val1;
if(!ss.eof()) {
std::cout << fail;
continue;
} else {
d = val1;
break;
}
}
}
void get_int_between(int& d, int min, int max, std::string prompt, std::string fail)
{
while(1) {
get_int(d, prompt, fail);
if(d > max || d < min) {
std::cout << "Sorry, your choice is out of range.\n";
continue;
}
break;
}
}
If you want to use strings use getline.
#include <iostream> // std::cin, std::cout
int main ()
{
char name[256], title[256];
std::cout << "Please, enter your name: ";
std::cin.getline (name,256);
std::cout << "Please, enter your favourite movie: ";
std::cin.getline (title,256);
std::cout << name << "'s favourite movie is " << title;
return 0;
}
if you make gametype as an int it will only accept 1 or 2 (of course you have to prevent other numbers to be accepted).
It's because gametype is an integer, so it's trying to read as much as would be valid for an integer. 1asdaosd is not a valid integer so it stops at the 1. If you want to read that thing in completely you'll have to make gametype a string for example, but then you won't be able to compare it to integers as you already do.
You can read it as a string if you want, and if you want to handle the case of strings and ints both, then you can use something like stoi to attempt to convert the string to an integer. Then catch the std::invalid_argument exception so you can know if the string can be converted to an integer. If it can't, then you know to keep it as a string.
It reads an int as far the input can be construed as such. Then stops. If you read into a string variable it will get it all.
Read data into a string variable.
Check that data is a valid integer.
Convert string to integer.
Tedious but it's the only way to do it
I'm guessing you want one input value on each line. You need to read this as string and then check if you got more than you asked for. If you need it as an integer you can convert the read string later.
I'm also assuming you only need to read single digit integers. More digits need the string to integer conversion in the loop and some more checks.
string gametype;
do
{
cout << "Choose the game type: ";
// read one word as string, no conversion, so will not fail (may hit eof though)
cin >> gametype;
// ignore rest of line (assuming you want next valid input on next line)
cin.ignore(std::numeric_limits<int>::max(), '\n');
}
while ( gametype.size() != 1 || gametype.at(0) < '1' || gametype.at(0) > '2') );
// char to int conversion (single digit only)
int gametypeint = gametype.at(0) - '0';
// other way to convert string to int
istringstream iss(gametype);
iss >> gametypeint;
// yet another way (C++11)
gametypeint = stio(gametype);

Receiving integers, but also want to test for char

Say I am looking to receive a series of numeric values and read them into an int, but I also want to test if the user hit key 'x'.
I am sure I am missing something obvious, and have tried a few things but seem to be stuck.
This is what I have so far...
cout << endl << "Enter key (or 'x' to exit): ";
cin >> key;
if (key == 'x') { cout << "exiting";}
// continue on...
You need to read into a string and then convert that to an integer. In outline:
#include <string>
#include <sstream>
#include <iostream>
using namespace std;
int main() {
string s;
cout << endl << "Enter key (or 'x' to exit): ";
getline( cin, s );
if ( s == "x" ) {
// do exit stuff
}
else {
istringstream is( s );
int n;
if ( ! is >> n ) {
// report not an integer
}
else {
// do something with n
}
}
}
It depends on how key is declared.
If key is an int, you can only test for numbers, of course.
How about the following outline of an algorithm:
int n = 0
bool xentered = false
while (not xentered and there is one more character before EOF)
if that character is 'x' then xentered = true
else if it is a digit
n = 10*n + numeric value of the digit
else
error
I leave the task to translate that to the programming language of your choice. :)